Reputation: 2201
I have built the following model of hierarchy for DB:
public abstract class ApplicationUser : IdentityUser
{ }
public class FirstUser : ApplicationUser
{}
public class SecondUser : ApplicationUser
It is noticeable abstract Application class inherits from ASP.NET Core Identity's not abstarct class IdentityUser.
So my purpose is building different tables for UserFirst and UserSecond only, not for IdentityUser and ApplicationUser.
I tried to configure model the following:
builder.Ignore<IdentityUser>();
builder.Entity<FirstUser>().ToTable("FirstUsers");
builder.Entity<SecondUser>().ToTable("SecondUsers");
However it throws exception: Invalid column name 'Discriminator'
What can I do?
Upvotes: 3
Views: 8361
Reputation: 70184
Table-per-concrete-type (TPC) mapping is now available in EFC 7.0.0 nightly builds.
https://github.com/dotnet/efcore/issues/3170
https://github.com/dotnet/efcore/issues/3170#issuecomment-1124607226
What you need to try it out:
.NET SDK 7.0.100-preview.4 https://dotnet.microsoft.com/en-us/download/dotnet/7.0
Visual Studio 2022 Preview 17.3 https://visualstudio.microsoft.com/vs/preview/
NuGet Microsoft.EntityFrameworkCore 7.0.0-preview.4.22229.2
Code example:
ApplicationDbContext:
using Microsoft.EntityFrameworkCore;
namespace WebApplicationNet7.Data
{
public class ApplicationDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<RssBlog> RssBlogs { get; set; }
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Blog>().UseTpcMappingStrategy();
modelBuilder.Entity<RssBlog>().UseTpcMappingStrategy();
}
}
public class Blog
{
public int BlogId { get; set; }
public string Url { get; set; }
}
public class RssBlog : Blog
{
public string RssUrl { get; set; }
}
}
Migration will look like this:
Note that RssBlog
is missing .Annotation("SqlServer:Identity", "1, 1")
.
You will probably get a warning that looks like this:
Microsoft.EntityFrameworkCore.Model.Validation[20609]
The property 'BlogId' on entity type 'Blog' is configured with a database-generated default, however the entity type is mapped to the database using table per concrete class strategy. Make sure that the generated values are unique across all the tables, duplicated values could result in errors or data corruption.
I could not get it to work with either setting
modelBuilder.Entity<RssBlog>().Property(u => u.BlogId).UseIdentityColumn();
or using annotation [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
.
Upvotes: 2
Reputation: 64297
Table per Concrete Type (TPC) or Table per Type (TPT) aren't currently supported in EntityFrameework Core 1.0. Only Table per Hierarchy (TPH) is supported.
TPC and TPT are on the high priority list and may come in EntityFramewor Core 1.1 or 1.2, see the EntityFramework Core Roadmap.
Backlog Features
...
High priority features
...
- Modelling
- More flexible property mapping, such as constructor parameters, get/set methods, property bags, etc.
- Visualizing a model to see a graphical representation of the code-based model.
- Simple type conversions such as string => xml.
- Spatial data types such as SQL Server's geography & geometry.
- Many-to-many relationships without join entity. You can already model a many-to-many relationship with a join entity.
- Alternate inheritance mapping patterns for relational databases, such as table per type (TPT) and table per concrete type TPC.
As for your question:
You can't do anything about it. If you absoloutely need this feature, you have to fall back to EntityFramework 6.x, but then you can't target .NET Core and have to target .NET Framework 4.x.
It should be noted here, that Microsoft do not feels (or recommends) to use EntityFramework Core 1.0 yet in production environment, if you require the features used from EF6. It will take several versions (at least 2 minor releases) until EntityFramework Core will get anyway close featurewise to EF6.
So if TPC is absolute requirement, go back to EF6.
Technical stuff aside, performance wise it's prefered to use TPH for mapping inheritance to your database as it avoids unnecessary joins during queries. When you use TPT/TPC every query invovling it will have to perform joins and joins are less performant.
So unless you have to map to a legacy DB designed in that way, you should fall back to TPH.
Upvotes: 7