linq sql 一例特殊故障及处理

故障现象

数据结构如下:
<Waybills>waybill<--><Clients>sender<--==><ClientsAddrs>senderAddrs[]

from w in _context.Waybills.Where(o => o.FlowID == 2 && o.SenderStationID == localStationId) 
join c in _context.Clients.Include(o => o.clientAddrs) on w.RecipientID equals c.Id 
select new { w.Id, c.Name, w.RecipientID, w.RecipientAddrNo, c.clientAddrs[w.RecipientAddrNo].CityId, c.clientAddrs[w.RecipientAddrNo].Address, w.SenderStationID }
).ToList(); ;

生成的sql如下

SELECT [w].[Id], [c].[Name], [w].[RecipientID], [w].[RecipientAddrNo], 
	  ( SELECT [c0].[CityId] 
    FROM [ClientsAddr] AS [c0]
    WHERE [c].[Id] = [c0].[ClientId]
    ORDER BY (select 1)//=order  by id
    OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as cityId,
	(select [c1].Address 
    FROM [ClientsAddr] AS [c1]
    WHERE [c].[Id] = [c1].[ClientId]
    ORDER BY (select 1)//=order by id
    OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as address
FROM [Waybills] AS [w] 
INNER JOIN [Clients] AS [c] ON [w].[RecipientID] = [c].[Id] where (w.FlowID=2 and w.SenderStationID=1)

上述代码能直接运行,且结果正确。但认真看上面的代码,其中:

 ( SELECT [c0].[CityId] 
    FROM [ClientsAddr] AS [c0]
    WHERE [c].[Id] = [c0].[ClientId]
    ORDER BY (select 1)
    OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as cityId,
    //只选择了<Client> ClientsAddr  库中,第RecipientAddrNo行数据的CityID字段;
	(select [c1].Address 
    FROM [ClientsAddr] AS [c1]
    WHERE [c].[Id] = [c1].[ClientId]
    ORDER BY (select 1)
    OFFSET [w].[RecipientAddrNo] ROWS FETCH NEXT 1 ROWS ONLY)as address
      //只选择了<Client> ClientsAddr  库中,第RecipientAddrNo行数据的Address字段;

其实是一ClientsAddr 库中同一条记录,且这两个字段(cityId和Address)均来自ClientsAddr,并满足以下条件

 (SELECT  [c0].[CityId] as cityId,[c0].[Address] as address
    FROM [ClientsAddr] AS [c0]
    WHERE [c].[Id] = [c0].[ClientId]
   and [c0].Id2=[w].[RecipientAddrNo]
   )

那么,能不能将两个子查询 合并为一个?但把两个字段合并时,出现错误:
消息 116,级别 16,状态 1,第 7 行
当没有用 EXISTS 引入子查询时,在选择列表中只能指定一个表达式。

原因分析

由于本例中,首先是Waybills库与收货人(Recipient)库Clients 进行一对一连接(on RecipientID=Clients.ID),再由Client 与ClientsAddr进行一对多条件连接(通过条件 [c].[Id] = [c0].[ClientId] and [c0].Id2=[w].[RecipientAddrNo],在EntityFramwork中,依据sql 语言要求,直接将linq 转化为

SELECT [w].[Id], [c].[Name], [w].[RecipientID], [w].[RecipientAddrNo] , 
	   (SELECT  [c0].[CityId] as cityId,[c0].[Address] as address
    FROM [ClientsAddr] AS [c0]
    WHERE [c].[Id] = [c0].[ClientId]
   and [c0].Id2=[w].[RecipientAddrNo]
   ),
   (SELECT  [c0].[Address] as address
    FROM [ClientsAddr] AS [c0]
    WHERE [c].[Id] = [c0].[ClientId]
   and [c0].Id2=[w].[RecipientAddrNo]
   )

FROM [Waybills] AS [w] 
INNER JOIN [Clients] AS [c] ON [w].[RecipientID] = [c].[Id] where (w.FlowID=2 and w.SenderStationID=1)

因在sqlserver 查询时,select a.f1…,b.f2… from a inner join b on a.fa=b.fb where exisits (select * from c where …) 或 select a.f1…,b.f2… from a inner join b on a.fa=b.fb where a.fc in (select * from c…) 多字段 select 子句只能出现 exists 或in 后面,因此 就只能将查询CityID 和Address两个字段的子句,分开为两个子句了。
这虽然是语法规定,但和想按照上述思路,一次查询一个子句能生成的结果,两个子句肯定效率要低。其中深层次的原因,也请数据库高手,在评论留言中说明。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值