Myl*_*les 3 c# linq entity-framework entity-framework-6
我有一个用于替换数据库函数的 Linq 查询。这是第一个有多个连接的,我似乎无法弄清楚为什么它返回 0 结果。
如果您能看到任何可能导致错误返回的差异,将不胜感激......我一直在尝试解决它的时间比我应该有的时间更长。
Linq 查询
context.StorageAreaRacks
.Join(context.StorageAreas, sar => sar.StorageAreaId, sa => sa.Id, (sar, sa) => new { sar, sa })
.Join(context.StorageAreaTypes, xsar => xsar.sar.StorageAreaId, sat => sat.Id, (xsar, sat) => new { xsar, sat })
.Join(context.Racks, xxsar => xxsar.xsar.sar.RackId, r => r.Id, (xxsar, r) => new { xxsar, r })
.Where(x => x.xxsar.sat.IsManual == false)
.Where(x => x.r.IsEnabled == true)
.Where(x => x.r.IsVirtual == false)
.Select(x => new { x.xxsar.sat.Id, x.xxsar.sat.Name })
.Distinct()
.ToList();
Run Code Online (Sandbox Code Playgroud)
这是由 LINQ 查询生成的查询
SELECT
[Distinct1].[C1] AS [C1],
[Distinct1].[Id] AS [Id],
[Distinct1].[Name] AS [Name]
FROM ( SELECT DISTINCT
[Extent2].[Id] AS [Id],
[Extent2].[Name] AS [Name],
1 AS [C1]
FROM [dbo].[StorageAreaRacks] AS [Extent1]
INNER JOIN [dbo].[StorageAreaTypes] AS [Extent2] ON [Extent1].[StorageAreaId] = [Extent2].[Id]
INNER JOIN [dbo].[Racks] AS [Extent3] ON [Extent1].[RackId] = [Extent3].[Id]
WHERE (0 = [Extent2].[IsManual]) AND (1 = [Extent3].[IsEnabled]) AND (0 = [Extent3].[IsVirtual])
) AS [Distinct1]
Run Code Online (Sandbox Code Playgroud)
生成所需结果的 Sql 查询
SELECT DISTINCT sat.Name, sat.Id
FROM StorageAreaRacks sar
JOIN StorageAreas sa on sa.id = sar.StorageAreaId
JOIN StorageAreaTypes sat on sat.id = sa.StorageAreaTypeId
JOIN Racks r on r.id = sar.RackId
WHERE sat.IsManual = 0
AND r.IsEnabled = 1
AND r.IsVirtual = 0
Run Code Online (Sandbox Code Playgroud)
将连接与 LINQ 方法语法一起使用很难阅读并且容易出错。
将连接与 LINQ 查询语法一起使用会更好,但仍然容易出错(您可以像以前一样使用错误的键进行连接)并且不会为您提供有关连接基数的信息。
LINQ to Entities 查询的最佳方式是使用导航属性(正如 Gert Arnold 在评论中所建议的,而不仅仅是 - 请参阅不要使用 Linq 的连接。导航!),因为它们没有上述缺点。
整个查询应该是这样的:
var query = context.StorageAreaRacks
.Where(sar => !sar.StorageArea.StorageAreaType.IsManual
&& sar.Rack.IsEnabled && !sar.Rack.IsVirtual)
.Select(sar => new
{
sar.StorageArea.StorageAreaType.Id,
sar.StorageArea.StorageAreaType.Name,
})
.Distinct();
Run Code Online (Sandbox Code Playgroud)
或者
var query = (
from sar in context.StorageAreaRacks
let sat = sar.StorageArea.StorageAreaType
let r = sar.Rack
where !sat.IsManual && r.IsEnabled && !r.IsVirtual
select new { sat.Id, sat.Name })
.Distinct();
Run Code Online (Sandbox Code Playgroud)
简单,可读,几乎没有错误的地方。导航属性是 EF 最漂亮的功能之一,不要错过它们。
您的 LINQ 无法正确翻译 SQL;它Join
是StorageAreaTypes
on theStorageAreaRack.StorageAreaId
而不是 on the StorageAreas.StorageAreaTypeId
,这就是 EF 放弃 the 的原因StorageAreas
Join
- 它对结果没有影响。
我认为,如果您提升每个联接的成员以展平匿名对象并根据其成员(即联接表)命名它们,那就更清楚了。另外,没有理由分隔Where
子句,LINQ 可以使用&&
,SQL 也可以使用AND
. 另外,如果您有布尔值,请勿将它们与true
or进行比较false
。此外,没有理由传递稍后不使用的范围变量。
把它们放在一起:
var ans = context.StorageAreaRacks
.Join(context.StorageAreas, sar => sar.StorageAreaId, sa => sa.Id, (sar, sa) => new { sar, sa })
.Join(context.StorageAreaTypes, sarsa => sarsa.sa.StorageAreaTypeId, sat => sat.Id, (sarsa, sat) => new { sarsa.sar, sat })
.Join(context.Racks, sarsat => sarsat.sar.RackId, r => r.Id, (sarsat, r) => new { sarsat.sat, r })
.Where(satr => !satr.sat.IsManual && satr.r.IsEnabled && !satr.r.IsVirtual)
.Select(satr => new { satr.sat.Id, satr.sat.Name })
.Distinct()
.ToList();
Run Code Online (Sandbox Code Playgroud)
不过,我认为当涉及到多个连接以及翻译 SQL 时,LINQ 理解语法可以更容易理解:
var ans = (from sar in context.StorageAreaRacks
join sa in context.StorageAreas on sar.StorageAreaId equals sa.Id
join sat in context.StorageAreaTypes on sa.StorageAreaTypeId equals sat.Id
join r in context.Racks on sar.RackId equals r.Id
where !sat.IsManual && r.IsEnabled && !r.IsVirtual
select new {
sat.Name,
sat.Id
}).Distinct().ToList();
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2227 次 |
最近记录: |