Cách tham gia LINQ trên nhiều lĩnh vực trong một lần tham gia


244

Tôi cần thực hiện một truy vấn LINQ2DataSet để tham gia trên nhiều lĩnh vực (như

var result = from x in entity
join y in entity2 
       on x.field1 = y.field1 
and 
          x.field2 = y.field2

Tôi vẫn chưa tìm thấy một giải pháp phù hợp (tôi có thể thêm các ràng buộc bổ sung vào mệnh đề where, nhưng đây là một giải pháp phù hợp, hoặc sử dụng giải pháp này , nhưng giả sử một Equijoin).

LINQ có thể tham gia trên nhiều lĩnh vực trong một lần tham gia không?

BIÊN TẬP

var result = from x in entity
             join y in entity2
             on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

là giải pháp mà tôi đã tham chiếu khi giả sử một Equijoin ở trên.

EDIT thêm

Để trả lời những lời chỉ trích rằng ví dụ ban đầu của tôi là một Equijoin, tôi thừa nhận rằng, Yêu cầu hiện tại của tôi là cho một Equijoin và tôi đã sử dụng giải pháp mà tôi đã tham khảo ở trên.

Tuy nhiên, tôi đang cố gắng hiểu những khả năng và thực tiễn tốt nhất mà tôi có / nên sử dụng với LINQ. Tôi sẽ sớm thực hiện tham gia truy vấn phạm vi ngày với ID bảng và chỉ cần xử lý trước vấn đề đó, có vẻ như tôi sẽ phải thêm phạm vi ngày trong mệnh đề where.

Cảm ơn, như mọi khi, cho tất cả các đề xuất và ý kiến ​​được đưa ra


48
Chỉ là một FYI cho bất cứ ai đọc điều này, nếu bạn tham gia nhiều trường tham gia vào các lớp annon, bạn PHẢI đặt tên cho các trường trong cả hai lớp annon giống nhau, nếu không bạn sẽ gặp lỗi biên dịch.
Đánh dấu

6
Hay đúng hơn, bạn phải đảm bảo họ có tên phù hợp. tức là bạn chỉ có thể đặt tên cho các trường của một trong các loại anon để làm cho chúng khớp với các loại khác.
Tom Ferguson

1
Hãy chú ý đến câu trả lời này stackoverflow.com/a 432176502/1704458
TS

Tôi đã sử dụng các bộ dữ liệu cho cả hai bên bằng chứ không phải các đối tượng và nó dường như cũng hoạt động.
GHZ

Câu trả lời:


89

Các giải pháp với loại ẩn danh nên hoạt động tốt. LINQ chỉ có thể đại diện cho đẳng thức (dù sao cũng có mệnh đề tham gia) và thực sự đó là những gì bạn đã nói bạn muốn diễn đạt bằng cách dựa trên truy vấn ban đầu của bạn.

Nếu bạn không thích phiên bản có loại ẩn danh vì một số lý do cụ thể, bạn nên giải thích lý do đó.

Nếu bạn muốn làm một cái gì đó khác với những gì bạn yêu cầu ban đầu, xin vui lòng cho một ví dụ về những gì bạn thực sự muốn làm.

EDIT: Trả lời chỉnh sửa trong câu hỏi: có, để thực hiện tham gia "phạm vi ngày", bạn cần sử dụng mệnh đề where thay thế. Chúng thực sự tương đương về mặt ngữ nghĩa, vì vậy đó chỉ là vấn đề tối ưu hóa có sẵn. Equijoins cung cấp tối ưu hóa đơn giản (trong LINQ to Object, bao gồm LINQ to DataSets) bằng cách tạo một tra cứu dựa trên chuỗi bên trong - nghĩ về nó như một hàm băm từ khóa đến chuỗi các mục khớp với khóa đó.

Làm điều đó với phạm vi ngày có phần khó hơn. Tuy nhiên, tùy thuộc vào chính xác ý của bạn về "tham gia phạm vi ngày", bạn có thể làm điều gì đó tương tự - nếu bạn dự định tạo "dải" ngày (ví dụ: một mục mỗi năm) sao cho hai mục xuất hiện trong cùng năm (nhưng không cùng ngày) sẽ khớp, sau đó bạn có thể làm điều đó chỉ bằng cách sử dụng băng tần đó làm khóa. Nếu nó phức tạp hơn, ví dụ một mặt của phép nối cung cấp một phạm vi và mặt kia của phép nối cung cấp một ngày duy nhất, khớp nếu nó nằm trong phạm vi đó, điều đó sẽ được xử lý tốt hơn bằng một wheremệnh đề (sau một giâyfrommệnh đề) IMO. Bạn có thể thực hiện một số phép thuật đặc biệt thú vị bằng cách ra lệnh cho bên này hoặc bên kia để tìm trận đấu hiệu quả hơn, nhưng đó sẽ là rất nhiều công việc - Tôi chỉ làm điều đó sau khi kiểm tra xem hiệu suất có phải là vấn đề hay không.


Cảm ơn, có hiệu suất là lo lắng chính của tôi với việc sử dụng mệnh đề where. Tôi đoán một mệnh đề where sau khi tham gia sẽ thực hiện một bộ lọc trên một tập dữ liệu lớn hơn có thể đã được giảm bằng cách giới thiệu tham số nối thứ hai. Tôi thích ý tưởng đặt hàng để kiểm tra xem tôi có thể đạt được hiệu quả hay không
johnc

Bạn sẽ có bao nhiêu hồ sơ? Đừng quên rằng việc đặt hàng kết quả để bắt đầu sẽ mất một khoảng thời gian nhất định để bắt đầu với ...
Jon Skeet

"Chúng thực sự tương đương về mặt ngữ nghĩa" - chúng ta có cần từ "thực sự" trong đó không? Có lẽ bạn muốn nói, "Chúng thực sự tương đương về mặt ngữ nghĩa" :)
ngày

