C# 如何在 LINQ 的表达式树中创建连接?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/485398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 05:16:21  来源:igfitidea点击:

How to create a join in an expression tree for LINQ?

c#.netlinqlinq-to-sqljoin

提问by mattruma

I have a Task object that has a collection of Label objects ... in the database the tables are called Task and Label.

我有一个 Task 对象,它有一个 Label 对象的集合……在数据库中,这些表被称为 Task 和 Label。

There are a variety of ways to search for a Task, so using LINQ, I construct my LINQ query in an expression tree ... similar to the below code sample:

有多种方法可以搜索任务,因此使用 LINQ,我在表达式树中构建了我的 LINQ 查询……类似于以下代码示例:

IQueryable<Data.Task> query = ctx.DataContext.Tasks;    

if (criteria.Number > 0)    
    query = query.Where(row => row.Number == criteria.Number);  

if (criteria.CustomerId != Guid.Empty)
    query = query.Where(row => row.Project.CustomerId == criteria.CustomerId);

if (criteria.ProjectId != Guid.Empty)
    query = query.Where(row => row.ProjectId == criteria.ProjectId);

var data = query.Select(row => TaskInfo.FetchTaskInfo(row));

this.AddRange(data); 

This works great ... but now I would like to search for Tasks with a specific Label, for example, accounting or feature-request.

这很好用……但现在我想搜索具有特定标签的任务,例如会计或功能请求。

I am able to do this in LINQPad from a complete query:

我可以通过一个完整的查询在 LINQPad 中做到这一点:

from t in Tasks
join l in Labels on t.TaskId equals l.SourceId 
where l.Name == "accounting"
select t

Is there anyway to do this using an expression tree? I'm stuck! Any help would be greatly appreciated!

有没有办法使用表达式树来做到这一点?我被卡住了!任何帮助将不胜感激!

采纳答案by David Morton

I believe this should do it:

我相信这应该这样做:

Tasks.Join(Labels.Where(l => l.Name == "accounting"), t => t.TaskId, l => l.SourceId, (t, l) => t)

回答by Jon Skeet

A "join" (not a "join ... into") clause in a query expression translates into a Join call. The tricky bit is transparent identifiers - only one sequence comes out of the join, and it's got to have both tand lin it (in your example) so the compiler does some magic.

查询表达式中的“join”(不是“join ... into”)子句转换为 Join 调用。棘手的一点是透明标识符 - 只有一个序列从连接中出来,并且它必须同时包含tl(在您的示例中),因此编译器会做一些魔术。

I don't have much time to go into the details here, but it's probably best to just show you how your query expression is translated.

我没有太多时间在这里详细介绍,但最好只向您展示您的查询表达式是如何翻译的。

This:

这个:

from t in Tasks
join l in Labels on t.TaskId equals l.SourceId 
where l.Name == "accounting"
select t

Is translated into:

翻译成:

Tasks.Join(Labels, t => t.TaskId, l => l.SourceId, (t, l) => new { t, l })
     .Where(z => z.l.Name == "accounting")
     .Select(z => z.t)

Note the introduction of "z" here - basically that contains both t and l from the original expression.

请注意此处引入的“z”——基本上包含原始表达式中的 t 和 l。

EDIT: David Morton's answer gives a more efficient way of doing it. His line is equivalent to:

编辑:大卫莫顿的回答提供了一种更有效的方法。他的台词相当于:

from t in Tasks
join l in (from x in Labels where x.Name == "accounting") 
       on t.TaskId equals l.SourceId 
select t

If you only have a select clause after the join, the compiler is able to skip the transparent identifier and put the projection directly as the last parameter to the Join call.

如果 join 后只有一个 select 子句,编译器可以跳过透明标识符并将投影直接作为 Join 调用的最后一个参数。

回答by John Boker

If you click the little lambda button in LINQPad it will show you the expression tree that you're trying to create, it's in the list of three buttons above the results box and below the expression box.

如果您单击 LINQPad 中的小 lambda 按钮,它将显示您尝试创建的表达式树,它位于结果框上方和表达式框下方的三个按钮列表中。