C# Linq对实体复杂性的影响
我从Linq to entities开始,也许有人能给我们一些启示 我有两个表-Vizite父表和Angajivizite子表。我首先使用数据库,所以我使用Vizite.Id和Angajivizite.IdVizita创建了它们之间的关系 我需要从Vizite中获取行,如果DataStart或DataEnd字段为null,或者Angactivizite中的子记录计数为零,则另一个位字段必须为0。也就是说,如果Vizite没有从属记录,或者这些数据字段中的任何一个为空,则计算字段为0 到目前为止,我使用的linq工作正常。我使用的语法如下:C# Linq对实体复杂性的影响,c#,sql-server,entity-framework,linq,linq-to-entities,C#,Sql Server,Entity Framework,Linq,Linq To Entities,我从Linq to entities开始,也许有人能给我们一些启示 我有两个表-Vizite父表和Angajivizite子表。我首先使用数据库,所以我使用Vizite.Id和Angajivizite.IdVizita创建了它们之间的关系 我需要从Vizite中获取行,如果DataStart或DataEnd字段为null,或者Angactivizite中的子记录计数为零,则另一个位字段必须为0。也就是说,如果Vizite没有从属记录,或者这些数据字段中的任何一个为空,则计算字段为0 到目前为止,
var list = ctx.Vizite
.OrderBy(p => p.DataEnd != null && p.DataStart != null && p.AngajatiVizite.Count > 0)
.ThenBy(p => p.Data)
.Select(p => new
{
p.Id,
p.Numar,
p.Data,
p.DataStart,
p.DataEnd,
Programat = p.DataEnd != null && p.DataStart != null && p.AngajatiVizite.Count > 0
})
.ToList();
Linq生成的sql命令非常复杂,我不明白为什么它会如此复杂,有什么区别
我从linq那里得到的是:
SELECT
[Project6].[Numar] AS [Numar],
[Project6].[Id] AS [Id],
[Project6].[Data] AS [Data],
[Project6].[DataStart] AS [DataStart],
[Project6].[DataEnd] AS [DataEnd],
[Project6].[C2] AS [C1]
FROM ( SELECT
[Project5].[C1] AS [C1],
[Project5].[Id] AS [Id],
[Project5].[Numar] AS [Numar],
[Project5].[Data] AS [Data],
[Project5].[DataStart] AS [DataStart],
[Project5].[DataEnd] AS [DataEnd],
CASE WHEN ([Project5].[C2] > 0) THEN cast(1 as bit) WHEN ( NOT ([Project5].[C3] > 0)) THEN cast(0 as bit) END AS [C2]
FROM ( SELECT
[Project4].[C1] AS [C1],
[Project4].[Id] AS [Id],
[Project4].[Numar] AS [Numar],
[Project4].[Data] AS [Data],
[Project4].[DataStart] AS [DataStart],
[Project4].[DataEnd] AS [DataEnd],
[Project4].[C2] AS [C2],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[AngajatiVizite] AS [Extent5]
WHERE [Project4].[Id] = [Extent5].[IdVizita]) AS [C3]
FROM ( SELECT
[Project3].[C1] AS [C1],
[Project3].[Id] AS [Id],
[Project3].[Numar] AS [Numar],
[Project3].[Data] AS [Data],
[Project3].[DataStart] AS [DataStart],
[Project3].[DataEnd] AS [DataEnd],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[AngajatiVizite] AS [Extent4]
WHERE [Project3].[Id] = [Extent4].[IdVizita]) AS [C2]
FROM ( SELECT
CASE WHEN ([Project2].[C1] > 0) THEN cast(1 as bit) WHEN ( NOT ([Project2].[C2] > 0)) THEN cast(0 as bit) END AS [C1],
[Project2].[Id] AS [Id],
[Project2].[Numar] AS [Numar],
[Project2].[Data] AS [Data],
[Project2].[DataStart] AS [DataStart],
[Project2].[DataEnd] AS [DataEnd]
FROM ( SELECT
[Project1].[Id] AS [Id],
[Project1].[Numar] AS [Numar],
[Project1].[Data] AS [Data],
[Project1].[DataStart] AS [DataStart],
[Project1].[DataEnd] AS [DataEnd],
[Project1].[C1] AS [C1],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[AngajatiVizite] AS [Extent3]
WHERE [Project1].[Id] = [Extent3].[IdVizita]) AS [C2]
FROM ( SELECT
[Extent1].[Id] AS [Id],
[Extent1].[Numar] AS [Numar],
[Extent1].[Data] AS [Data],
[Extent1].[DataStart] AS [DataStart],
[Extent1].[DataEnd] AS [DataEnd],
(SELECT
COUNT(1) AS [A1]
FROM [dbo].[AngajatiVizite] AS [Extent2]
WHERE [Extent1].[Id] = [Extent2].[IdVizita]) AS [C1]
FROM [dbo].[Vizite] AS [Extent1]
) AS [Project1]
) AS [Project2]
) AS [Project3]
) AS [Project4]
) AS [Project5]
) AS [Project6]
当我真正需要的是:
Select
Vizite.Id
, Vizite.Numar
, Vizite.Data
, Vizite.DataStart
, Vizite.DataEnd
, Case
When DataStart != Null And DataEnd != Null And (Select Count(Id) From AngajatiVizite Where Vizite.Id = AngajatiVizite.IdVizita) > 0 Then 1
Else 0
End As Programat
From Vizite
Order By Programat, Data
有谁能向我解释一下,为什么生成的SQL如此复杂,甚至不可能通过简单地阅读SQL语法来理解它
谢谢如果执行以下操作,SQL语句的复杂性会发生什么变化
var list = ctx.Vizite
.Select(p => new
{
p.Id,
p.Numar,
p.Data,
p.DataStart,
p.DataEnd,
Programat =
p.DataEnd != null && p.DataStart != null && p.AngajatiVizite.Count > 0
}
.OrderBy(p => p.Programat)
.ThenBy(p => p.Data)
.ToList();
我希望不要重复p.DataEnd!=null&&p.DataStart!=null&&p.angajivizite.Count>0并移动OrderBy,然后在选择之后移动by,您将得到一个更简单的查询
编辑
为了进一步简化SQL,您可以选择在从数据库获取原始数据后执行一些工作:
var list = ctx.Vizite
.Select(p => new
{
p.Id,
p.Numar,
p.Data,
p.DataStart,
p.DataEnd,
AngajatiViziteCount = p.AngajatiVizite.Count
}
.AsEnumerable() // do the rest of the work using LINQ to objects
.OrderBy(p => p.DataEnd != null && p.DataStart != null && p.AngajatiViziteCount > 0)
.ThenBy(p => p.Data)
.ToList();
实体框架不会构建漂亮的查询,这是事实;有时这很麻烦,因为很难将SQL日志记录追溯到LINQ语句 但是,如果查询计划优化器不知道如何处理它们,这将是一个问题。幸运的是,就SQLServer而言,EF团队在EF5之后的每个版本中都设法使Sql更好地优化。因此,一般来说,您不应该太担心它,只有在性能比合理预期的更差时才开始研究它 不过,有一些经验法则。其中之一是只计算一次计算值。这就是let关键字派上用场的地方:
var list = (from p in ctx.Vizite
let Programat = p.DataEnd != null && p.DataStart != null
&& p.AngajatiVizite.Count > 0
order by Programat, p.Data
select new
{
p.Id,
p.Numar,
p.Data,
p.DataStart,
p.DataEnd,
Programat
}).ToList();
这在LINQ查询语法中运行良好。在fluent方法语法中,您可以执行完全相同的操作,但这需要两个后续Select语句。之所以如此复杂,是因为您在linq中使用逻辑来选择实体。如果您这样做,EF通常会生成一个SQL子查询,而不是CASE子句。@CodeNotFound:您能给我一个替代方案吗?我是初学者,正在努力解决这个问题。有更好的方法吗?除了调用一个存储过程(我现在实际上正在这么做)之外,感谢您的帮助:事实上,生成的sql不太复杂,但仍然太复杂,IMO。它在字段列表中有两个以上的选择。。。。我无法将其粘贴到这里,因为注释字段限制为500个字符:@GrigoreDolghin,我用另一个想法编辑了我的答案。如果您正在寻找一个可以粘贴到长SQL语句中的位置,我建议您编辑您的问题并在结尾添加任何新内容。非常感谢大家。你的回答对理解它的工作原理很有帮助。