2009-02-11 36 views
5

OK đây là một tiếng rên nhỏ nhưng đó cũng là một câu hỏi. Trong Linq tôi có thể tham gia như sau:Tại sao LINQ tham gia khác nhau

from c in dc.Customers join o in dc.Orders on c.custid equals o.custid ... 

Tất cả tốt và tốt và hoàn toàn có thể nhớ được mà không cần phải quay lại và google. Tuy nhiên trái tham gia còn lâu mới phức tạp hơn đối với một số lý do:

from c in dc.Customers 
join o in dc.Orders on c.custid equals o.custid 
into temp from x in temp.DefaultIfEmpty() ... 

Vì vậy, câu hỏi của tôi là lý do tại sao các nhà thiết kế của LINQ không thể làm cho mọi việc đơn giản (sql nhiều loại tương tự) với một cái gì đó như thế này:

từ c trong dc.Customers trái tham gia o trong dc.Orders trên c.custid bằng o.custid ...

Cheers Lee

Trả lời

0

có lẽ vì các biểu thức LINQ chỉ đơn giản là syntactic sugar trong trình biên dịch, có thể dịch chúng thành meth od cuộc gọi. Vì vậy, cú pháp truy vấn là một trừu tượng bị rò rỉ của một hệ thống hướng đối tượng.

Vì bạn không thực sự viết SQL, nên chắc chắn có trường hợp công nghệ cơ bản hoạt động khác nhau. Việc thêm một 'tham gia trái' giống SQL có thể khó hơn rất nhiều so với bạn nghĩ.


Một số người rõ ràng không biết cách biểu thức LINQ hoạt động, vì vậy, đây là giải thích thêm.

Nếu tôi mất lớp thử nghiệm này:

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; 
    } 
} 

list.Where(l => l == "test2") được biên soạn vào mã giống như from l in list where l == "test2" select l. Trong cả hai trường hợp, trình biên dịch tạo ra các đại biểu phương thức ẩn danh:

.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 
} 

Đây là ý nghĩa của đường cú pháp. Biểu thức truy vấn không thêm bất kỳ thứ gì mới vào ngôn ngữ, chúng chỉ cung cấp cách dễ dàng hơn để sử dụng các tính năng ngôn ngữ hiện có.

+0

Vâng tôi đoán nó có lẽ là khó khăn - Tôi muốn biết tại sao nó là khó khăn mặc dù ... – user52110

+0

LINQ không phải là cú pháp đường. trình biên dịch không dịch bất kỳ biểu thức lambda INTO nào. Không ai nói gì về việc tạo ra SQL trong câu hỏi. -1 –

+0

OK, tôi không tích cực nó là lambdas mỗi se, nhưng linq IS cú pháp đường, và được dịch sang các cuộc gọi phương pháp của trình biên dịch. –

5

lý do tại sao các nhà thiết kế của LINQ không thể làm cho mọi việc đơn giản (sql giống như)

Họ có thể có. Nhưng định nghĩa của bạn về đơn giản (như một lập trình viên sql) không giống như định nghĩa của lập trình viên OO đơn giản. Linq (trong C#) là một công nghệ truy vấn cho các lập trình viên OO, đầu tiên. Ví dụ về điều này là lý do tại sao chọn đến cuối cùng. Đó là để thực hiện các quy tắc phạm vi trong hỗ trợ C# và intellisense trong trình soạn thảo.

Những lập trình viên này có thể không nhận được LEFT JOIN (và thực sự bối rối nếu bạn nói LEFT OUTER JOIN - nghĩ rằng có một số khác biệt, giống như một kế thừa từ khác).

Điều họ hiểu là GROUP JOIN, hoạt động theo cách tương tự.

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); 
} 

Tất cả những gì DefaultIfEmpty thứ làm là giải nén nhóm - làm phẳng các kết quả vào hàng/form cột - xa dạng heirarchical tự nhiên các lập trình viên OO của.DefaultIfEmpty không cần thiết về mặt ngữ nghĩa để có được kết quả.

Dưới đây là cùng một truy vấn trong form method - mà trình biên dịch tạo ra từ bên trên và trong đó tôi thích:

var query = myInts.GroupJoin(
    myOtherInts, 
    i => i, 
    j => j, 
    (i, g) => new { key = i, myGroup = g } 
); 

Ông có thể nói rằng về mặt gương sáng của mình?

Truy vấn này cung cấp cho bạn khách hàng, với đơn đặt hàng của họ dưới dạng bộ sưu tập được đính kèm. Bộ sưu tập đơn đặt hàng có thể trống. Nếu bạn có 50 khách hàng và 1000 đơn đặt hàng, bạn sẽ có 50 khách hàng trong kết quả.

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}; 

Truy vấn này cung cấp cho bạn hàng CustomerOrder. Nếu khách hàng có 5 đơn đặt hàng, khách hàng sẽ xuất hiện 5 lần, mỗi lần khớp với một đơn hàng khác. Nếu khách hàng có 0 đơn đặt hàng, khách hàng sẽ xuất hiện sau khi khớp với một đơn đặt hàng không. Nếu bạn có 50 khách hàng và 1000 đơn đặt hàng, bạn sẽ có 50-1049 hàng sau khi tham gia và ý nghĩa của một yếu tố trong kết quả khó xác định.

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} 

Nếu chúng triển khai left join, nó sẽ yêu cầu hình dạng kết quả của ví dụ thứ hai. Khi tôi sử dụng group join, tốt hơn, tôi cũng sẽ không triển khai left join trong một bước. Cấu trúc phân cấp kết quả truy vấn rất tuyệt vời.

+0

Tôi không thấy câu trả lời của bạn giải quyết câu hỏi như thế nào. Bạn có thể nói rằng về mặt ví dụ của mình? – dkretz

+0

Tôi muốn cuộc sống đầu tiên để nói cảm ơn đã dành thời gian để viết suy nghĩ của bạn kích động bài. Tôi sẽ có một cái nhìn gần hơn vào ngày mai - phản ứng ngay lập tức của tôi tuy nhiên là để nói rằng có một Sqlish rõ ràng nghiêng để Linq đã để nói rằng các lập trình viên OO sẽ không nhận được nó không thực sự rửa như một lý do. – user52110

+0

Ouch bộ não của tôi đau ... nhưng tôi nghĩ rằng tôi hiểu về các nhà thiết kế LINQ đang cố gắng giữ gìn sự đại diện theo kiểu người thừa kế theo sở thích của họ. – stusmith

Các vấn đề liên quan