2010-06-25 42 views
0

我想创建一个LINQ to SQL查询,我真的难倒了。linq到sql mulitiple加入

我有一个数据库与多个表,并可以创建一个查询,成功地返回单个连接的结果。我遇到的问题是介绍第二次加入。

的SQL语句很容易足以产生

USE InlandMarina 
SELECT * 
FROM Slip s LEFT JOIN Lease l ON s.id = l.slipid 
WHERE GETDATE() > l.EndDate OR ISNULL(l.startdate, '') = '' 

我产生两个功能LINQ查询单独地返回了预期的效果,但无法成功娶两个。

var nulledSlips = from slips in theContext.Slips 
        join nulled in theContext.Leases on slips.ID equals nulled.SlipID into slipsNulled 
        from nulledEndDate in slipsNulled.Where(nulled => nulled.EndDate==null).DefaultIfEmpty() 

返回在数据库中没有设置结束日期的所有单据(空),它们从未被租用过。

from expiredSlips in theContext.Slips 
          join leased in theContext.Leases on slips.ID equals leased.SlipID into allSlips 
          from leased in allSlips 
          where leased.EndDate < DateTime.Today 

返回租约已到期的单据。

我想要做的就是将两个查询以某种方式组合起来,返回所有从未被租出或租约到期的单据。

任何帮助将不胜感激,我已经在这里两天,不能再看到树木的森林。

模式是四张表;租赁,滑,码头,位置。 租赁 PK ID FK SlipID

滑 PK ID FK DockID

基座 PK ID FK LocationID

位置 PK ID

修订的查询是:

var expiredSlips = from slips in theContext.Slips 
        join nulled in theContext.Leases on slips.ID equals nulled.SlipID into slipsNulled 
        from nulledEndDate in slipsNulled.Where(nulled => nulled.EndDate == null).DefaultIfEmpty() 
        join leased in theContext.Leases on slips.ID equals leased.SlipID into allSlips 
        from leased in allSlips.Where(leased=> leased.EndDate < DateTime.Today).DefaultIfEmpty() 

返回:

<SlipsDTO> 
<SlipID>1000</SlipID> 
<Width>8</Width> 
<Length>16</Length> 
<DockID>1</DockID> 
<WaterService>true</WaterService> 
<ElectricalService>true</ElectricalService> 
<MarinaLocation>Inland Lake</MarinaLocation> 
<LeaseStartDate xsi:nil="true" /> 
<LeaseEndDate xsi:nil="true" /> 
</SlipsDTO> 

屈服的一切。如果我删除最后一个.DefaultIfEmpty()我得到一个只有已经有租约的单据的结果集;当前或过期。

+3

在甚至完全分析代码之前,我的建议是在执行任何中间连接时将直接扩展方法语法的linq查询理解语法隐藏起来复杂。 – Pierreten 2010-06-25 02:43:21

+0

我只提到,因为LINQ以不同的方式处理连接,所以你会习惯RDBS世界;在MSDN上查找IEnumerable.Join()并将其与SQL连接进行比较。 – Pierreten 2010-06-25 02:52:58

+1

你可以添加一个关于你的模式的小信息吗?我无法弄清楚它是如何与当前代码相关的。 – 2010-06-25 02:54:48

回答

1

如果FK已经就位,通常您不必使用linq-to-sql自己完成“连接”步骤,只需引用导航属性即可。另外,请记住,您可以使用'let'来在查询中定义可能使您更容易进行查询的内容。

由于FK是通过具有SlipID的租赁方式出现的,因此似乎给定的单据可能有与其相关的任何租赁数量(0 .. *),尽管您的逻辑似乎表明它只是0或1 - 如果这是真的,那么slip上的一个可以为空的FK LeaseID可能更有意义,但这是一个切线。现在我会坚持这是原来的SQL逻辑“任何相关的租约过期”

var query = 
from slip in context.Slips 
let expiredLeases = slip.Leases.Where(lease => lease.EndDate < DateTime.Today) 
where slip.Leases.Any() == false // no leases for this slip yet 
    || expiredLeases.Any() // at least one associated lease is expired 
select slip; 

你仍然可以构造一个查询,而无需导航性能,当然,但我觉得它更容易,更无差错倾向于使用生成的导航属性,而不是手动指定连接及其条件:)

+0

James, 谢谢!发出一张照片,让我可以向这个方向鞠躬。谢谢。 Tom – tkryton 2010-06-25 04:13:09