LINQ to SQL - Left Outer कई ज्वाइन शर्तों के साथ जुड़ें


148

मेरे पास निम्न SQL है, जिसे मैं LINQ में अनुवाद करने की कोशिश कर रहा हूं:

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

मैंने बाएं बाहरी जुड़ाव (यानी into x from y in x.DefaultIfEmpty()आदि) के विशिष्ट कार्यान्वयन को देखा है, लेकिन यह अनिश्चित है कि अन्य जुड़ने की स्थिति को कैसे शुरू किया जाए ( AND f.otherid = 17)

संपादित करें

AND f.otherid = 17WHERE क्लॉज में बजाय JOIN के हालत हिस्सा क्यों है ? क्योंकि fकुछ पंक्तियों के लिए मौजूद नहीं हो सकता है और मैं अभी भी इन पंक्तियों को शामिल करना चाहता हूँ। जोइन के बाद अगर WHERE क्लॉज में यह शर्त लागू होती है, तो मुझे वह व्यवहार नहीं मिलता, जो मैं चाहता हूं।

दुर्भाग्य से यह:

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

इसके बराबर प्रतीत होता है:

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

जो काफी नहीं है कि मैं उसके बाद क्या हूं।


मिठाई! मैं थोड़ी देर के लिए इस के लिए देख रहा हूँ, लेकिन यह कैसे के लिए खोज करने के लिए यकीन नहीं था। सुनिश्चित नहीं हैं कि इस उत्तर में टैग कैसे जोड़े जाएं। यहाँ मैं खोज मापदंड का उपयोग किया है: linq में शामिल होने के लिए sql फ़िल्टर या linq से sql में शामिल होने के लिए जहां खंड या से
Solburn

जवाबों:


243

आपको कॉल करने से पहले अपनी जॉइन कंडीशन को शुरू करना होगा DefaultIfEmpty()। मैं सिर्फ विस्तार विधि वाक्यविन्यास का उपयोग करूंगा:

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

या आप एक सबक्वेरी का उपयोग कर सकते हैं:

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

1
साझा करने के लिए धन्यवाद। कहाँ से क्वालीफायर .... डिफ़ॉल्ट वक्तव्य। मुझे नहीं पता था कि आप ऐसा कर सकते हैं।
फ्रैंक थॉमस

28

यह भी काम करता है, ... यदि आपके पास कई कॉलम हैं

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

12

मुझे पता है कि यह " थोड़ा देर से " है, लेकिन अगर किसी को LINQ मेथड सिंटैक्स में ऐसा करने की आवश्यकता होती है ( यही कारण है कि मुझे यह पोस्ट शुरू में मिली ), तो यह होगा कि ऐसा कैसे करें:

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

2
मेमने के संस्करण को देखने के लिए बहुत उपयोगी है!
शिक्षार्थी

2
.Select(fact.Value)होना चाहिए.Select(f => f.Value)
पेट्र फेल्जमैन

5

एक और वैध विकल्प निम्न के रूप में कई LINQ खंडों में जाल फैलाना है:

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

            // Add the specified content using UNION
            content = content.Union(addMoreContent);

            // Exclude the duplicates using DISTINCT
            content = content.Distinct();

            return content;
        }
    catch (MyLovelyException ex)
    {
        // Add your exception handling here
        throw ex;
    }
}

क्या यह एकल linq क्वेरी में पूरे ऑपरेशन को करने की तुलना में धीमा नहीं होगा?
उमर टी।

@ umar-t, हाँ सबसे अधिक संभावना है, इस पर विचार आठ साल से अधिक समय पहले जब मैंने इसे लिखा था। व्यक्तिगत रूप से मुझे Dahlbyk द्वारा पोस्ट की गई सह-संबद्ध उप-क्वेरी पसंद है यहां stackoverflow.com/a/1123051/212950
MAbraham1

1
एक "संघ" एक "क्रॉस-जॉइन" की तुलना में एक अलग ऑपरेशन है। यह इसके अलावा गुणा की तरह है।
सनकैट

1
@ Suncat2000, सुधार के लिए धन्यवाद। थैंक्सगिविंग की शुभकामनाएं! Ham
MAbraham1

0

संयुक्त सम्मिलित कुंजी का उपयोग करके लिखा जा सकता है। इसके अलावा अगर लेफ्ट और राइट साइड दोनों तरफ से प्रॉपर्टीज का चयन करना है तो LINQ को लिखा जा सकता है

var result = context.Periods
    .Where(p => p.companyid == 100)
    .GroupJoin(
        context.Facts,
        p => new {p.id, otherid = 17},
        f => new {id = f.periodid, f.otherid},
        (p, f) => new {p, f})
    .SelectMany(
        pf => pf.f.DefaultIfEmpty(),
        (pf, f) => new MyJoinEntity
        {
            Id = pf.p.id,
            Value = f.value,
            // and so on...
        });

-1

ऐसा लगता है कि अनुवाद करने का प्रयास करने से पहले आपके SQL कोड में कुछ पुनर्लेखन पर विचार करने का मूल्य है।

व्यक्तिगत रूप से, मैं एक संघ के रूप में ऐसी क्वेरी लिखूंगा (हालांकि मैं पूरी तरह से अशक्तता से बचूंगा!):

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

इसलिए मुझे लगता है कि मैं @ MAbraham1 के उत्तर की भावना से सहमत हूं (हालांकि उनका कोड प्रश्न से असंबंधित लगता है)।

हालाँकि, ऐसा लगता है कि क्वेरी को स्पष्ट रूप से डुप्लिकेट पंक्तियों से युक्त एकल कॉलम परिणाम का उत्पादन करने के लिए डिज़ाइन किया गया है - वास्तव में डुप्लिकेट नल! यह निष्कर्ष पर नहीं आना मुश्किल है कि यह दृष्टिकोण त्रुटिपूर्ण है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.