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

发生这种情况的原因是ProductDetail继承了Product,这在技术上使其成为按层次表的映射,而不是简单的表分割。这意味着,当你装载所有的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)的所有查询中包含详细信息,以便使其工作。

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

最新更新