using EF 6.1+ there were times where we need to add or remove existing conentions. The code looks more or less like:
public class MyContext : DbContext { protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.AddFromAssembly(Assembly.GetExecutingAssembly()); modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); base.OnModelCreating(modelBuilder); } }
how do the same in EF core? Modelbuilder has no Conventions property :(
Conventions are a set of rules hard-baked into Entity Framework Core that govern how the model will be mapped to a database schema. Most of the time, especially with new application development, it makes sense to follow EF Core's conventions when developing the model.
EF will create a primary key column for the property named Id or <Entity Class Name> + "Id" (case insensitive). By default EF will look for the foreign key property with the same name as the principal entity primary key name.
I'm porting some code from EF to EF Core 2.1+ and can't wait for EF Core 3.0 so wrote a few extension methods which help a bit..
public static IEnumerable<IMutableEntityType> EntityTypes(this ModelBuilder builder) { return builder.Model.GetEntityTypes(); } public static IEnumerable<IMutableProperty> Properties(this ModelBuilder builder) { return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties()); } public static IEnumerable<IMutableProperty> Properties<T>(this ModelBuilder builder) { return builder.EntityTypes().SelectMany(entityType => entityType.GetProperties().Where(x => x.ClrType == typeof(T))); } public static void Configure(this IEnumerable<IMutableEntityType> entityTypes, Action<IMutableEntityType> convention) { foreach (var entityType in entityTypes) { convention(entityType); } } public static void Configure(this IEnumerable<IMutableProperty> propertyTypes, Action<IMutableProperty> convention) { foreach (var propertyType in propertyTypes) { convention(propertyType); } }
with these you can write conventions similar to those in EF 6.1.x, for example.
// equivalent of modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); modelBuilder.EntityTypes() .Configure(et => et.Relational().TableName = et.DisplayName()); // Put the table name on the primary key modelBuilder.Properties() .Where(x => x.Name == "Id") .Configure(p => p.Relational().ColumnName = p.DeclaringEntityType.Name + "Id"); // Mark timestamp columns as concurrency tokens modelBuilder.Properties() .Where(x => x.Name == "Timestamp") .Configure(p => p.IsConcurrencyToken = true);
For EF Core 3.0 the metamodel methods have changed slightly so you need
modelBuilder.EntityTypes() .Configure(et => et.SetTableName(et.DisplayName())); modelBuilder.Properties() .Where(x => x.Name == "Id") .Configure(p => p.SetColumnName(BaseName(p.DeclaringEntityType.Name) + "Id"));
Haven't checked this for efficiency but unless your model is huge it shouldn't pose a problem
This can be extended with other helpers for foreign keys, indexes etc
Looks like it's still not in EF Core 2.0. So here's one way of achieving it. I had done this to apply consistent behaviour to certain attributes, but to address the examples in your question you could try this:
protected override void OnModelCreating(ModelBuilder modelBuilder) { // equivalent of modelBuilder.Conventions.AddFromAssembly(Assembly.GetExecutingAssembly()); // look at this answer: https://stackoverflow.com/a/43075152/3419825 // for the other conventions, we do a metadata model loop foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { // equivalent of modelBuilder.Conventions.Remove<PluralizingTableNameConvention>(); entityType.Relational().TableName = entityType.DisplayName(); // equivalent of modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); // and modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>(); entityType.GetForeignKeys() .Where(fk => !fk.IsOwnership && fk.DeleteBehavior == DeleteBehavior.Cascade) .ToList() .ForEach(fk => fk.DeleteBehavior = DeleteBehavior.Restrict); } base.OnModelCreating(modelBuilder); }
You should be able to do a lot of things with entityType
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With