Custom Code First Conventions
Currently there are three ways to customize conventions in EF6:
- Lightweight conventions
- Configuration conventions
- Model conventions
We thought that having three ways to do conventions would be confusing unless there where obvious and clear boundaries around when it made sense to use each type. This is easy enough for model conventions, as they are the only way to write conventions that manipulate the EDM. But it was more difficult to clearly define situations where a user should use lightweight vs configuration conventions, they are both different ways of modifying the configuration that goes into building a model.
We also thought that the interfaces used in configuration conventions suffered from a lack of discoverability. However, configuration conventions do have some functionality that is not included in lightweight conventions, such as the ability to configure associations and are more easily encapsulated and shared between projects.
We considered a number of options to resolve this, including:
- Change the configuration conventions surface to address some of the issues we had with it, such as changing it to have two top level interfaces that each only require a single generic parameter e.g. IPropertyConfigurationConvention<TConfiguration> and ITypeConfigurationConvention<TConfiguration> instead of IConfigurationConvention<TMemberInfo, TConfiguration>
- Merge the functionality of configuration conventions with that of lightweight conventions. This would require adding some capabilities to the lightweight api so that it can do more of the things that configuration conventions can do.
When we did an analysis of what we thought was missing from Lightweight conventions we identified the following:
- Ignore a type
- Make an entity a complex type
- Allow the configuration of associations
We decided to merge lightweight conventions and configuration conventions. This requires a few changes:
- Add the functionality from configuration conventions that is missing form light weight conventions.
- Make the existing configuration convention classes internal (they basically become an implementation detail of lightweigh conventions) and introduce a way to encapsulate lightweight conventions in a class - similar to how Fluent API config can be done directly in OnModelCreating or encapsulated in an EntityConfiguration class.
- The class that allows you to implement lightweight conventions will implement IConvention so that the existing DbModelBuilder.Conventions.Add/Remove API continues to work as-is.
- We may update the default conventions we wrote using configuration conventions to use the new combined API. Because the only public use of these is the ability to remove them, provided they continue to implement IConvention there will be no breaking change to developers code.
In addition to the merging configuration conventions and lightweight conventions we are also making some changes to simplify model based conventions:
- Prior to EF6 Code First has its own internal object model for representing your EF model. This object model had separate classes for representing your conceptual model (entities, properties, etc.) and your database model (tables, columns, etc.). Therefore we had two model convention interfaces – one for manipulating the conceptual model (IEdmConvention) and one for manipulating the database model (IDbConvention).
- In EF6 we moved the core components out of the .NET Framework and into EntityFramework.dll. This allowed us to remove this separate object model and standardized on the core EF object model. This object model uses the same classes to represent both the conceptual and database model (i.e. entities and properties are used to represent tables and columns).
- This now means that IEdmConvention and IDbConvention have the same signature. Therefore we decided to merge them into the same interface and allow an enum value to be passed identifying whether the convention targets the database or conceptual model. We’ll use the existing DataSpace enum.
- The IDbMappingConvention is currently available to implement, but conventions that implement the interface are not actually able to mutate the model because the mapping is currently read-only. Since a convention that can read, but not modify, the mapping is not going to be very useful we will make IDbMappingConvention internal. If we modify EF so that mapping information can be mutated then we will make the interface public again.