LINQ to SQL-левое внешнее соединение с несколькими условиями соединения
у меня есть следующий 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() etc.) но я не уверен, как ввести другое условие соединения (AND f.otherid = 17)
EDIT
почему AND f.otherid = 17 условие часть соединения вместо того, чтобы в предложении WHERE?
Потому что 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
что не совсем то, что мне нужно.
5 ответов:
вам нужно ввести ваше условие соединения перед вызовом
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
это тоже работает ...если у вас есть несколько столбцов соединения
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
Я знаю, что это "немного поздно!--3--> но на всякий случай, если кому-то нужно сделать это в синтаксис метода 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();
еще одним допустимым вариантом является распространение присоединяется через несколько предложений 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; } //CROSS-JOIN this content content = content.Union(addMoreContent); //Exclude dupes - effectively OUTER JOIN content = content.Distinct(); return content; } catch (MyLovelyException ex) { throw ex; } }
Мне кажется, что есть смысл рассмотреть некоторые перезаписи в ваш 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 (хотя их код, похоже, не связан с вопросом).
однако, похоже, что запрос явно предназначен для получения результата одного столбца, содержащего повторяющиеся строки -- действительно дублировать нули! Трудно не прийти к выводу, что этот подход ошибочен.
Comments