2009-07-14 36 views
126

Tôi có SQL sau đây, mà tôi đang cố gắng để dịch để LINQ:LINQ to SQL - Left Outer Join với nhiều điều kiện tham gia

SELECT f.value 
FROM period as p 
LEFT OUTER JOIN facts AS f ON p.id = f.periodid AND f.otherid = 17 
WHERE p.companyid = 100 

Tôi đã thấy việc thực hiện đặc trưng của trái bên ngoài tham gia (ví dụ. into x from y in x.DefaultIfEmpty() vv), nhưng không chắc chắn làm thế nào để giới thiệu người kia điều kiện join (AND f.otherid = 17)

EDIT

Tại sao là phần AND f.otherid = 17 điều kiện JOIN thay vì trong mệnh đề WHERE? Vì f có thể không tồn tại đối với một số hàng và tôi vẫn muốn các hàng này được bao gồm. Nếu điều kiện được áp dụng trong mệnh đề WHERE, sau JOIN - thì tôi không nhận được hành vi mà tôi muốn.

Thật không may này:

from p in context.Periods 
join f in context.Facts on p.id equals f.periodid into fg 
from fgi in fg.DefaultIfEmpty() 
where p.companyid == 100 && fgi.otherid == 17 
select f.value 

có vẻ là tương đương với điều này:

SELECT f.value 
FROM period as p 
LEFT OUTER JOIN facts AS f ON p.id = f.periodid 
WHERE p.companyid = 100 AND f.otherid = 17 

mà không phải là khá gì tôi sau đó.

+0

Ngọt ngào!Tôi đã tìm kiếm điều này một thời gian nhưng không chắc chắn làm thế nào để tìm kiếm điều này. Không chắc chắn cách thêm thẻ vào câu trả lời này. Dưới đây là các tiêu chuẩn tìm kiếm tôi đã sử dụng: LINQ to sql filter tham gia hoặc từ LINQ to sql where khoản tham gia hoặc từ – Solburn

Trả lời

205

Bạn cần giới thiệu điều kiện tham gia của mình trước khi gọi DefaultIfEmpty(). Tôi sẽ chỉ cần sử dụng phần mở rộng phương pháp cú pháp:

from p in context.Periods 
join f in context.Facts on p.id equals f.periodid into fg 
from fgi in fg.Where(f => f.otherid == 17).DefaultIfEmpty() 
where p.companyid == 100 
select f.value 

Hoặc bạn có thể sử dụng một subquery:

from p in context.Periods 
join f in context.Facts on p.id equals f.periodid into fg 
from fgi in (from f in fg 
      where f.otherid == 17 
      select f).DefaultIfEmpty() 
where p.companyid == 100 
select f.value 
5

Một tùy chọn khác hợp lệ là để truyền bá tham gia trên nhiều LINQ khoản, như sau:

public static IEnumerable<Announcementboard> GetSiteContent(string pageName, DateTime date) 
{ 
    IEnumerable<Announcementboard> content = null; 
    IEnumerable<Announcementboard> addMoreContent = null; 
     try 
     { 
      content = from c in DB.Announcementboards 
       //Can be displayed beginning on this date 
       where c.Displayondate > date.AddDays(-1) 
       //Doesn't Expire or Expires at future date 
       && (c.Displaythrudate == null || c.Displaythrudate > date) 
       //Content is NOT draft, and IS published 
       && c.Isdraft == "N" && c.Publishedon != null 
       orderby c.Sortorder ascending, c.Heading ascending 
       select c; 

      //Get the content specific to page names 
      if (!string.IsNullOrEmpty(pageName)) 
      { 
       addMoreContent = from c in content 
        join p in DB.Announceonpages on c.Announcementid equals p.Announcementid 
        join s in DB.Apppagenames on p.Apppagenameid equals s.Apppagenameid 
        where s.Apppageref.ToLower() == pageName.ToLower() 
        select c; 
      } 

      //CROSS-JOIN this content 
      content = content.Union(addMoreContent); 

      //Exclude dupes - effectively OUTER JOIN 
      content = content.Distinct(); 

      return content; 
     } 
    catch (MyLovelyException ex) 
    { 
     throw ex; 
    } 
} 
+0

nó sẽ không chậm hơn so với thực hiện toàn bộ hoạt động trong một truy vấn LINQ? –

+0

@ umar-t, Có nhiều khả năng, xem xét việc này đã hơn tám năm trước khi tôi viết nó. Cá nhân tôi thích truy vấn con tương quan được mô phỏng bởi Dahlbyk ở đây https://stackoverflow.com/a/1123051/212950 – MAbraham1

23

công trình này cũng vậy, ... nếu bạn có nhiều cột tham gia

from p in context.Periods 
join f in context.Facts 
on new { 
    id = p.periodid, 
    p.otherid 
} equals new { 
    f.id, 
    f.otherid 
} into fg 
from fgi in fg.DefaultIfEmpty() 
where p.companyid == 100 
select f.value 
-1

Dường như với tôi có giá trị trong việc xem xét một số ghi đè vào mã SQL của bạn trước khi thử dịch nó.

Cá nhân, tôi muốn viết một truy vấn như một liên minh (mặc dù tôi muốn tránh null hoàn toàn!):

SELECT f.value 
    FROM period as p JOIN facts AS f ON p.id = f.periodid 
WHERE p.companyid = 100 
     AND f.otherid = 17 
UNION 
SELECT NULL AS value 
    FROM period as p 
WHERE p.companyid = 100 
     AND NOT EXISTS ( 
         SELECT * 
         FROM facts AS f 
         WHERE p.id = f.periodid 
          AND f.otherid = 17 
        ); 

Vì vậy, tôi đoán tôi đồng ý với tinh thần của câu trả lời @ MAbraham1 (mặc dù mã của họ dường như không liên quan đến câu hỏi).

Tuy nhiên, có vẻ như truy vấn được thiết kế rõ ràng để tạo ra một kết quả cột đơn bao gồm các hàng trùng lặp - thực sự là các số không trùng lặp! Thật khó để không đi đến kết luận rằng cách tiếp cận này là thiếu sót.

7

Tôi biết đó là "hơi muộn" nhưng chỉ trong trường hợp nếu ai cần phải làm điều này trong LINQ Phương pháp cú pháp (đó là lý do tôi tìm thấy bài viết này ban đầu), đây sẽ là làm thế nào để làm điều đó :

var results = context.Periods 
    .GroupJoin(
     context.Facts, 
     period => period.id, 
     fk => fk.periodid, 
     (period, fact) => fact.Where(f => f.otherid == 17) 
           .Select(fact.Value) 
           .DefaultIfEmpty() 
    ) 
    .Where(period.companyid==100) 
    .SelectMany(fact=>fact).ToList(); 
+0

Rất hữu ích để xem phiên bản lambda! – Learner

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