方法语法(= 带有 lambda 表达式的语法)比查询语法具有更多功能。因此,我更喜欢在查询语法之上使用方法语法。
但是有一个例外:当连接三个或更多表时,方法语法看起来很可怕,就像 Sebu 在他的回答中显示的那样。也显示在this answer where the two methods for joining three tables are compared
IQueryable 内部的 Expression 是一样的,不管你是使用方法语法还是查询语法,所以生成的 SQL 语句不会有太大差异。
因此我的建议是:尽可能使用方法语法,但为了可读性、错误更少、可维护性更好:使用查询语法连接三个表。
如果您必须经常连接三个表,请考虑创建一个隐藏连接完成方式的扩展函数:
见:extension functions demystified
以下函数采用三个输入序列:IQueryable、IQueryable 和 IQueryable。
它连接使用 T1Join1Selector 和 T2Join1Selector 提取的键的前两个序列,
如果在使用 T2Join2Selector 和 T3Join2Selector
提取的键上连接后两个序列
从每个匹配的 T1 / T2 / T3 它根据 resultSelector 创建一个结果
public static IQueryable<TResult> Join<T1, T2, T3,
TKeyJoin1, TKeyJoin2, TResult>(
this IQueryable<T1> table1,
IQueryable<T2> table2,
IQueryable<T3> table3,
Expression<Func<T1, TKeyJoin1>> table1Join1KeySelector,
Expression<Func<T2, TKeyJoin1>> table2Join1KeySelector,
Expression<Func<T2, TKeyJoin2>> table2Join2KeySelector,
Expression<Func<T3, TKeyJoin2>> table3Join2KeySelector,
Expression<Func<T1, T2, T3, Tresult>> resultSelector)
{
return Tabl1.Join(table2, // join table1 and table2
t1 => table1Join1KeySelector(t1), // select the key from table1 for the first join
t2 => table2Join1KeySelector(t2), // select the key from table2 for the first join
(t1, t2) => new // remember the matching records as T1 and T2
{
T1 = t1,
T2 = t2,
})
// use this as input for the second join:
.Join(table3,
// use the T2 in the result of the first join as key for the second join
joinedT1andT2 => table2Join2KeySelector(joinedT1andT2.T2),
t3 => table3Join2KeySelector(t3), // select the key from table3 for the 2nd join
// and use the result of the first and second join to create a linq-result:
(joinedT1andT2, t3) => resultSelector(joinedT1andT2.T1, joinedT1andT2.T2, T3);
}
使用查询语法交替连接三个表:
public static IQueryable<TResult> Join<T1, T2, T3,
TKeyJoin1, TKeyJoin2, TResult>(
this IQueryable<T1> table1,
IQueryable<T2> table2,
IQueryable<T3> table3,
Expression<Func<T1, TKeyJoin1>> table1Join1KeySelector,
Expression<Func<T2, TKeyJoin1>> table2Join1KeySelector,
Expression<Func<T2, TKeyJoin2>> table2Join2KeySelector,
Expression<Func<T3, TKeyJoin2>> table3Join2KeySelector,
Expression<Func<T1, T2, T3, Tresult>> resultSelector)
{
return select resultSelector(table1, table2, table3)
from table1
join table2 on table1Join1KeySelector(table1) == table2Join1KeySelector(table2)
join table3 on table2Join2KeySelector(table2) == table3Join2KeySelector(table3)
}
用法类似于使用方法语法连接两个表的方式:
var result = a.Join(b, c, // join your tables a, b, c
t1 => t1.PayoutId, // first join on a.PayoutID = b.PayoutID
t2 => t2.PayoutId,
t2 => t2.UserId, // second join on b.UserID = c.UserID
t3 => t3.UserId,
(t1, t2, t3) => new // from the matching records create one new object
{
PayoutId = t1.PayoutId,
PayoutName = t2.PayoutName,
...
});
我看到您的第二次加入是在 a 和 c 上,而我的第二次加入是在 b 和 c 上。我相信你会知道如何根据需要重写代码
由于这个函数的结果是一个IQueryable,这个函数只会改变Expression。查询尚未执行。因此,您可以安全地将其与其他 IQueryable 函数混合使用:
var resultQuery = a.Where(t1 => t1.Name = ...)
.Join( /* 3-table join as described above */ )
.GroupBy(joinResult => ...)
.Take(4);
查询仍未执行,直到您执行不返回IQueryable 的操作,例如ToList / FirstOrDefault / Any / ...