问题 实体框架4.1 RC:Code First EntityTypeConfiguration继承问题


我试图使用一个通用的EntityTypeConfiguration类来为我的所有实体配置主键,以便每个派生的配置类不会重复。我的所有实体都实现了一个公共接口IEntity(它表示每个实体必须具有int类型的Id属性)。

我的配置基类如下所示:

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'不是声明的属性   输入“客户”。验证它有   未被明确排除在外   模型,它是一个有效的原语   属性。来源=的EntityFramework

如果我将CustomerConfiguration类更改为从EntityTypeConfiguration <Customer>扩展并重复主键配置,那么它工作正常,但我失去了共享公共配置的能力(DRY主体是动机)。

  • 我在这里做错了吗?
  • 是否有另一种方法可以在实体之间共享通用配置?

这里参考其他课程:

public interface IEntity {

    int Id { get; set; }

}

public class Customer : IEntity {

    public virtual int Id { get; set; }

    public virtual string name { get; set; }

}

谢谢!


8772
2018-04-08 11:58


起源



答案:


我认为你不需要经历所有这些。 EF 4.1 Code First使用了很多约定优于配置,通过这种方式,实体的Id属性被配置为主键。因此,通过在您的实体上实现IEntity接口,您将使用Id作为主键来设置它们。

以下是ADO.NET团队博客的链接,该博客解释了主键约定的工作原理 - Code First的约定


2
2018-04-08 12:12



是的,这是事实,但我个人不喜欢依赖约定,在可能的情况下,我希望配置显式,自我记录和版本控制。迟早的某些事情可能不符合惯例,所以这些问题应该可以预先解决。此简化示例中还没有显示一些共享配置,我不确定约定会自动处理。 - Jamie
“我不喜欢依赖约定” - 然后编写测试,当约定改变时它将失败,记录事实(代码或其他方面)是一种不太理想的方法 - RhysC


答案:


我认为你不需要经历所有这些。 EF 4.1 Code First使用了很多约定优于配置,通过这种方式,实体的Id属性被配置为主键。因此,通过在您的实体上实现IEntity接口,您将使用Id作为主键来设置它们。

以下是ADO.NET团队博客的链接,该博客解释了主键约定的工作原理 - Code First的约定


2
2018-04-08 12:12



是的,这是事实,但我个人不喜欢依赖约定,在可能的情况下,我希望配置显式,自我记录和版本控制。迟早的某些事情可能不符合惯例,所以这些问题应该可以预先解决。此简化示例中还没有显示一些共享配置,我不确定约定会自动处理。 - Jamie
“我不喜欢依赖约定” - 然后编写测试,当约定改变时它将失败,记录事实(代码或其他方面)是一种不太理想的方法 - RhysC


看起来这些配置有一些接口问题。如果你改变它是有效的 IEntity 至 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()
    {
        ...
    }
}

12
2018-04-10 21:52



好吧,我尝试将接口转换为抽象类,但它仍然不起作用。然后我使基类非抽象,它仍然不起作用!我现在开始重复配置,直到(有一天?)Entity Framework团队支持软件使用代码优先的接口(我认为这是我自己的核心要求)。 - Jamie
它对我有一个基类,所以必须有另一个问题。 - Ladislav Mrnka
虽然这对我有用,但我宁愿使用界面。希望EF将来会支持这一点。 - jrummell
@LadislavMrnka:+1在尝试申请时,我在VS2010 EF4.4上遇到了类似的错误信息 RowVersion 通过通用接口配置。我一改变了 IEntity 至 EntityBase 有效。它以两种方式工作;使用普通类作为基类的地方 RowVersion 简单地继承或使用覆盖的抽象类 RowVersion。可惜接口方法不起作用。 - Nope


您可以在类上创建静态方法并将实体传递给它。例如:

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

1
2018-03-21 21:49



不是一个糟糕的解决方法。 - David


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

而且,幸运的是,找到了解决方案:

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

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


0
2017-12-04 09:54