Out of the box, EF 4 will apply a number of conventions to an entity model to derive an appropriate physical data model. For example, it will be assumed that a property of type int with a name that is the same as the class name suffixed with Id represents the primary key of the underlying data table.

It doesn’t take too much variance from what is expected before EF 4 is not able to imply the appropriate datamodel, and that is where explicit model definition is required.

EF 4 has two methods for defining the model – either using declarative attributes, or using Configuration classes. Configuration classes derive from EntityTypeConfiguration<TEntity>, and are added to the modelBuilder of the DbContext during model creation.

Today I’m going to examine a few common scenarios that you’ll probably come up against some time or other when using EF 4 Code First, and how you might approach them using both attributes and Configuration classes.

With foreign keys, they can either be exposed in the model or not. When I say “exposed in the model”, it means there is an additional property on the dependent entity that is the value of the principal entity. In the code below, the property PrimaryCategoryCode is an exposed foreign key of Primary Category.

Note the use of the empty WithMany() API to indicate the relationship is navigable in just one direction (Product->Category).

It’s possible to customise the name of the foreign key column using the Column attribute as I’ve already covered.

Where the foreign key is not exposed on the model (say the property “ProductCatgoryCode” was not on the Product class), then the situation is a bit more complex, and I think a custom column name can only be configured using the Fluent API as follows:

Note the use of the IsIndependent() API to indicate that the foreign key column is not exposed on the Product entity. In this case the foreign key coulmn in the database would be called “MainCategory”.

Custom storage type

It is common to want to store a decimal as a money type. EF 4 will not do this automatically. We can again the ColumnAttribute to specify the desired store type as follows (where the store type is a string that matches a SqlServer datatype).

Ignore a property

Is not uncommon to have properties that you do NOT want persisted. You can declaratively specify this using the System.ComponentModel.DataAnnotations.NotMapped attribute, or use the fluent API as follows:

Where both ends of the relationship are either required or optional, additional hints need to be supplied to indicate which table in the database is the primary key holder, and which is the foreign key holder.

This will result in a column called “Type” being generated in the database, even though it does not exist in the object model. When an instance of “DiscontinuedProduct” is saved, the value “Old” will be saved into the column Type.

Table Per Type

In TPT a base set of properties are saved in a table, and properties specific to derived classes are kept in separate tables joined by foreign keys.

To implement TPC, simply specify a different table to store the sub class in as follows:

Table per Concrete Type

In TPC, there is a base abstract class that all concrete classes inherit from. Each of classes are stored in their own table. It does not seem possible to do TPC where the base class is non-abstract and has storage.

Conclusion

I’ve covered a lot of scenarios here. It can be seen that many peristence specifications can be made either declaratively as attributes or using special configuration classes.

I would normally avoid decorating entity classes with persistance specifications such as column name, table name, store type or ignore, preferring instead to use a buddy configuration class and the model builder. To use of attributes couples the entity to it’s persistence, which seem to me to be defeating the whole point of having an ORM in the first place.

Entity Framework still feels like it has a ways to go compared to say NHibernate, particularly in the the specification of discriminator for sub clsses and the use of custom types, but it has come a long way.

I was interested to see today that Orchard, the new CMS recently published by Microsoft, is backed by NHibernate instead of Entity Framework. To my mind that shows amazing pragmatism on the part of Micrsoft, and in no dampens my enthusiasm for Entity Framework – I am sure it’s going to get even better down the track.

Nice post. Have you ever tried mapping a inherited property? Because I would be glad to hear that works, as I am getting the error:

“The property ‘UserName’ is not a declared property on type ‘Advertiser’. Verify that the property has not been explicitly excluded from the model by using the Ignore method or NotMappedAttribute data annotation. Make sure that it is a valid primitive property. ”