如何在Linq中筛选子集合
我需要使用单个linq查询过滤linq中实体的子元素。这可能吗 假设我有两个相关的表。诗和诗的翻译。LINQ to SQL创建的实体是这样的,我有一个Verse对象,其中包含一个子对象,该子对象是VerseTranslation的集合 现在,如果我有以下linq查询如何在Linq中筛选子集合,linq,lambda,filtering,inner-join,Linq,Lambda,Filtering,Inner Join,我需要使用单个linq查询过滤linq中实体的子元素。这可能吗 假设我有两个相关的表。诗和诗的翻译。LINQ to SQL创建的实体是这样的,我有一个Verse对象,其中包含一个子对象,该子对象是VerseTranslation的集合 现在,如果我有以下linq查询 var res = from v in dc.Verses where v.id = 1 select v; 我得到一组id为1的诗句,每个诗句对象都包含来自
var res = from v in dc.Verses
where v.id = 1
select v;
我得到一组id为1的诗句,每个诗句对象都包含来自诗句翻译的所有子对象
我还想做的是过滤诗歌翻译的子列表
到目前为止,我唯一能想到的方法是使用一种新的匿名类型或其他类型。如下
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如果这是来自数据库,则可以运行第一条语句 然后用Where子句加载或包含一组VerseTranslations 在你的模型中,韵文和韵文翻译之间有关系吗。在这种情况下,这可能会起作用:
var res= from v in
dc.Verses.Include("VerseTranslations").Where(o => languageId==o.LanguageId)
select v;
筛选对象的封闭集合
var res = dc.Verses
.Update(v => v.VerseTranslations
= v.VerseTranslations
.Where(n => n.LanguageId == languageId));
通过使用来自的扩展方法“Update”
公共静态类更新扩展{
公共委托无效函数(TArg0元素);
///
///对IEnumerable序列中的所有元素执行Update语句块。
///
///源元素类型。
///源序列。
///要为每个元素执行的update语句。
///受影响的记录数。
公共静态int更新(此IEnumerable源,Func更新){
如果(source==null)抛出新的ArgumentNullException(“source”);
如果(update==null)抛出新的ArgumentNullException(“update”);
if(typeof(TSource).IsValueType)
抛出新的NotSupportedException(“更新不支持值类型元素”);
整数计数=0;
foreach(源中的TSource元素){
更新(要素);
计数++;
}
返回计数;
}
}
在这种情况下,难道没有办法做到这一点吗
方式,以便在
子表可以合并到
第一个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查询而言,这完全取决于您希望数据的结构。在我看来,您最初的查询似乎最有意义:将每个韵文与经过筛选的翻译列表配对。如果您希望每种语言只进行一次翻译,则可以使用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()
作为左连接,以确保即使缺少翻译,我们也能得到所有的诗句。因此,多亏设拉子给出的指针,我终于让它起作用了
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;
DataLoadOptions=newdataloadoptions();
options.AssociateWith(item=>item.versetransation.Where(t=>languageId.Contains(t.languageId));
dc.LoadOptions=选项;
var res=从s到dc.Verse
选择s;
这不需要投影或使用新的扩展类
感谢您的所有输入人员。根据我从链接中了解的情况,顺便说一句,在其示例中,该链接获取单个对象,然后对其进行加载。在我的例子中,我有一个res中的集合,但我仍然无法使它适应我的场景。可能是睡眠不足:/ok..愚蠢的问题…但我找不到包含方法!!是的,它来自一个数据库,这两个表之间有关系。所以dc是数据上下文,Verses是表。但是我不能得到包含函数。包含是实体框架,请看一下这个linq到sql等价物谢谢,它使用DataLoadOptions工作,但我必须使用AssociateWith函数,而不是链接中提到的LoadWith。真的没有内置机制吗?你有一个危险的“=”在您的答案中,它应该在哪里“==”。
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;