In this post I’m going to cover configuring Entity Framework “CodeFirst”.
- Custom column name
- Custom storage type
- Custom table name
- Data constraints
- Ignore a property
- Turning cascade delete off
- One to one mapping
- Inheritance Mapping
- Conclusion
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.
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){} } public class ProductContext : DbContext{ public DbSet<product> Products { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder){ modelBuilder.Configurations.Add(new ProductConfiguration()); } }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.
Unconventional Key Name
Consider the class Product:
public class Product{ public int ProductCode { get; set; } public string Name { get; set; } }EF 4 will not be able to build a
DBSet<Product>– it will complain that a key has not been defined (because there is no property called “PropertyId”).Using Attributes, we can decorate the ProductCode property with the
System.ComponentModel.DataAnnotations.KeyAttribute.public class Product{ [Key] public int ProductCode { get; set; } public string Name { get; set; } }Or alternatively we could use the Configuration class (ensuring that the configuration class is added to the modelBuilder Configurations in
OnModelCreatingof theDbContext).public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.HasKey(m =>m.ProductCode); } }Either of these approaches will work.
Custom Column Name
Code naming conventions may differ from database naming conventions, so it may be neccesary to specify a custom column name for a property.
Using the
System.Component.DataAnnotations.ColumnAttribute, we can specify the column name as follows:[Column(Name="ProductName")] public string Name { get; set; }Using configuration, we can specify the column name using the HasColumName fluent API:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.Property(m => m.Name).HasColumnName("ProductName"); } }It is possible to have a custom name for the Key column also. Simply add a
ColumnAttributein addition to theKeyAttribute, or in the Fluent API add another specification:public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.HasKey(m => m.ProductCode); this.Property(m => m.ProductCode).HasColumnName("ProductID"); .... } }The default names for foreign keys can be changed also.
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.
public string PrimaryCategoryCode { get; set; } public virtual Category PrimaryCategory { get; set; }To indicate this, use the ForeignKey attribute on the PrimaryCategory property as follows:
public string PrimaryCategoryCode { get; set; } [ForeignKey("PrimaryCategoryCode")] public virtual Category PrimaryCategory { get; set; }You can also use the Fluent API as follows:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ .... this.HasRequired(m => m.PrimaryCategory).WithMany().HasForeignKey(p=>p.PrimaryCategoryCode); .... } }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
Columnattribute 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:
this.HasRequired(m => m.PrimaryCategory) .WithMany() .IsIndependent() .Map(m => m.MapKey(p => p.CategoryCode, "MainCategory"));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).
public class Product{ .... [Column(TypeName="money", Name="PurchasePrice")] public decimal BaseCost { get; set; } .... } public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.Property(m => m.BaseCost).HasColumnName("PurchasePrice").HasColumnType("money"); } }Data Constraints
DataAnnotation attributes such as
Requiredor StringLength will be applied to the applicable columns. They can also be applied using the Fluent API as follows:public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.Property(m => m.Name) .HasColumnName("ProductName") .IsRequired() .HasMaxLength(50); ..... } }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.NotMappedattribute, or use the fluent API as follows:public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.Ignore(m=>m.CurrentUserName); ..... } }Custom table name
Use the class-level
System.ComponentModel.DataAnnotations.Tableattribute to specify a custom storage location for an entity:[Table("tblProduct")] public class Product{ .... }Or use the Fluent API as follows:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.ToTable("tblProduct"); ..... } }There is an overload in both cases to enable the specification of a schema name.
Turning Cascade Delete Off
This seems only possible using the Fluent API as follows:
public class CategoryConfiguration : EntityTypeConfiguration<category>{ public CategoryConfiguration(){ this.HasMany(c => c.Products) .WithRequired(p=>p.PrimaryCategory) .WillCascadeOnDelete(false); } }One to One relationships
Generally a bad idea, but sometimes you have them. It seems they can only be represented using the Fluent API. The result in the database one table's primary key is a foreign key into the other table.
Where the relationship is optional at one end, then the mapping is pretty strightforward as follows:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ ... this.HasOptional(p => p.Note).WithRequired(n => n.Product); ... } }Will result in the Notes table having a non-identity primary key.
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.
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ .... this.HasRequired(p => p.Note).WithRequiredPrincipal(n => n.Product); } }The
WithRequiredPrincipalFluent API indicates that the Product table is the primary key table. Alternatively, using theWithRequiredDependentwould mean the Notes table was the primary key table.Inheritance mapping
Table Per Heirarchy mapping
In TPH, all derived instances of a base class are stored in the same table, with a column acting as a discriminator.
All Mapable subclasses must be defined using the Fluent API as follows:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.Map<product>(m=>m.Requires("Type").HasValue("Current")); this.Map<discontinuedproduct>(m => m.Requires("Type").HasValue("Old")); } }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:
public class ProductConfiguration : EntityTypeConfiguration<product>{ public ProductConfiguration(){ this.ToTable("Products"); } } public class DiscontinuedProductsConfiguration: EntityTypeConfiguration<discontinuedproduct>{ public DiscontinuedProductsConfiguration<p align="center"></p>(){ this.ToTable("DiscontinuedProducts"); } }This will result into tables being created in the database.
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.
I going to create a very contrived code mode:
public abstract class Product{ public int ProductId { get; set; } public string Name { get; set; } } public class TaxableProduct : Product{ public string TaxCode{get;set;} } public class UnTaxedProduct : Product{ public string Reason{get;set;} }Becuase the tables are being persisted to different tables, separate configurations are required.
public class UnTaxedProductConfiguration : EntityTypeConfiguration<untaxedproduct>{ public UnTaxedProductConfiguration(){ this.Map(m => m.MapInheritedProperties()).ToTable("Untaxed"); this.HasKey(m => m.ProductId); this.Property(m => m.ProductId).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity); } } public class TaxableProductProductConfiguration : EntityTypeConfiguration<taxableproduct>{ public TaxableProductProductConfiguration(){ this.Map(m => m.MapInheritedProperties()).ToTable("taxed"); this.HasKey(m => m.ProductId); this.Property(m => m.ProductId).HasDatabaseGenerationOption(DatabaseGenerationOption.Identity); } }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.

Thanks, very useful information.
Actually there is a way to Ignore a property by attribute its called ‘NotMapped’
Thanks for that – I’ve updated the post accordingly – X
As you mentioned Orchard, it’s worth to have a look on Dotnetage. It uses EF – Code First.
That was some instructive writing!
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. ”
My model looks like this:
abstract class Entity { public int Id {get; set; }}
abstract class User : Entity { public string UserName {get; set;} }
sealed class Advertiser : User
My AdvertisementConbfiguration class looks like this:
class AdvertiserConfiguration : EntityTypeConfiguration
{
public AdvertiserConfiguration()
{
// the following line indirectly causes an InvalidOperationException:
Property( x => x.UserName ).HasMaxLength(50);
}
}
If I would change the Advertiser class so that it does not inherit from User (and pull the UserName property down) then it works great.
I found the answer here on StackOverflow: http://stackoverflow.com/questions/8170338/ef4-code-first-fluent-mapping-does-not-work-with-inherited-properties
In summary, you need to create another configuration class that configures the abstract class (‘User’ in my case).