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()等),但是不确定如何引入其他连接条件( AND f.otherid = 17

编辑

为什么AND f.otherid = 17条件部分JOIN,而不是在WHERE子句? 因为f可能不存在的一些行,我仍然希望这些行被列入。 如果在WHERE子句中应用条件,则在JOIN之后 – 那么我不会得到我想要的行为。

不幸的是:

 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 

这不是我所追求的。

您需要在调用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 

我知道这是“ 有点晚 ”,但如果有人需要在LINQ方法语法中这样做( 这就是为什么我最初find这个post ),这将是如何做到这一点:

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

另一个有效的select是扩展跨多个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代码是有价值的。

就个人而言,我会写一个这样的查询作为一个联盟(尽pipe我完全避免了空值):

 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答案的精神(虽然他们的代码似乎与这个问题无关)。

但是,似乎查询是明确devise的,以产生包含重复行的单列结果 – 实际上是重复的空值! 这个方法是有缺陷的,这是很难得出的结论。