如何根据 LINQ 中的嵌套属性协商连接和分组?

How do I negotiate joins and groupings based on nested properties in LINQ?

所以我有一个这样的嵌套数据结构:

public class ContractTerm
{
    public int ContractId { get; set; }
    public string SectionId { get; set; }
    public string SubsectionId { get; set; }
    public string TermId { get; set; }
    public int TermOrder { get; set; }
    public TermItem TermNavigation { get; set; }
}

public class TermItem
{
    public string SectionId { get; set; }
    public string SubsectionId { get; set; }
    public string TermId { get; set; }
    public string Text { get; set; }
    public ICollection<ContractTerm> ContractNavigation { get; set; }
}

我还有一个 class 以更加 EF 友好的方式映射 section/subsection 配对(IRL 这是一个具有属性值和助手的枚举,但是这个 class 抽象出一些不需要重现问题的工作):

public class Section
{
    public string Name { get; set; }
    public string SectionId { get; set; }
    public string SubsectionId { get; set; }
}

ContractTermTermItem 在 DbContext 中都有自己的集合,我正在尝试获取分配给给定特定 Section 的所有文本条目的集合ContractId。我有以下 class 来包含它:

public class TextsBySection
{
    public string SectionName { get; set; }
    public IEnumerable<string> Texts { get; set; }
}

我想要 select 一个 TextsBySection 的集合,并且有这样的东西:

public class ContractManager
{
    //insert constructor initializing MyContext here

    private MyContext Context { get; }

    public IEnumerable<MyOutputClass> GetTerms(int contractId, IEnumerable<Section> sections)
    {
        Func<string, string, IEnumerable<string>> getBySection =
            (section, subsection) => context.ContractTerms.Include(x => x.TermNavigation)
                                            .Where(x => x.ContractId == contractId
                                                        && x.SectionId == section
                                                        && x.SubsectionId == subsection)
                                            .Select(x => x.TermNavigation.Text);

        var result = sections.Select(x => new MyOutputClass
                              {
                                  SectionName = x.Name,
                                  Texts = getBySection(x.SectionId, x.SubsectionId)
                              }).ToList();

        return result;
    }
}

这很好用,但 它会为每个 Section 访问数据库。 我觉得必须有一种方法可以使用 Join and/or GroupBy 让它只查询一次,但我不太明白。可能是这样的:

var result = context.ContractTerms.Include(x => x.TermNavigation)
                                  .Where(x => x.ContractId == contractId)
                                  .Join(sections,
                                        term => //something
                                        section => //something
                                        (term, section) => /*something*/)

如果所有这些都在 SQL 中,select 获取必要的数据将很容易:

SELECT sections.name,
       term_items.text
FROM   contract_terms
JOIN   term_items
ON     term_items.section_id = contract_terms.section_id
AND    term_items.subsection_id = contract_terms.subsection_id
AND    term_items.term_id = contract_terms.term_id
JOIN   sections --not a real table; just corresponds to sections argument in method
ON     sections.section_id = contract_terms.section_id
AND    sections.subsection_id = contract_terms.subsection_id

...然后我可以在 .NET 中对结果进行分组。但是我不明白如何创建一个可以做同样事情的 LINQ 查询。

我改变了我的答案,好吧,我会做这样的事情......也许这可能对你有帮助。

public static void Main(string[] args)
        {
            List<Section> sections = new List<Section>();
            List<ContractTerm> contractTerms = new List<ContractTerm>();
            List<TermItem> termItens = new List<TermItem>();

            //considering lists have records

            List<TextsBySection> result = (from contractTerm in contractTerms
                          join termItem in termItens
                              on new
                              {
                                  contractTerm.SectionId,
                                  contractTerm.SubsectionId,
                                  contractTerm.TermId
                              }
                              equals new
                              {
                                  termItem.SectionId,
                                  termItem.SubsectionId,
                                  termItem.TermId
                              }
                          join section in sections
                           on new
                           {
                               contractTerm.SectionId,
                               contractTerm.SubsectionId
                           } equals new
                           {
                               section.SectionId,
                               section.SubsectionId
                           }
                          select
                          new
                          {
                              sectionName = section.Name,
                              termItemText = termItem.Text
                          }).GroupBy(x => x.sectionName).Select(x => new TextsBySection()
                          {
                              SectionName = x.Key,
                              Texts = x.Select(i=> i.termItemText)
                          }).ToList();  
        }