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.