136
var result = from x in entity
   join y in entity2 on new { x.field1, x.field2 } equals new { y.field1, y.field2 }

Đây là những gì tôi đang tìm kiếm khi 101 Mẫu Linq không có thứ này, hoặc ít nhất là tôi đã thấy.
Chris Marisic

1
@PeterX thực sự có thể, xem câu trả lời của tôi ở đây: stackoverflow.com/a/22176658/595157
niieani

13
Các mã trên không hoạt động. Sau khi thêm on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 } Nó hoạt động
Ravi Ram

@Ravi Ram .. Cảm ơn .. bình luận của bạn đã giúp
NMathur

80
var result = from x in entity1
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }

Bạn cần phải làm điều này, nếu tên cột khác nhau trong hai thực thể.


6
Cảm ơn đã đề cập đến các tên cột khác nhau. Điều này đã sửa chữa biểu hiện xấu của tôi.
Gaʀʀʏ

1
Điều này làm việc cho tôi quá. Nếu tên cột không khớp, bạn sẽ gặp lỗi này, "Loại một trong các biểu thức trong mệnh đề nối là không chính xác. Nhập suy luận không thành công trong lệnh gọi 'GroupJoin'."
humbads 27/8/2016

Cảm ơn bạn đã bí danh các biến quan trọng.
Thomas.Benz

Tôi đã gặp lỗi mà @humbads đã đề cập khi tôi không đặt tên cho tất cả các thuộc tính của int 'new {}'. Vì vậy, chỉ cần fyi nếu bạn đặt tên một, bạn cũng phải đặt tên cho phần còn lại.
Ethan Melamed

CẢM ƠN BẠN RẤT NHIỀU
Charly H

51

Chỉ cần hoàn thành việc này với cú pháp chuỗi phương thức tương đương:

entity.Join(entity2, x => new {x.Field1, x.Field2},
                     y => new {y.Field1, y.Field2}, (x, y) => x);

Trong khi đối số cuối cùng (x, y) => xlà những gì bạn chọn (trong trường hợp trên, chúng tôi chọn x).


31

Tôi nghĩ rằng một tùy chọn dễ đọc và linh hoạt hơn là sử dụng chức năng Where:

var result = from x in entity1
             from y in entity2
                 .Where(y => y.field1 == x.field1 && y.field2 == x.field2)

