EF表与多对多的关系,这会消耗内存吗?

时间:2014-07-03 09:16:22

标签: c# linq entity-framework many-to-many

我有两个保存家庭成员的表,当我使用include来检索家庭成员时,生成的T-SQL就是我所期望的,但是当我看到来自VS的结果时,如下图所示,它看起来永无止境。

我的问题:

  1. 这是正常的吗?
  2. 当关系变得复杂时,我应该避免include吗?
  3. 如果这是正常的,这会非常消耗内存吗?
  4. POCO

    public  class Cust_ProfileTbl
    {
        [Key]
        public long bintAccountNo { get; set; } 
        public string nvarCardName { get; set; }
        public string varEmail { get; set; }
    
    
        public virtual ICollection<Cust_ProfileFamilyTbl> profileFamilyParents { get; set; }
        public virtual ICollection<Cust_ProfileFamilyTbl> profileFamilyChildren { get; set; }
    }
    
    public class Cust_ProfileFamilyTbl
    {
        [Key]
        public int intProfileFamily { get; set; } 
        public long bintAccountNo { get; set; }
        public long bintAccountNoMember { get; set; }
    
        public virtual Cust_ProfileTbl custProfileParent { get; set; }
        public virtual Cust_ProfileTbl custProfileChild { get; set; }
    }
    

    LINQ

    var rs = from family in context.member.Include("profileFamilyParents.custProfileChild")
             select family;
    
    rs = rs.Where(x => x.bintAccountNo.Equals(1));
    
    var result = rs.ToList();
    

    on onModelCreating

    modelBuilder.Entity<Cust_ProfileFamilyTbl>()
           .HasRequired(m => m.custProfileParent)
           .WithMany(t => t.profileFamilyParents)
           .HasForeignKey(m => m.bintAccountNo)
           .WillCascadeOnDelete(false);
    
    modelBuilder.Entity<Cust_ProfileFamilyTbl>()
                .HasRequired(m => m.custProfileChild)
                .WithMany(t => t.profileFamilyChildren)
                .HasForeignKey(m => m.bintAccountNoMember)
                .WillCascadeOnDelete(false);
    

    Result when mouse hover

2 个答案:

答案 0 :(得分:2)

当人们在他们的应用程序中使用像EF这样的ORM时,很多时候应用程序设计都是由这个ORM和其模型中定义的实体驱动的。当应用程序是一个简单的&#34; CRUD&#34;应用,这不是问题,而是优势,因为你节省了很多时间。

然而,当事情开始变得更复杂时,一个&#34; ORM引导设计&#34;成为一个问题。看起来就是这样。

至少有两个问题,从评论中找到:

  1. 从数据库中检索的数据超出了需要
  2. 在这种情况下,由于实体之间的某些特定关系,有一个循环引用,当试图在视图中显示模型时,它会创建无限循环和堆栈溢出
  3. 当出现这种情况时,最明智的做法是打破ORM与应用程序其余部分之间的紧密联系,这可以通过定义新类并将数据投影到其中来实现。让我们给出一个通用的ProfileDto名称。

    public class ProfileDto { ... }
    

    DTO是这类类的通用名称:数据传输对象 - 但是,当它们具有特定用途时,它们可以获得其他名称,例如视图模型,当它们将被用作模型发送到MVC视图

    然后,您需要做的是将查询结果投影到DTO中:

    var model = theQuery.Select(i => new ProfileDto { a = i.a, b = i.b...}).ToList();
    

    通过Dto的良好设计,您只能从数据库中恢复所需的数据,并且您将避免循环问题(通过不包括创建循环的导航属性)。

    注意:很多时候人们使用映射器(例如AutoMapperValueInjecter来自动生成映射或映射的一部分

    代码标准化是一个非常好的想法,直到它成为问题的根源。编写代码的主要目的是实现业务逻辑。如果代码标准化,技术或其他任何东西使得实现业务逻辑变得更加困难,而不是为解决方案做出贡献,那么它们就成了一个问题,所以你需要避免它们。

答案 1 :(得分:1)

  1. 您创建的映射是正常,但使用Include取决于其用法

  2. 使用Include取决于使用情况,例如,如果您想将其缓存在内存中,那么您可以使用include,其中您好像只使用显示Cust_ProfileTbl的属性 某些网格中的类,如果您想要显示Cust_ProfileFamilyTbl的详细信息,那么您可能不想使用include。但是如果您使用的是Automapper,请小心,因为当它尝试映射相关属性时,它将查询数据库。

  3. 当您执行ToList()时会消耗内存,因为您正在将查询结果加载到List集合中。如果您再次想要查询结果,那么您可以使用ToQueryable()或只是想迭代,您可以不将它们加载到List。