Add NetTopologySuite when configuring Oracle Dbcontext with Ef Core 5 - oracle

I have a project with .Net 5.0 and Oracle is the databse provider. The version of the packages are:
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="5.0.10" />
<PackageReference Include="NetTopologySuite.IO.Oracle" Version="3.0.0" />
<PackageReference Include="Oracle.EntityFrameworkCore" Version="5.21.3" />
I want to configure the DbContext of Oracle, and the 'AddDbContext' to accept the use of topology, so using fluent API I could create a migration with a geometry column, like this:
builder.Property(p => p.WKTSRID)
.HasColumnType("SDO_GEOMETRY")
.HasConversion(w => WKTToSdoGeometry(w.WKT, w.SRID), r => SdoGeometryToWKT(r))
If not, the migration shows an error saying that the property 'WKTSRID' has a type that isn't supported by teh provider, and doesn't map to the type 'SDO_GEOMETRY' of Oracle
The DbContext needs to keep the compatibility with the 11 version, with the method .UseOracleSQLCompatibility("11")
Is there any way to achieve this (without using Devart)?
Edit:
I've also tested directly with a NetTopologySuite.IO.Sdo.SdoGeometry property. Having my entity class like this:
public class MyGeo { public SdoGeometry MySdoGeo { get; set; } }
And my EF configuration as either of this two:
builder.Property(p => p.MySdoGeo).HasColumnType("SDO_GEOMETRY")
builder.Property(p => p.MySdoGeo)
I obtain the same error:
The property 'MyGeo.MySdoGeo' is of type 'SdoGeometry' which is not
supported by the current database provider. Either change the property
CLR type, or ignore the property using the '[NotMapped]' attribute or
by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
I've also tried using the type 'NetTopologySuite.Geometries.Geometry' and setting the property type and the conversion on the EF configuration as follows, but doesn't work:
public class MyGeo { public Geometry MySdoGeo { get; set; } }
builder.Property(p => p.MySdoGeo)
.HasColumnType("SDO_GEOMETRY")
.HasConversion(a => Geo2SdoGeometry(a), d => SdoGeometry2Geo(d))
If there is any way to add the use of topology in the DbContext configuration? (As it seems to be not supported, Could you give any hint to add the missing support?)
Thanks in advance.

Related

DbSet declaration format

