好吧这是一个小小的呻吟,但这也是一个问题.在Linq我可以这样做一个连接:
from c in dc.Customers join o in dc.Orders on c.custid equals o.custid ...
Run Code Online (Sandbox Code Playgroud)
一切都很好,完全可以记住,而不必回去谷歌.但是由于某些原因,左连接更加复杂:
from c in dc.Customers
join o in dc.Orders on c.custid equals o.custid
into temp from x in temp.DefaultIfEmpty() ...
Run Code Online (Sandbox Code Playgroud)
所以我的问题是为什么Linq的设计师不能用这样的东西简单(更像sql):
来自c的dc.Customers在c.custid等于o.custid的dc.Orders中加入了o ...
干杯李
为什么Linq的设计师不能简单(更像sql)
他们可以.但是你对简单(作为sql程序员)的定义与OO程序员对简单的定义不同.Linq(在C#中)首先是面向OO程序员的查询技术.这方面的一个例子是为什么选择最后.这是为了在编辑器中实现C#中的范围规则和智能感知支持.
这些程序员可能没有得到LEFT JOIN
(并且如果你说LEFT OUTER JOIN
- 并且认为存在一些差异,如同一个继承自另一个),会变得非常困惑.
他们所理解的是GROUP JOIN
,其行为方式类似.
List<int> myInts = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
List<int> myOtherInts = new List<int>() { 1, 3, 5, 7, 9, 11, 13 };
//
var query = from i in myInts
join j in myOtherInts on i equals j into g
select new {key = i, myGroup = g};
//
foreach (var grouping in query)
{
Console.WriteLine("--{0}", grouping.key);
foreach (var x in grouping.myGroup)
Console.WriteLine(x);
}
Run Code Online (Sandbox Code Playgroud)
所有DefaultIfEmpty
这些工作都是打开组 - 将结果展平为行/列形式 - 远离OO程序员的自然形式. DefaultIfEmpty
在语义上没有必要得到结果.
这是方法形式的相同查询 - 编译器从上面生成并且我更喜欢它:
var query = myInts.GroupJoin(
myOtherInts,
i => i,
j => j,
(i, g) => new { key = i, myGroup = g }
);
Run Code Online (Sandbox Code Playgroud)
你可以用他的例子来说明吗?
此查询为您的客户提供其订单作为附加集合.订单集合可能为空.如果您有50个客户和1000个订单,则结果中将有50个客户.
from c in dc.Customers
join o in dc.Orders on c.custid equals o.custid into someOrders
select new CustomerWithOrders()
{theCustomer = c, theOrders = someOrders};
Run Code Online (Sandbox Code Playgroud)
此查询为您提供CustomerOrder行.如果客户有5个订单,则客户将出现5次,每次都与不同的订单匹配.如果客户有0个订单,则客户将出现一次与空订单匹配.如果您有50个客户和1000个订单,则在连接后将有50-1049行,并且结果中的元素含义很难定义.
from c in dc.Customers
join o in dc.Orders on c.custid equals o.custid into temp
from x in temp.DefaultIfEmpty()
select new CustomerOrderHybrid() {theCustomer = c, theOrder = x}
Run Code Online (Sandbox Code Playgroud)
如果它们已实现left join
,则需要第二个示例的结果形状.一旦我使用了group join
,哪个更好,我也不会left join
一步到位.查询结果的分层整形很棒.
可能是因为 Linq 表达式只是编译器中的语法糖,编译器将它们转换为方法调用。因此,查询语法是面向对象系统的有漏洞的抽象。
由于您实际上并未编写 SQL,因此必然存在底层技术表现不同的情况。添加类似 SQL 的“左连接”可能比您想象的要困难得多。
有些人显然不知道 Linq 表达式是如何工作的,所以这里有进一步的解释。
如果我参加这门测试课:
public class Class1
{
public List<string> list = new List<string>() { "test", "test1", "test2" };
public void test_lambda()
{
var test = list.Where(l => l == "test1");
}
public void test_linq()
{
var test = from l in list
where l == "test2"
select l;
}
}
Run Code Online (Sandbox Code Playgroud)
list.Where(l => l == "test2")
被编译为与 相同的代码from l in list where l == "test2" select l
。在这两种情况下,编译器都会生成匿名方法委托:
.method public hidebysig instance void test_lambda() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class [mscorlib]System.Collections.Generic.List`1<string> Class1::list
L_0006: ldsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate1
L_000b: brtrue.s L_001e
L_000d: ldnull
L_000e: ldftn bool Class1::<test_lambda>b__0(string)
L_0014: newobj instance void [System.Core]System.Func`2<string, bool>::.ctor(object, native int)
L_0019: stsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate1
L_001e: ldsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate1
L_0023: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Core]System.Func`2<!!0, bool>)
L_0028: pop
L_0029: ret
}
.method public hidebysig instance void test_linq() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class [mscorlib]System.Collections.Generic.List`1<string> Class1::list
L_0006: ldsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate3
L_000b: brtrue.s L_001e
L_000d: ldnull
L_000e: ldftn bool Class1::<test_linq>b__2(string)
L_0014: newobj instance void [System.Core]System.Func`2<string, bool>::.ctor(object, native int)
L_0019: stsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate3
L_001e: ldsfld class [System.Core]System.Func`2<string, bool> Class1::CS$<>9__CachedAnonymousMethodDelegate3
L_0023: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [System.Core]System.Func`2<!!0, bool>)
L_0028: pop
L_0029: ret
}
Run Code Online (Sandbox Code Playgroud)
这就是我所说的语法糖的意思。查询表达式不会向该语言添加任何新内容,它们只是提供一种使用现有语言功能的更简单的方法。
归档时间: |
|
查看次数: |
400 次 |
最近记录: |