How to create Table per type inheritance in Entity Framework Core 2.0 code first? - entity-framework

Following code generates only single table "CertificateEvent".
How do I achieve TPT inheritance in EF Core 2.0?
public abstract class CertificateEvent {
public int CertificateEventId { get; set; }
}
public class Assignment : CertificateEvent {...}
public class Assessment : CertificateEvent {...}
public class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
public DbSet<Assessment> AssessorAssessments { get; set; }
public DbSet<Assignment> AssessorAssignments { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<CertificateEvent>().ToTable(nameof(CertificateEvent));
modelBuilder.Entity<Assessment>().ToTable(nameof(Assessment));
modelBuilder.Entity<Assignment>().ToTable(nameof(Assignment));
}
}
class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
{
public MyDbContext CreateDbContext(string[] args)
{
var builder = new DbContextOptionsBuilder<MyDbContext>();
builder.UseSqlServer("Server=(local);Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true");
return new MyDbContext(builder.Options);
}
}
I've also tried dotnet ef migrations add Inheritance, but it did not created TPT inheritance in the database

TPT is not in EF Core (yet). See
The feeling from our team is that TPT is generally an anti-pattern and
results in significant performance issues later on. While enabling it
may make some folks "happier" to start with it ultimately just leads
to issues. We are willing to consider it though, so we're leaving this
open and will consider it based on the feedback we get.
https://github.com/aspnet/EntityFrameworkCore/issues/2266

Related

EF Core migration

I have a working web application (an end point) containing a few methods and connected to two tables in sql server. This application is fully implemented from scratch by myself in an ashx file and does not follow any new or old architecture, simply some methods in ashx file that are remotely called and handle requirements of client. There are shared DLLs among client and server for data handling.
For some reasons I want to upgrade client side to Dot Net core, consequently common DLL needs to be upgraded and finally the end point.
Now I'm facing the problem that EF Core only supports code first, but there are ways for scaffolding . I started with Microsoft tutorials. Then I see There are certain ways for migrating and scaffolding existing database, but I got stuck for hours in first step of using command "dotnet ef dbcontext scaffold "Data Source=..." . Then usually tutorial materials get combined with other technologies like asp.net core very fast, I need to read tons of technologies to do a simple task.
I'm worried I'm going the wrong way. there are only two tables and I can implement table structure by hand. Isn't there any sample code that I can modify it's table definitions and I can restart my project soon? If things are so hard, I will omit EF from my project and redefine the whole end point logic by text sql queries.
I can implement table structure by hand.
Great. Simply create a DbContext subtype that has a DbSet for each of your entities. The only thing scaffolding does is save you time.
Here's a complete example for SQL Server:
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Order> Orders { get; } = new HashSet<Order>();
}
public class Order
{
public int CustomerId { get; set; }
public int Id { get; set; }
public Customer Customer { get; set; }
}
public class Db : DbContext
{
string connectionString = "Server=localhost; database=efcore5test; integrated security = true;TrustServerCertificate=true;";
public DbSet<Customer> Customers { get; set; }
public DbSet<Order> Orders{ get; set; }
public Db(string connectionString) : base()
{
this.connectionString = connectionString;
}
public Db() : base()
{
this.Database.SetCommandTimeout(180);
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
var constr = this.connectionString;
optionsBuilder.LogTo(Console.WriteLine);
optionsBuilder.UseSqlServer(constr, o => o.UseRelationalNulls().CommandTimeout(180).UseNetTopologySuite());
base.OnConfiguring(optionsBuilder);
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().HasKey(o => new { o.CustomerId, o.Id });
base.OnModelCreating(modelBuilder);
}
}

Migrate Entity Framework 4.0 to Core

I have an old project developed with the Entity Framwork 4.0 which uses some complex types. Since I need to migrate it to .NET Core, I created a new project, installed all required libraries and used the command
PM> Scaffold-DbContext "Server=ServerInstance; Database=DBName; Trusted_Connection=True;"
Microsoft.EntityFrameworkCore.SqlServer -OutputDir Models
on the existing database in order to create the new models. The problem is that it does not generate the complex type classes.
I can imagine I could replace the generated properties with by hand created complex types, use the [ComplexType] attribute and set the property using OwnsOne command, but I was wandering if there is a sort of auto generation option.
Is there a way to do this?
I created a second partial class in order to add custom stuff to the created one. Added also a partial OnModelCreatingPartial method in which I define my complex types.
Here a snippet:
[Owned]
public class MyComplexType
{
public bool AField { get; set; }
public string BField { get; set; }
}
public partial class MyMainEntity
{
public MyComplexType MyComplexType { get; set; }
}
public partial class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer("myConnectionString",
opts => opts.CommandTimeout((int)TimeSpan.FromMinutes(10).TotalSeconds)
);
}
}
partial void OnModelCreatingPartial(ModelBuilder modelBuilder)
{
modelBuilder.Entity<MyMainEntity>().OwnsOne(e => e.MyComplexType, myComplexType =>
{
myComplexType.Property(p => p.AField).HasColumnName("ColumnNameFieldA");
myComplexType.Property(p => p.BField).HasColumnName("ColumnNameFieldB");
});
}
}

The entity type <myType> is not part of the model for the current context

Using EF6, .NET 4.0
I have my own custom models and am using Database First approach. I've modified the edmx to use the same namespace as my custom models. I'm getting the error in the subject of the thread when running the code. The class 'User' does exist in my model and in my edmx. I also have my custom DbContext like so:
public class MyEntities : DbContext
{
public MyEntities()
: base("Name=MyEntities")
{
User = Set<User>();
}
public virtual DbSet<User> User { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
}
Any ideas?

EntityFramework how to not map a class but do map it's inherited properties

We use EntityFramework 6.1 with CodeFirst in our web mvc application (StdWebApp). Now we want to make a new custom version of this application (CustomWebApp) .
The CustomWebApp will use most of the code of the standard one, in it's domain model it will extend the Person class.
In CustomDomain we make implement a new DbContext that must connect with the database of the custom app (CustomSqlDb).
In (C#) code there is no problem that there is a Person in Domain and in CustomDomain. However we have not been able to devise a mapping for Person in the Custom DbContext that will:
Create a single "Person" table.
Contains fields form "CustomDomain.Person" AND those from "Domain.Person".
We tried some variants like this:
modelBuilder.Entity<Person>().Map(m =>
{
m.MapInheritedProperties();
m.ToTable("Person");
}
);
using this document as our inspiration msdn mapping types
But EF complains about the simple name beeing equal.
Obviously we could rename the "Person" in "CustomDomain" to "PersonCustom" but that could lead to a lot of silly names if we have to do this again in the future like "PersonCustomExtraSpecial" etc.
Thoughts anyone?
UPDATE
we tried the solution suggested by mr100, here is the complete code:
namespace Domain
{
public class Person
{
public int Id { get; set; }
public string Stuff { get; set; }
}
}
namespace CustomDomain
{
public class Person : Domain.Person
{
public string ExtraStuff { get; set; }
}
}
namespace CustomDomain
{
public class DbModel : DbContext
{
DbSet<CustomDomain.Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<CustomDomain.Person>().Map(m => m.ToTable("Person"));
}
}
}
This still result in the error
The type 'CustomDomain.Person' and the type 'Domain.Person' both have the same simple name of 'Person' and so cannot be used in the same model. All types in a given model must have unique simple names. Use 'NotMappedAttribute' or call Ignore in the Code First fluent API to explicitly exclude a property or type from the model.
So we added the following code:
namespace CustomDomain
{
public class DbModel : DbContext
{
DbSet<CustomDomain.Person> Persons { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<Domain.Person>();
modelBuilder.Entity<CustomDomain.Person>().Map(m => m.ToTable("Person"));
}
}
}
Still same result.
To achieve this your DbContext class in CustomWebApps should have property People defined like this:
public DbSet<CustomDomain.Person> People {get; set;}
and no property:
public DbSet<Domain.Person> People {get; set;}
even if it comes from StdWebApp DbContext class from which CustomWebApp DbContext class may derive (if that is the case for you). Additionally you may set properly table name:
modelBuilder.Entity<Person>().ToTable("Person");

Model-first Entity Framework - how to have multiple schemas

I googled/searched for an answer here in SO, but didn't find anything, specially specific for model-first approach.
I am just starting with creation of a new model for my new database and want to organize the entities for tables that logically belong to different scopes by having multiple schemas. I am using .NET-4.5
thanks in advance.
imagine that you have these two classes (Models):
public class Order
{
}
public class Book
{
}
now in entity framework code first, you can implement the table in schema like this:
public class ContextClass : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Order>().ToTable("Order", schemaName: "Orders");
modelBuilder.Entity<Book>().ToTable("Book", schemaName: "Books");
}
public DbSet<Book> Customers { get; set; }
public DbSet<Order> Orders { get; set; }
}