简体   繁体   English

linq to sql多个联接

[英]linq to sql mulitiple joins

I am trying to create a LINQ to SQL query and am really stumped. 我正在尝试创建LINQ to SQL查询,但确实很麻烦。

I have a database with multiple tables and can create a query that successfully returns the result from a single join. 我有一个具有多个表的数据库,并且可以创建一个查询,该查询从单个联接中成功返回结果。 The problem I am having is introducing the second join. 我遇到的问题是引入第二个联接。

The SQL statement was easy enough to generate SQL语句很容易生成

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

I've generated two functional LINQ queries that individually return the desired results, but can't marry the two successfully. 我已经生成了两个功能性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()

Returns all slips that have no end date set in the database (null), they've never been leased. 返回未在数据库中设置结束日期的所有发票(空),这些发票从未被租借。

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

Returns slips that the lease has expired on. 返回租约到期的单据。

What I'd like to be able to do is combine the two queries somehow into one that returns all slips that have either never been leased out or have had their leases expire. 我想做的是将这两个查询以某种方式组合成一个查询,该查询返回所有从未租出或租约到期的单据。

Any help would be greatly appreciated, I've been at this for two days and can't see the forest for the trees anymore. 任何帮助将不胜感激,我已经在这里待了两天了,再也看不到森林里有树木了。

Schema is four tables; 模式是四个表。 Lease, Slip, Dock, Location. 租赁,滑移,停放,位置。 Lease PK ID FK SlipID 租赁PK ID FK SlipID

Slip PK ID FK DockID 单据PK ID FK DockID

Dock PK ID FK LocationID 码头PK ID FK位置ID

Location PK ID 位置PK ID

Revised query is: 修改后的查询为:

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

Returns: 返回值:

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

Yielding everything. 屈服一切。 If I remove the last .DefaultIfEmpty() I get a result set of only the slips that have had a lease; 如果删除最后一个.DefaultIfEmpty(),则会得到仅包含租约的单据的结果集。 current or expired. 当前或过期。

if the FK's are in place, normally you don't have to do the 'join' steps yourself with linq-to-sql, you can just reference the navigation properties. 如果FK到位,通常您不必自己使用linq-to-sql进行“加入”步骤,您只需引用导航属性即可。 Also, keep in mind that you can use 'let' to define things in the query that might make it easier for you to make a query. 另外,请记住,可以使用“ let”来定义查询中的内容,这可能会使您更容易进行查询。

Since the FK is by way of lease having a SlipID, then it appears a given slip could have any number (0 .. *) of leases associated with it, although your logic seems to indicate it would be just 0 or 1 - if that's true, a nullable FK LeaseID on the slip might make more sense, but that's a tangent. 由于FK是通过具有SlipID的租约方式进行的,因此给定的单据可能具有与之关联的任何数量(0 .. *)的租约,尽管您的逻辑似乎表明它将仅为0或1-如果那是是的,单据上可以为空的FK LeaseID可能更有意义,但这是切线。 For now I'll stick with the original SQL logic which was "any associated lease is expired" 现在,我将继续使用原始的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;

You could still construct a query without navigation properties, of course, but I find it easier and much less error-prone to use the generated navigation properties instead of manually specifying the join and its condition :) 当然,您仍然可以构造不带导航属性的查询,但是我发现使用生成的导航属性而不是手动指定联接及其条件容易,容易出错得多:)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM