开发者

Entity Framework 4.1 RC: Code First EntityTypeConfiguration inheritance issue

I am trying to use a common EntityTypeConfiguration class to configure the primary key for all of my entities, so that each derived configuration class does not repeat itself. All of my entities implement a common interface IEntity (which says that each entity must have an Id property of type int).

My configuration base class looks like this:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>

    whe开发者_开发问答re TEntity : class , IEntity {

    public EntityConfiguration() {

        HasKey( e => e.Id );

        Property( e => e.Id ).HasDatabaseGeneratedOption( DatabaseGeneratedOption.Identity );

    }

}

Each entity then has it's own specific configuration class extending this one like this:

public class CustomerConfiguration : EntityConfiguration<Customer> {

    public CustomerConfiguration() : base() {

        // Entity specific configuration here

    }

}

It compiles fine, but the problem I am having is that at runtime I get the following Exception being raised when EF 4.1 RC tries to create the model:

System.InvalidOperationException was unhandled Message=The key component 'Id' is not a declared property on type 'Customer'. Verify that it has not been explicitly excluded from the model and that it is a valid primitive property. Source=EntityFramework

If I change the CustomerConfiguration class to extend from EntityTypeConfiguration<Customer> and repeat the primary key configuration then it works fine, but I lose the ability to share common configuration (DRY principal is the motivation).

  • Am I doing something wrong here?
  • Is there another way to share common configuration between entities?

For reference here are the other classes involved:

public interface IEntity {

    int Id { get; set; }

}

public class Customer : IEntity {

    public virtual int Id { get; set; }

    public virtual string name { get; set; }

}

Thanks!


It looks like these configurations has some problem with interface. It works if you change IEntity to EntityBase:

public class EntityBase
{
    public virtual int Id { get; set; }
}

public class Customer : EntityBase
{
    public virtual string Name { get; set; }
}

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity>
    where TEntity : EntityBase
{
    public EntityConfiguration()
    {
        HasKey(e => e.Id);
        Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}

public class CustomerConfiguration : EntityConfiguration<Customer>
{
    public CustomerConfiguration()
        : base()
    {
        ...
    }
}


I do not think that you need to go through all of this. EF 4.1 Code First uses a lot of convention over configuration and via this, the Id property of an entity is configured as the primary key. So by implementing the IEntity interface on your entities you are setting them up with the Id as the primary key.

Here is a link to the ADO.NET Team Blog that explains how the primary key convention works - Conventions for Code First


You could just create a static method on a class and pass the entity into it. For example:

public class CustomerConfiguration : EntityConfiguration<Customer>
{
    public CustomerConfiguration()
        : base()
    {
        ...
        EntityConfiguration.Configure(this);
    }
}

public static class EntityConfiguration
{
    public static void Configure<TEntity>(EntityTypeConfiguration<TEntity> entity) where TEntity : EntityBase
    {
        entity.HasKey(e => e.Id);
        entity.Property(e => e.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
    }
}


I have similar issue with EF5.0 when i have generic abstract class with Id property and implementation for abstract members and self defined properties. look like entity framework code first is looking only for mapped class properties. i have tried to use reflector - seems i am right, but don't sure about this for 100%.

And, fortunately, have found solution for this:

 protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {                
            modelBuilder.Conventions.Remove<IncludeMetadataConvention>();
            modelBuilder.Entity<MyEntity>()
               .Map(m =>
               {
                   **m.MapInheritedProperties();**                   
               });
        }

so in my case: to map also properties from base class i have to add one line of code m.MapInheritedProperties()...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