Нет ли способа сделать это таким
таким образом, что фильтрация на
дочерний стол может быть включен в
первый запрос linq, так что нет новых
классы должны быть объявлены?
Технически, ответ - нет. Если вы пытаетесь вернуть больше данных, чем может вместить один объект сущности (Verse, VerseTranslation), вам потребуется какой-то объект для «проецирования». Однако вы можете обойтись без явного объявления myType
, используя анонимный тип:
var res = from v in dc.Verses
select new
{
Verse = v,
Translations = (from trans in v.VerseTranslations
where languageId==trans.LanguageId
select trans).ToList()
};
var first = res.First();
Console.WriteLine("Verse {0} has {1} translation(s) in language {2}.",
first.Verse.VerseId, first.Translations.Count, languageId);
Компилятор сгенерирует класс с соответствующими типами свойств Verse и Translations для вас. Вы можете использовать эти объекты практически для чего угодно, если вам не нужно ссылаться на тип по имени (например, для возврата из именованного метода). Поэтому, хотя вы технически не «объявляете» тип, вы все равно используете новый тип, который будет сгенерирован в соответствии с вашей спецификацией.
Что касается использования одного запроса LINQ, все зависит от того, как вы хотите структурировать данные. Мне кажется, ваш исходный запрос имеет больше смысла: соедините каждый Verse
с отфильтрованным списком переводов. Если вы ожидаете только один перевод для каждого языка, вы можете использовать SingleOrDefault
(или FirstOrDefault
), чтобы сгладить свой подзапрос, или просто использовать SelectMany
, например:
var res= from v in dc.Verses
from t in v.VerseTranslations.DefaultIfEmpty()
where t == null || languageId == t.LanguageId
select new { Verse = v, Translation = t };
Если в стихе есть несколько переводов, будет возвращаться «строка» для каждой пары «Стих / Перевод». Я использую DefaultIfEmpty()
в качестве левого соединения, чтобы убедиться, что мы получим все стихи, даже если они пропустили перевод.