如何在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的诗句,每个诗句对象都包含来自

我需要使用单个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
                   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;