实体框架+多级继承+ EF代码优先

时间:2011-07-27 15:52:45

标签: inheritance entity-framework-4.1 ef-code-first

我正在尝试使用Code First设置TPC继承。我有一个三级层次结构。 抽象类A,具体类B继承自A,类C继承自B. A类属性:ID,CreatedBy和CreatedOn。 B类属性:FirstName,LastName,BirthDate C类属性:约会日期,状态

我希望在数据库中使用数据库生成的标识创建类B和类C的表。

我的上下文类中有以下代码:

public DbSet<B> BList { get; set; }
public DbSet<C> CList { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<B>().ToTable("BClass");
        modelBuilder.Entity<C>().ToTable("CClass");
    }

我有一个contextinitializer类,它覆盖Seed方法来填充数据库中的一些测试数据。

protected override void Seed(TestContext context)
    {
        TestDataClass testData = new TestDataClass();

        List<B> bList= testData.GetBList();

        foreach (B objB in bList)
        {
            context.BList.Add(objB);
        }

        List<C> cList = testData.GetCList();
        foreach (C objC in cList)
        {
            context.CList.Add(objC);
        }

        context.SaveChanges();
    }

这会在数据库中创建表BClass和CClass,但问题是如果Iam在BClass中插入10行并且在CClass中插入相应的10行,则实体框架在BClass中插入20行,其中10行包含实际值,10行包含Null 。 CClass给出了10行的预期结果。 第二个问题是当我从CClass查询数据时,我没有得到结果。我的错误信息说:

  

EntitySet'CClass'未在EntityContainer中定义   '的TestContext'。近简单标识符,第1行,第12列。

我正在使用来自http://huyrua.wordpress.com/2011/04/13/entity-framework-4-poco-repository-and-specification-pattern-upgraded-to-ef-4-1/的Huy Nguyen的实体框架4 POCO,存储库和规范模式[升级到EF 4.1]的帖子中的代码,我在通用存储库中的代码看起来像

public IList<TEntity> FindAll<TEntity>() where TEntity : class
    {
        DbContext.Set<TEntity>();
        var entityName = GetEntityName<TEntity>();
        return ((IObjectContextAdapter)DbContext).ObjectContext.CreateQuery<TEntity>(entityName).ToList<TEntity>();
    }

        private string GetEntityName<TEntity>() where TEntity : class
    {
        DbContext.Set<TEntity>();
        return string.Format("{0}.{1}", ((IObjectContextAdapter)DbContext).ObjectContext.DefaultContainerName, _pluralizer.Pluralize(typeof(TEntity).Name));
    }

我尝试更改我的表映射但它没有帮助。我不知道我在这里缺少什么,不知道该怎么做。我迫切需要帮助。

提前致谢。


这是我的实际课程的样子:

public abstract class EntityBase
{
    [DatabaseGenerated(System.ComponentModel.DataAnnotations.DatabaseGeneratedOption.Identity)]
    public virtual long Id { get; set; }
    public virtual string CreatedBy { get; set; }
    public virtual DateTime? CreatedOn { get; set; }
    public virtual string LastModifiedBy { get; set; }
    public virtual DateTime? LastModifiedOn { get; set; }

}


public class Person: EntityBase
{
    public virtual string FirstName { get; set; }
public virtual string MiddleName { get; set; }
    public virtual string LastName { get; set; }
    public virtual DateTime? BirthDate { get; set; }


    [NotMapped]
    public virtual string FullName
    {
        get
        {
            return String.Format("{0}, {1} {2}", LastName, FirstName, MiddleName);
        }
    }
}

public partial class Employee : Person
{
[Required]
    public string EmployeeNumber { get; set; }
[Required]
public string department { get; set; }

    public  DateTime? JoiningDate { get; set; }
    public  DateTime? PromotionDate { get; set; }
 }

我的上下文类现在有:

public DbSet<EntityBase> People { get; set; }

protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Person>().ToTable("Person");
        modelBuilder.Entity<Employee>().Map(m => m.MapInheritedProperties()).ToTable("Employee"); 
}

1 个答案:

答案 0 :(得分:7)

您的映射指定TPT而不是TPC。你必须使用:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    modelBuilder.Entity<B>().ToTable("BClass"); 
    modelBuilder.Entity<C>().Map(m => m.MapInheritedProperties()).ToTable("CClass");
}
  

我想要在数据库中创建B类和C类的表   与数据库生成的身份。

EF不会为你做这件事。这将需要对生成的代码进行自定义修改,因为一旦使用继承实体,在整个继承层次结构中的所有实例中必须具有唯一的Id = id在B和C表之间必须是唯一的。这可以通过为种子0指定标识,为B和种子1指定递增2,为C指定递增2,但每次添加新的子实体类型时都必须修改它。

您的存储库非常糟糕。当您使用DbContext时,为什么要转换回ObjectContext?阅读有关使用和查询DbContext的内容,并在没有存储库的情况下启动。 ObjectContext API也不允许在查询中使用派生类型。您必须查询顶级映射实体类型,并使用OfType扩展方法仅获取派生类型。

var cs = objectContext.CreateSet<B>().OfType<C>().ToList();

另一个通用方法不起作用的例子。

修改

对不起,我知道问题出在哪里。我在描述中禁食,我跳过了解决方案的一个重要细节。我没有映射A(EntityBase),因为它不需要。它被标记为抽象实体,因此不需要为TPC继承中始终为空的单独表。这也是我的B(Person)在其映射中不调用MapInheritedProperties的原因,因为我把它作为映射继承的根。因此,为我的示例定义的DbSet必须定义为:

public DbSet<Person> People { get; set; }

如果您想定义DbSet<EntityBase>,则必须采用与Person相同的方式映射Employee

modelBuilder.Entity<Person>().Map(m => m.MapInheritedProperties()).ToTable("Person"); 

您当前的映射将EntityBasePerson定义为TPT继承的一部分,Employee作为TPC继承,但EF不喜欢组合继承类型。