Changing EF Core 3.1 conventions
A few days ago, a college ask me how to change EF Core 3.1 conventions. A little research later I found the this is possible, but a bit hidden.
EF Core 3.1 uses convention sets with all available conventions for a provider. Those sets are created by some sort of convention set builder. In case of a relational database like SQL Server it is a SqlServerConventionSetBuilder based on RelationalConventionSetBuilder which implements IProviderConventionSetBuilder
.
This builder can be replaces by in EF Core’s internal DI service with your own customized implemenation.
serviceCollection.AddDbContext<MyContext>(o => { o.ReplaceService<IProviderConventionSetBuilder, MySqlServerConventionSetBuilder>() .UseLoggerFactory(EFLoggerFactory.Instance) .UseSqlServer(MyContext.CONSTRING); });
Now you can write a custom convention and make your builder add this to the list of conventions- or simply remove one of the given conventions. It’s CreateConventionSet()
method is doing the job.
public override ConventionSet CreateConventionSet() { var conventionSet = new ConventionSet(); var propertyDiscoveryConvention = new PropertyDiscoveryConvention(Dependencies); var keyDiscoveryConvention = new MyKeyDiscoveryConvention(Dependencies); var inversePropertyAttributeConvention = new InversePropertyAttributeConvention(Dependencies); var relationshipDiscoveryConvention = new RelationshipDiscoveryConvention(Dependencies); var servicePropertyDiscoveryConvention = new ServicePropertyDiscoveryConvention(Dependencies); conventionSet.EntityTypeAddedConventions.Add(new NotMappedEntityTypeAttributeConvention(Dependencies)); conventionSet.EntityTypeAddedConventions.Add(new OwnedEntityTypeAttributeConvention(Dependencies)); conventionSet.EntityTypeAddedConventions.Add(new NotMappedMemberAttributeConvention(Dependencies)); conventionSet.EntityTypeAddedConventions.Add(new BaseTypeDiscoveryConvention(Dependencies)); conventionSet.EntityTypeAddedConventions.Add(propertyDiscoveryConvention); conventionSet.EntityTypeAddedConventions.Add(servicePropertyDiscoveryConvention); conventionSet.EntityTypeAddedConventions.Add(keyDiscoveryConvention); ... }
A new convention is based best on a given convention (or it’s interfaces).
public class MyKeyDiscoveryConvention : IEntityTypeAddedConvention, IPropertyAddedConvention, IKeyRemovedConvention, IEntityTypeBaseTypeChangedConvention, IPropertyFieldChangedConvention, IForeignKeyAddedConvention, IForeignKeyRemovedConvention, IForeignKeyPropertiesChangedConvention, IForeignKeyUniquenessChangedConvention, IForeignKeyOwnershipChangedConvention { ... }
Writing a new convention is not that easy as it could/ should be, but possible. It’s a bit work and I would only do this if absolutely required. I guess to override OnModelCreating()
and is the best in most cases.