EF POCO表拆分:两个实体都加载

时间:2013-05-20 12:49:09

标签: .net entity-framework poco

很抱歉,但我因桌子拆分而感到困惑!

我有Product和ProductDetail实体,映射到表Product。

当我加载Products集合时,也会加载ProductDetails。

有人可能会解释为什么我可以阻止ProductDetails加载直到我真的想要它们?谢谢!

        using (var ctx = new Context(cs))
        {
            var pc = ctx.Products.Local.Count();
            var pdc = ctx.ProductDetails.Local.Count();
            Assert.IsTrue(pc == 0);
            Assert.IsTrue(pdc == 0);

            ctx.Products.Load();

            pc = ctx.Products.Local.Count();
            pdc = ctx.ProductDetails.Local.Count();
            Assert.IsTrue(pc >= 10); //OK so far
            Assert.IsTrue(pdc == 0); //no, they are all there

        }

我的上下文类和实体:

public class Context:DbContext
{
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
    }

    public Context():base()
    {            
    }

    public Context(string nameOrConnectionString) : base(nameOrConnectionString)
    {

    }

    public DbSet<Product> Products { get; set; }
    public DbSet<ProductDetail> ProductDetails { get; set; }

}

[Table("Product")]
public class Product
{
    [Key]
    public virtual int ProductId { get; set; }
    public virtual string Name { get; set; }
}

[Table("Product")]    
public class ProductDetail:Product
{
    //[Key]
    //public virtual int ProductId { get; set; }
    //public virtual string Name { get; set; }
    public virtual string Description { get; set; }
}

1 个答案:

答案 0 :(得分:1)

发生这种情况的原因是因为ProductDetail继承自Product,从技术上讲,这是Table-per-Hierarchy mapping而不是简单的表格拆分。这意味着,无论何时加载所有Products,您都必须加载所有ProductDetails。 EF知道如何区分这两者,因此在加载每个实体时,框架会将其分类到您的上下文中的正确DbSet - 它们都被添加到Products集中,但也有一些也被添加到ProductDetails设置。

幸运的是,解决方案非常简单:只需将ProductDetail设为一个单独的类,而不是从Product派生。然后你会得到你正在寻找的表:

[Table("Product")]
public class Product
{
  [Key]
  public int ProductId { get; set; }

  public string Name { get; set; }
  public virtual ProductDetail Details { get; set; }
}

[Table("Product")]
public class ProductDetail
{
  [Key]
  public int ProductId { get; set; }

  public string Description { get; set; }
}

您还需要使用Fluent API在您的上下文中设置关系:

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

  modelBuilder.Entity<Product>()
              .HasRequired(p => p.Details)
              .WithRequiredPrincipal();
}

然后您只需加载Product并使用myProduct.Details.Description访问说明(您可能不需要手动访问ctx.ProductDetails,如果有的话,使用此设置)

请注意,您必须启用延迟加载,或者在ctx.Products.Include(p => p.Details)所需的所有查询中明确包含详细信息,以使其正常工作。

希望这有帮助!不同类型的表映射之间的区别有时可能非常微妙。