I originally developed a database(with UI) to add new records, retrieve list based on a query, and allow data alterations.
The two tables I used have now been incorporated into a SQL Server database, and I need to duplicate the same user experience in the new environment. I hope I am almost successful, but I still have errors in 2 files.
Within the ApplicationDbContext.cs file,
(1) I attempted to use the class name in declaring the DbSet statements. I get the following error in each instance:
"The type or namespace name '(className)' could not be found (are you missing a using directive or an assembly reference?)
(Should I be using something besides the class name in the DbSet statement?)
(2) I declare ApplicationDbContext as follows:
`public ApplicationDbContext() : base(ApplicationDbContext)
{}
The following error appears:
"'ApplicationDbContext' is a type, which is not valid in the given context"
In Startup.cs, ConfigureServices looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContextPool<ApplicationDbContext>(options =>
{
UseSqlServer(Configuration.GetConnectionString("AFForm1067DbConnection" ));
});
services.AddRazorPages();
//services.AddSingleton<IAFForm1067Repository,
MockAFForm1067Repository>();
}
I get the following error:
"The name 'UseSqlServer' does not exist in the current context"
Any help would be very much appreciated!

How can I use database Views in a scaffolded DbContext with Entity Framework Core 1.0 (EF7)

Unfortunately Entity Framework Core 1.0 (formerly Entity Framework 7) does not yet support Views, and I'm trying to 'fake' it using a table.
However the scaffolding dotnet dbcontext ef scaffold command doesn't currently recognize or generate views, and I want a single DbContext which allows querying a view and updating of tables. Is there a way to do this?
This is the command I use to scaffold the DbContext:
dotnet ef dbcontext scaffold -c MyStoreContext -o Model "Data Source=(local);Initial Catalog=DBNAME;Integrated Security=True" Microsoft.EntityFrameworkCore.SqlServer --force
(This puts all my model classes in a Model directory, and forces them to be overwritten.)
Note: The reason I actually want to use a View is for GROUP BY logic, which isn't supported either in EF Core 1.0
For me, my view was in a different schema, so I had to alter an attribute on the model class:
using System.ComponentModel.DataAnnotations.Schema;
namespace API.DataAccess
{
[Table("MyViewName", Schema = "SomeSchema")]
public class MyViewName
{
//props
}
}
For completeness, the entity code:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyViewName>(entity =>
{
entity.HasKey(e => new { e.SomeColumn }).HasName("PK_FAKEKEY");
entity.Property(e => e.SomeColumn ).IsRequired();
entity.Property(e => e.SomeColumn2 );
entity.Property(e => e.SomeColumn3 );
});
}
Here's what I came up with:
I create a partial class that inherits from the DbContext and then add any new logic to it by overriding the OnModelCreating method.
Eventually the EF scaffolder should (I hope) be able to create views for me, so in the interim I'm calling the class MyStoreContext_WithViews so I can do a search and replace at some point to update it.
The database view in this example is called RepeatOrderSummaryView.
I had to add all the columns manually to my view class here (since the scaffolder doesn't support it). That's fine for now.
There is no key on the View, but EF requires a key so I just create a fake one using one of the columns.
namespace MyStore.EF.Model
{
public partial class MyStoreContext_WithViews : MyStoreContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<RepeatOrderSummaryView>(entity =>
{
entity.HasKey(e => new { e.FirstOrder_Date })
.HasName("PK_FAKEKEY");
});
}
public virtual DbSet<RepeatOrderSummaryView> RepeatOrderSummaryView { get; set; }
}
[Table("RepeatOrderSummaryView")]
public partial class RepeatOrderSummaryView
{
public DateTime OrderDate { get; set; }
public bool HasShipped { get; set; }
}
}
I was then able to successfully run this query against the View:
RRStoreContext_WithViews ctx = new RRStoreContext_WithViews();
var data = ctx.RepeatOrderSummaryView.Where(x => x.HasShipped == true);
Since this class just inherits from my generated DbContext (MyStoreContext) I can of course use all the rest of the tables that were scaffolded.
Not tested on updateable views - of course if you try this you'll need a real PK defined.
Because you aren't returning 'real' entities, or necessarily items with a real key defined you should use .AsNoTracking(). I found fewer results in my result set than I expected and it was because it was doing a key match and thinking it already had the object in memory.
Be sure to test carefully to ensure the number of results is as expected - or you're going to run into big problems.
What difference does .AsNoTracking() make?

OData $orderby clause on collection property

I have the following classes :
public class Parent
{
public string ParentProp { get; set; }
public IEnumerable<Child> ManyChildren { get; set; }
}
public class Child
{
public string ChildName { get; set; }
public int Value { get; set; }
}
Say I have an OData operation defined which returns IEnumberable<Parent>. Can I write an $orderby clause which performs the following operation ('parents' is an IEnumerable<Parent>) :
parents.OrderBy(x => x.ManyChildren.Single(y => y.ChildName == "Child1").Value);
I know I can write custom actions (http://msdn.microsoft.com/en-us/library/hh859851(v=vs.103).aspx) to do this ordering for me, but I'd rather use an $orderby clause.
(The only SO question which asked something similar is a little dated - How can I order objects according to some attribute of the child in OData?)
As I tried is possible with nesting $orderby in $expand so will be:
odata/User?&$select=Active,Description,Name,UserId&$expand=Company($select=Active,Name,CreatedBy,CompanyId;$orderby=Active asc)
And what you get is somthing like:
ORDER BY [Project2].[UserId] ASC, [Project2].[C19] ASC
will order a company collection for each user separately.
I think in version OData Client for .NET 6.7.0 is supported, in release notes is writhing:
In query options
$id, $select, $expand(including nested query options)....
I see in version 6.1 that values for nested options exist and is in:
DataQueryOptions->SelectExpand->SelectExpandClasue->SelectedItems->ExpandNavigationItem->OrderByOption
but is not working.
I tried and with System.Web.OData 5.6 and all releated dependencies but seams is not working.
My conclusion:
Seams that is everiting prepared like DataQueryOptions exist nested orderby but is not working.
Like I find out standard seams is going in that direction.
https://issues.oasis-open.org/browse/ODATA-32
It depends on your OData service implementation. Which kind of service are you using? WCFDS, WebAPI, or the service you implement yourself?
Url parser do can parse the URL such as root/People?$orderby=Company/Name. The translator is implemented by service.
And I agree with the answer in related question: "it's not possible to do this with a navigation property that has a cardinality of many". Since it's has a cardinality of many, service cannot know which one should be used to sorting.

Entity Fw 4, MVC3, Derived class does not appear in the ObjectContext

I'm using MVC3 with EF (version 4, but not sure if 4.0,4.1,etc). I've been fighting with this since yesterday and I don't find the answer anywhere. I'm using the book "Pro Entity Framework 4.0".
I did Model First approach and because I want to use inheritance I created a basic model to do the first testings (sorry, click the link, I don't have enough rep to put a picture):
EF Model
Then with this model I created the database. I'm not very happy with the naming convention, because in spite of pluralizing the entity names, for the derived class table it created a prefixed-single table name. I'm sorry I don't have SSMS installed but have a look through the Server Explorer, see the picture:
DB created from EF Model
Then I created controllers for BaseClass with the template "Controller with read/write actions and views, using Entity Framework". It works great! It created all the views, CRUD.
For instance in the Details view I have this code:
//
// GET: /BaseClass/Details/5
public ViewResult Details(int id)
{
BaseClass baseclass = db.BaseClasses.Single(b => b.Id == id);
return View(baseclass);
}
It works fine.
Then I did the same for the DerivedClass and I got the controller with all the CRUD actions and the views. And now the problem. For instance the Details controller of the DerivedClass is like this:
//
// GET: /DerivedClass/Details/5
public ViewResult Details(int id)
{
DerivedClass derivedclass = db.BaseClasses.Single(d => d.Id == id);
return View(derivedclass);
}
As you can see it tries to get db.BaseClasses instead of db.DerivedClasses, with gives a compilation error, but db does not provide any access to the DerivedClass entity, there is nothing in db at all related with DerivedClass.But if I create manually an instance of DerivedClass in the code it is possible:
MyNamespace.Blablabla.Site.Models.DerivedClass dev = new Models.DerivedClass();
Am I missing anything? Thanks in advance.
Inheritance hierarchies are mapped to one DbSet. If you want to filter on inherited entities you can use:
DerivedClass derivedclass = db.BaseClasses.OfType<DerivedClass>().Single(d => d.Id == id);
The OfType<>() filters the object set for instances of the type you specify.
For adding and updating a derived entity you can also the parent DbSet and EF will map it to the correct tables.

working with Fluent NHibernate and guid ids

We're working with Fluent NHibernate 1.2 and our primary key is a guid saved in a nvarchar(32) column, working with Oracle 11gr2.
How can we make this work? (making an automatic conversion...)
Thanks ahead, random programmer...
UPDATE:
forgot to mention, the guid is saved WITHOUT dashes ...
Update:
You will have to implement your own IUserType to handle the dashless Guids.
You can read about it here:
http://dotnet.dzone.com/articles/understanding-nhibernate-type
The detail below is now irrelevant to the question but I'll keep it here for future reference for people to find.
Using Guids "normally"
In your entity the Id should be of type Guid:
public virtual Guid Id { get; private set; }
And in your ClassMap you should map it like this:
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidComb();
This will use the recommended comb algorithm to generate new guids.
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.Guid();
to genertae new Guids using System.Guid
or
Id(x => x.Id)
.Column("Id")
.GeneratedBy.GuidNative();
if you want to let the database generate the Guid for you.

Resources