Как согласовать объединения и группировки на основе вложенных свойств в LINQ? - PullRequest
0 голосов
/ 06 сентября 2018

Итак, у меня есть такая вложенная структура данных:

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

У меня также есть класс для сопоставления пар раздела / подсекции более дружественным к EF способом (IRL - это перечисление со значениями атрибута и помощник, но этот класс абстрагирует некоторую работу, не необходимую для воспроизведения проблемы ):

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

И ContractTerm, и TermItem имеют свои собственные коллекции в DbContext, и я пытаюсь получить коллекцию всех текстовых записей, назначенных определенным Section с для данного ContractId. У меня есть следующий класс, чтобы содержать его:

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

Я хочу выбрать коллекцию 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 и / или 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 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, который сделал бы то же самое.

1 Ответ

0 голосов
/ 06 сентября 2018

Я изменил свой ответ, ну, я бы сделал что-то вроде этого ... может быть, это может помочь вам.

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();  
        }
...