LINQ生成带有重复嵌套选择的SQL

我是.NETentity framework的新手,我认为这很棒,但不知怎的,我得到了这个奇怪的问题(抱歉西class牙语,但我的程序是用那种语言,无论如何这不是什么大问题,只是列或属性名称):我正在进行正常的LINQ To Entities查询以获取UltimaConsulta列表,如下所示:

var query = from uc in bd.UltimasConsultas select uc; 

UltmasConsultas是一个观点,顺便说一句。 问题是LINQ正在为查询生成此SQL:

 SELECT [Extent1].[IdPaciente] AS [IdPaciente], [Extent1].[Nombre] AS [Nombre], [Extent1].[PrimerApellido] AS [PrimerApellido], [Extent1].[SegundoApellido] AS [SegundoApellido], [Extent1].[Fecha] AS [Fecha] FROM (SELECT [UltimasConsultas].[IdPaciente] AS [IdPaciente], [UltimasConsultas].[Nombre] AS [Nombre], [UltimasConsultas].[PrimerApellido] AS [PrimerApellido], [UltimasConsultas].[SegundoApellido] AS [SegundoApellido], [UltimasConsultas].[Fecha] AS [Fecha] FROM [dbo].[UltimasConsultas] AS [UltimasConsultas]) AS [Extent1] 

为什么LINQ生成嵌套的Select? 我从video和示例中想到,它为这种查询生成了正常的SQL选择。 我是否必须配置某些内容(实体模型是从向导生成的,因此它是默认配置)? 提前感谢您的回答。

要清楚,LINQ to Entities不会生成SQL。 相反,它会生成一个ADO.NET规范命令树,而数据库的ADO.NET提供程序(在这种情况下可能是SQL Server)会生成SQL。

那么为什么它会生成这个派生表(我认为“派生表”是这里使用的SQL特性的更正确的术语)? 因为生成SQL的代码必须为各种LINQ查询生成SQL,所以大多数LINQ查询并不像您显示的那样简单。 这些查询通常会选择多种类型的数据(其中许多类型可能是匿名的,而不是命名类型),并且为了使SQL生成相对合理,它们被分组为每种类型的范围。

另一个问题:你为什么要关心? 从性能的角度来看,很容易certificate在此语句中使用派生表是“免费的”。

我从填充的数据库中随机选择了一个表,并运行以下查询:

 SELECT [AddressId] ,[Address1] ,[Address2] ,[City] ,[State] ,[ZIP] ,[ZIPExtension] FROM [VertexRM].[dbo].[Address] 

我们来看看成本:

     

现在让我们将它与派生表的查询进行比较:

 SELECT [Extent1].[AddressId] ,[Extent1].[Address1] ,[Extent1].[Address2] ,[Extent1].[City] ,[Extent1].[State] ,[Extent1].[ZIP] ,[Extent1].[ZIPExtension] FROM (SELECT [AddressId] ,[Address1] ,[Address2] ,[City] ,[State] ,[ZIP] ,[ZIPExtension] FROM[VertexRM].[dbo].[Address]) AS [Extent1] 

而且费用:

     

在这两种情况下,SQL Server都只扫描聚集索引。 毫不奇怪,成本几乎完全相同。

我们来看一个稍微复杂一点的查询。 我启动了LINQPad,并针对同一个表输入了以下查询,以及一个相关的表:

 from a in Addresses select new { Id = a.Id, Address1 = a.Address1, Address2 = a.Address2, City = a.City, State = a.State, ZIP = a.ZIP, ZIPExtension = a.ZIPExtension, PersonCount = a.EntityAddresses.Count() } 

这会生成以下SQL:

 SELECT 1 AS [C1], [Project1].[AddressId] AS [AddressId], [Project1].[Address1] AS [Address1], [Project1].[Address2] AS [Address2], [Project1].[City] AS [City], [Project1].[State] AS [State], [Project1].[ZIP] AS [ZIP], [Project1].[ZIPExtension] AS [ZIPExtension], [Project1].[C1] AS [C2] FROM ( SELECT [Extent1].[AddressId] AS [AddressId], [Extent1].[Address1] AS [Address1], [Extent1].[Address2] AS [Address2], [Extent1].[City] AS [City], [Extent1].[State] AS [State], [Extent1].[ZIP] AS [ZIP], [Extent1].[ZIPExtension] AS [ZIPExtension], (SELECT COUNT(cast(1 as bit)) AS [A1] FROM [dbo].[EntityAddress] AS [Extent2] WHERE [Extent1].[AddressId] = [Extent2].[AddressId]) AS [C1] FROM [dbo].[Address] AS [Extent1] ) AS [Project1] 

通过分析,我们可以看到Project1是对匿名类型的投影Extent1Address表/实体。 Extent2是该关联的表。 现在没有Address派生表,但是有一个用于投影。

我不知道你是否编写过SQL生成系统,但这并不容易。 我认为certificateLINQ to Entities查询和SQL查询等效的一般问题是NP难的,尽管某些特定情况显然要容易得多。 SQL故意图灵不完整,因为它的设计者希望所有SQL查询在有限的时间内执行。 LINQ,不是这样。

简而言之,这是一个非常难以解决的问题,entity framework及其提供者的组合有时会牺牲一些可读性,有利于在各种查询中保持一致性。 但它不应该是性能问题。

基本上它定义了Extent1的组成以及与每个条目相关的变量。 然后将实际数据库表映射到Extent1,以便它可以返回该表的所有条目。

这是您的查询所要求的。 它只是LINQ无法添加通配符,就像你手动完成它一样。