2011-04-08 112 views
11

我想使用一个普通的EntityTypeConfiguration类来配置我的所有实体的主键,以便每个派生的配置类不会重复自己。我的所有实体都实现了一个通用接口IEntity(它表示每个实体必须具有int类型的Id属性)。实体框架4.1 RC:代码第一个EntityTypeConfiguration继承问题

我的配置基础类看起来是这样的:

public class EntityConfiguration<TEntity> : EntityTypeConfiguration<TEntity> 

    where TEntity : class , IEntity { 

    public EntityConfiguration() { 

     HasKey(e => e.Id); 

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

    } 

} 

每个实体然后有它的延伸这一个这样自己的具体配置类:

public class CustomerConfiguration : EntityConfiguration<Customer> { 

    public CustomerConfiguration() : base() { 

     // Entity specific configuration here 

    } 

} 

它编译罚款,但我的问题在运行时,我会在EF 4.1 RC尝试创建模型时得到以下异常:

System.InvalidOperationException是 未处理消息=关键组件 'Id'不是 类型'Customer'的声明属性。确认它没有明确地从 模型中排除 ,并且它是有效的基元 属性。来源=的EntityFramework

如果我改变CustomerConfiguration类从EntityTypeConfiguration <客户>扩展和重复的主键的配置,然后它工作正常,但我失去了共享公共配置的能力(DRY主要是动机)。

  • 我在这里做错了什么?
  • 是否有另一种方法来共享实体之间的共同配置?

仅供参考这里所涉及的其他类:

public interface IEntity { 

    int Id { get; set; } 

} 

public class Customer : IEntity { 

    public virtual int Id { get; set; } 

    public virtual string name { get; set; } 

} 

谢谢!

回答

2

我不认为你需要经历所有这些。 EF 4.1 Code First使用大量的约定而不是配置,通过这种方式,实体的Id属性被配置为主键。所以通过在你的实体上实现IEntity接口,你可以用Id作为主键来设置它们。

下面是对ADO.NET团队博客,解释了主键惯例是如何工作的一个环节 - Conventions for Code First

+7

是的,这是真的,但个人而言,我不喜欢依赖这些约定,并且在可能的情况下我想要配置明确,自我记录和版本控制。迟早会有些东西可能不适合公约,所以这些问题应该可以预先解决。这个简化示例中还没有显示一些共享配置,我不确定该约定是否会自动处理。 – Jamie 2011-04-08 12:17:37

+1

“我不喜欢依赖于约定” - 然后编写一个测试,当约定发生变化时它会失败,记录事实(用代码或其他方式)是不太理想的方法 – RhysC 2014-08-22 04:11:43

12

它看起来像这些配置有一些问题与接口。

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() 
    { 
     ... 
    } 
} 
+0

嗯,我试图转换接口进入抽象类,它仍然不起作用。然后我让基类非抽象,它仍然不起作用!我现在已经开始重复配置,直到(有一天?)实体框架团队支持使用代码优先(我认为这是我自己的核心要求)接口的软件。 – Jamie 2011-04-12 22:23:04

+0

它为基础类工作,所以一定有另一个问题。 – 2011-04-12 22:24:02

+0

虽然这对我有用,但我宁愿使用界面。 EF希望未来能够支持这一点。 – jrummell 2011-07-14 13:39:00

1

你可以只创建一个类的静态方法和实体传递到它:如果你改变IEntityEntityBase它的工作原理。例如:

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); 
    } 
} 
+0

不是一个糟糕的解决方法。 – David 2012-08-10 09:15:53

0

我与EF5.0有类似的问题,当我有抽象成员和自定义属性的Id属性和实现的通用抽象类。 看起来像实体框架代码,首先只查看映射的类属性。 我曾尝试使用反射器 - 看起来我是对的,但不确定这是100%。

而且,这个幸运的是,已经找到解决方案:

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

所以在我的情况:也映射从基类的属性我必须添加的代码m.MapInheritedProperties()一行...