Итак, у меня есть такая вложенная структура данных:
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, который сделал бы то же самое.