Điều này cũng cho phép dễ dàng thay đổi từ tham gia bên trong sang tham gia bên trái bằng cách nối thêm .Default IfEmpty ().


Là một người dùng lambda lâu nay (trái ngược với khi tôi đặt câu hỏi), tôi sẽ phải đồng ý
johnc

Điều này sẽ chậm hơn?
AlfredBr

1
Tôi nghĩ rằng nó nên có hiệu suất tương tự như { ... } equals new { ... }cú pháp mới . LinqPad là một công cụ tuyệt vời để xem cách các biểu thức hoạt động (tập lệnh SQL nếu LINQ2Query được sử dụng, cây biểu thức, v.v.)
Alexei

Theo như tôi nhận thấy nó đang sản xuất CROSS THAM GIA thay vì INNER THAM GIA
Mariusz

@Mariusz Vâng, thật hợp lý khi tạo CROSS THAM GIA + Ở ĐÂU thay vì INNER THAM GIA. Đối với các truy vấn đơn giản, tôi hy vọng bộ phân tích sẽ tạo ra một thứ rất giống nhau.
Alexei

10
var result = from x in entity
             join y in entity2
             on new { X1= x.field1, X2= x.field2 } equals new { X1=y.field1, X2= y.field2 }
             select new 
             {
               /// Columns
              };

8

bạn có thể làm một cái gì đó như (bên dưới)

var query = from p in context.T1

        join q in context.T2

        on

        new { p.Col1, p.Col2 }

        equals

         new { q.Col1, q.Col2 }

        select new {p...., q......};

Như tôi đã đề cập trong câu hỏi, điều đó đòi hỏi một Equijoin
johnc

7

Sử dụng toán tử nối, bạn chỉ có thể thực hiện đẳng thức. Các loại liên kết khác có thể được xây dựng bằng cách sử dụng các toán tử khác. Tôi không chắc liệu tham gia chính xác mà bạn đang cố gắng thực hiện sẽ dễ dàng hơn bằng cách sử dụng các phương thức này hoặc bằng cách thay đổi mệnh đề where. Tài liệu về điều khoản tham gia có thể được tìm thấy ở đây . MSDN cũng có một bài viết về các hoạt động tham gia với nhiều liên kết đến các ví dụ về các liên kết khác.


3

Nếu tên trường khác nhau trong các thực thể

var result = from x in entity
   join y in entity2 on 
          new {
                field1=   x.field1,
               field2 =  x.field2 
             } 
          equals
         new { 
                field1= y.field1,
                field2=  y.myfield
              }
select new {x,y});

Cảm ơn bạn. Tên phù hợp là mảnh tôi đã mất.
Brett

2

Như một chuỗi phương thức đầy đủ sẽ trông như thế này:

lista.SelectMany(a => listb.Where(xi => b.Id == a.Id && b.Total != a.Total),
                (a, b) => new ResultItem
                {
                    Id = a.Id,
                    ATotal = a.Total,
                    BTotal = b.Total
                }).ToList();

-2
from d in db.CourseDispatches
                             join du in db.DispatchUsers on d.id equals du.dispatch_id
                             join u in db.Users on du.user_id equals u.id
                             join fr in db.Forumreports on (d.course_id + '_' + du.user_id)  equals  (fr.course_id + '_'+ fr.uid)

cái này hiệu quả với tôi


Đây là để tham gia nhiều lần, anh ấy muốn tham gia với nhiều lĩnh vực trong một lần tham gia
theLaw

-3

Khai báo một Class (Type) để giữ các thành phần bạn muốn tham gia. Trong ví dụ dưới đây, khai báo JoinEuity

 public class **JoinElement**
{
    public int? Id { get; set; }
    public string Name { get; set; }

}

results = from course in courseQueryable.AsQueryable()
                  join agency in agencyQueryable.AsQueryable()
                   on new **JoinElement**() { Id = course.CourseAgencyId, Name = course.CourseDeveloper } 
                   equals new **JoinElement**() { Id = agency.CourseAgencyId, Name = "D" } into temp1

1
Điều này đã được trả lời 9 năm trước ... câu trả lời này mang lại giá trị gì?
Maciej Jureczko
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.