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.