如何筛选Linq中的子集
-
22-07-2019 - |
题
我需要过滤在LINQ使用单个LINQ查询实体的子元素。这可能吗?
假设我有两个相关的表。想起来就VerseTranslations。通过LINQ创建SQL实体是这样的,我有一个包含一个子对象,它是VerseTranslation集合的诗对象。
现在,如果我有后续LINQ查询
var res = from v in dc.Verses
where v.id = 1
select v;
我得到的诗篇,其ID为1,每节经文对象包含所有子从VerseTranslations对象的集合。
我也想要做的是诗的翻译过滤器子列表。
到目前为止,我已经能够想出的唯一办法是通过使用一种新型的匿名或以其他方式。如下
var res= from v in dc.Verses
select new myType
{
VerseId = v.VerseId,
VText = v.Text,
VerseTranslations = (from trans in v.VerseTranslations
where languageId==trans.LanguageId
select trans
};
在上面的代码工作,但我不得不宣布一个新的类它。难道就没有办法做这样的方式,使得在子表中的过滤可以在第一LINQ查询被合并,以便没有新的类必须声明。
此致 MAC
解决方案
所以,我终于得到它的工作多亏了西拉给出的指针。
DataLoadOptions options = new DataLoadOptions();
options.AssociateWith<Verse>(item => item.VerseTranslation.Where(t => languageId.Contains(t.LanguageId)));
dc.LoadOptions = options;
var res = from s in dc.Verse
select s;
此不需要投影或使用新的扩展类。
感谢您的所有输入的人。
其他提示
在对象的封闭集合过滤,
var res = dc.Verses
.Update(v => v.VerseTranslations
= v.VerseTranslations
.Where(n => n.LanguageId == languageId));
通过使用扩展方法 “更新” 从 HookedOnLinq
public static class UpdateExtensions {
public delegate void Func<TArg0>(TArg0 element);
/// <summary>
/// Executes an Update statement block on all elements in an IEnumerable<T> sequence.
/// </summary>
/// <typeparam name="TSource">The source element type.</typeparam>
/// <param name="source">The source sequence.</param>
/// <param name="update">The update statement to execute for each element.</param>
/// <returns>The numer of records affected.</returns>
public static int Update<TSource>(this IEnumerable<TSource> source, Func<TSource> update) {
if (source == null) throw new ArgumentNullException("source");
if (update == null) throw new ArgumentNullException("update");
if (typeof(TSource).IsValueType)
throw new NotSupportedException("value type elements are not supported by update.");
int count = 0;
foreach(TSource element in source) {
update(element);
count++;
}
return count;
}
}
如果这是从一个数据库来了,你可以运行你的第一个语句。
然后做一个负荷或与VerseTranslations包括WHERE子句。
http://msdn.microsoft.com/en-us/library /bb896249.aspx
你有没有在诗和VerseTranslations之间模型的关系。在这种情况下,这可能工作:
var res= from v in
dc.Verses.Include("VerseTranslations").Where(o => languageId==o.LanguageId)
select v;
有没有办法做到这一点在这样的 方式使得在过滤 子表可以在被合并 第一LINQ查询,以便没有新 类已被宣布?
从技术上讲,答案是否定的。如果你想比一个单一的实体对象(诗,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);
,编译器会生成具有适当类型的诗和翻译属性你的类。您可以使用这些对象的任何事情,只要你并不需要通过名称来引用类型(从一个名为方法返回,例如)。所以,当你不是技术上“声明”一类,你还在使用,这将根据您的规范来生成一个新的类型。
至于使用单个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()
作为左连接,以确保我们将得到所有诗篇即使他们缺少一个翻译。