C# 代码首先加载嵌套而不递归

C# 代码首先加载嵌套而不递归,c#,.net,ef-code-first,entity-framework-5,code-first,C#,.net,Ef Code First,Entity Framework 5,Code First,我有一张可以包含许多部分的表格。每个部分也可以包含许多部分。我希望以尽可能少的往返数据库的方式加载工作表、其部分和所有子部分。实际上,我认为这通常是1-2层的深度,但可能会达到16层。代码如下: using System; using System.Collections.Generic; using System.Linq; using System.ComponentModel.DataAnnotations.Schema; using System.Data.Entity; public

我有一张可以包含许多部分的表格。每个部分也可以包含许多部分。我希望以尽可能少的往返数据库的方式加载工作表、其部分和所有子部分。实际上,我认为这通常是1-2层的深度,但可能会达到16层。代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data.Entity;

public class Sheet {
    public long Id { get; set; }
    // more fields
    public virtual IList<Section> Sections { get; set; }
}

public class Section {
    public long Id { get; set; }

    public long SheetId { get; set; }
    [ForeignKey("SheetId")]
    public virtual Sheet Sheet { get; set; }

    public long? ParentId { get; set; }
    [ForeignKey("ParentId")]
    public virtual Section Parent { get; set; }

    public virtual IList<Section> Sections { get; set; }
    // more fields
}

public class MyDbContext : DbContext {
    public DbSet<Sheet> Sheets { get; set; }
    public DbSet<Section> Sections { get; set; }
    public Sheet GetSheetConfiguration(long id) {
        Configuration.LazyLoadingEnabled = false;
        Sheet rtn;
        rtn = Sheets.Find(id);
        (Sections.Where(sect => sect.SheetId == id)).ToList();
        return rtn;
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.ComponentModel.DataAnnotations.Schema;
使用System.Data.Entity;
公开课程表{
公共长Id{get;set;}
//更多领域
公共虚拟IList节{get;set;}
}
公共课组{
公共长Id{get;set;}
公共长SheetId{get;set;}
[外键(“SheetId”)]
公共虚拟图纸{get;set;}
公共长?父ID{get;set;}
[ForeignKey(“ParentId”)]
公共虚拟节父项{get;set;}
公共虚拟IList节{get;set;}
//更多领域
}
公共类MyDbContext:DbContext{
公共DbSet表{get;set;}
公共DbSet节{get;set;}
公共图纸GetSheetConfiguration(长id){
Configuration.LazyLoadingEnabled=false;
薄板rtn;
rtn=工作表。查找(id);
(Sections.Where(sect=>sect.SheetId==id)).ToList();
返回rtn;
}
}
这将创建所需的表结构: 工作表:Id(主键)。。。 部分:Id(主键)、SheetId(非空)、ParentId(空)

GetSheetConfiguration方法加载与该工作表相关的所有部分,并让EF对其进行排序。除了所有部分也在Sheet.Sections中之外,它可以获得正确的关系。(我想为每个部分设置SheetId,以避免递归查询。)如何告诉EF在工作表级别仅使用ParentId=null的部分?
-列表项

您无法避免
Sheet.Sections
集合中会充满所有节,因为这就是
Sheet.Sections
Section.Sheet
之间的关系所描述的:它应该包含所有节,而不仅仅是
ParentId==null
的“根节”。实体框架基于关系修复填充此集合,您不能禁用或配置此行为

解决此问题的一个选项是引入一个额外的集合属性,该属性从
Sheet.Sections
导航属性中读取过滤后的数据,并且不映射到数据库以检索根节列表,如下所示:

public class Sheet {
    public long Id { get; set; }
    // more fields
    public virtual IList<Section> Sections { get; set; }

    public IEnumerable<Section> RootSections
    {
        get { return Sections.Where(sect => sect.ParentId == null); }
    }
}
。。。您可以使用:

Sections.Where(sect => sect.SheetId == id).Load();

Load
是一个
void
方法,它只将请求的实体加载到上下文中。它节省了创建不必要的
列表
集合的开销。

您无法避免
工作表.Sections
集合被所有节填满,因为这就是
工作表.Sections
工作表.Sheet
之间的关系所描述的:它应该有所有的节,不仅是ParentId==null的“根节”。实体框架基于关系修复填充此集合,您不能禁用或配置此行为

解决此问题的一个选项是引入一个额外的集合属性,该属性从
Sheet.Sections
导航属性中读取过滤后的数据,并且不映射到数据库以检索根节列表,如下所示:

public class Sheet {
    public long Id { get; set; }
    // more fields
    public virtual IList<Section> Sections { get; set; }

    public IEnumerable<Section> RootSections
    {
        get { return Sections.Where(sect => sect.ParentId == null); }
    }
}
。。。您可以使用:

Sections.Where(sect => sect.SheetId == id).Load();

Load
是一个
void
方法,它只将请求的实体加载到上下文中。它节省了创建不必要的
列表
集合的开销。

您为
GetSheetConfiguration
发布的代码是否正确?我不明白这行
(Sections.Where…
的目的是加载该表的所有部分,然后让EF进行排序。正如@Slauma所建议的,应该更清楚地说
Sections.Where(sect=>sect.SheetId==id.Load()
您为
GetSheetConfiguration
发布的代码是否正确?我不明白这行
(Sections.Where…
的目的是加载该表的所有部分,然后让EF进行排序。正如@Slauma所建议的,应该更清楚地说
Sections.Where(sect=>sect.SheetId==id.Load()