Las*_*sus 255 c# lambda linq-to-sql
假设我有一个左外连接:
from f in Foo
join b in Bar on f.Foo_Id equals b.Foo_Id into g
from result in g.DefaultIfEmpty()
select new { Foo = f, Bar = result }
Run Code Online (Sandbox Code Playgroud)
如何使用扩展方法表达相同的任务?例如
Foo.GroupJoin(Bar, f => f.Foo_Id, b => b.Foo_Id, (f,b) => ???)
.Select(???)
Run Code Online (Sandbox Code Playgroud)
Mar*_*ell 411
var qry = Foo.GroupJoin(
Bar,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(x,y) => new { Foo = x, Bars = y })
.SelectMany(
x => x.Bars.DefaultIfEmpty(),
(x,y) => new { Foo=x.Foo, Bar=y});
Run Code Online (Sandbox Code Playgroud)
Oce*_*t20 97
因为这似乎是使用方法(扩展)语法的左外连接的事实上的SO问题,我想我会添加一个替代当前选择的答案(至少在我的经验中)更常见的是我是什么后
// Option 1: Expecting either 0 or 1 matches from the "Right"
// table (Bars in this case):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bar = bs.SingleOrDefault() });
// Option 2: Expecting either 0 or more matches from the "Right" table
// (courtesy of currently selected answer):
var qry = Foos.GroupJoin(
Bars,
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f,bs) => new { Foo = f, Bars = bs })
.SelectMany(
fooBars => fooBars.Bars.DefaultIfEmpty(),
(x,y) => new { Foo = x.Foo, Bar = y });
Run Code Online (Sandbox Code Playgroud)
使用简单的数据集显示差异(假设我们自己加入了值):
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 4, 5 };
// Result using both Option 1 and 2. Option 1 would be a better choice
// if we didn't expect multiple matches in tableB.
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
List<int> tableA = new List<int> { 1, 2, 3 };
List<int?> tableB = new List<int?> { 3, 3, 4 };
// Result using Option 1 would be that an exception gets thrown on
// SingleOrDefault(), but if we use FirstOrDefault() instead to illustrate:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 } // Misleading, we had multiple matches.
// Which 3 should get selected (not arbitrarily the first)?.
// Result using Option 2:
{ A = 1, B = null }
{ A = 2, B = null }
{ A = 3, B = 3 }
{ A = 3, B = 3 }
Run Code Online (Sandbox Code Playgroud)
选项2适用于典型的左外连接定义,但正如我前面提到的,根据数据集的不同,通常会不必要地复杂.
小智 43
组连接方法不需要实现两个数据集的连接.
内部联接:
var qry = Foos.SelectMany
(
foo => Bars.Where (bar => foo.Foo_id == bar.Foo_id),
(foo, bar) => new
{
Foo = foo,
Bar = bar
}
);
Run Code Online (Sandbox Code Playgroud)
对于Left Join,只需添加DefaultIfEmpty()
var qry = Foos.SelectMany
(
foo => Bars.Where (bar => foo.Foo_id == bar.Foo_id).DefaultIfEmpty(),
(foo, bar) => new
{
Foo = foo,
Bar = bar
}
);
Run Code Online (Sandbox Code Playgroud)
EF正确转换为SQL.对于LINQ to对象,使用GroupJoin加入它是更好的,因为它在内部使用Lookup,但是如果你正在查询DB,那么跳过GroupJoin就是AFAIK的性能.
与GroupJoin()相比,这种方式的Personlay更具可读性.SelectMany()
haj*_*zin 14
您可以创建扩展方法,如:
public static IEnumerable<TResult> LeftOuterJoin<TSource, TInner, TKey, TResult>(this IEnumerable<TSource> source, IEnumerable<TInner> other, Func<TSource, TKey> func, Func<TInner, TKey> innerkey, Func<TSource, TInner, TResult> res)
{
return from f in source
join b in other on func.Invoke(f) equals innerkey.Invoke(b) into g
from result in g.DefaultIfEmpty()
select res.Invoke(f, result);
}
Run Code Online (Sandbox Code Playgroud)
改进 Ocelot20 的答案,如果你有一个表,你离开了外部连接,你只想要 0 或 1 行,但它可能有多个,你需要订购你的连接表:
var qry = Foos.GroupJoin(
Bars.OrderByDescending(b => b.Id),
foo => foo.Foo_Id,
bar => bar.Foo_Id,
(f, bs) => new { Foo = f, Bar = bs.FirstOrDefault() });
Run Code Online (Sandbox Code Playgroud)
否则,您在连接中获得的哪一行将是随机的(或者更具体地说,无论 db 碰巧先找到哪一行)。
| 归档时间: |
|
| 查看次数: |
169586 次 |
| 最近记录: |