2012-07-23 16 views
8

con la siguiente estructura de la tabla (columnas extraños eliminados)incluir y donde la causa predicado combinación izquierda en lugar de combinación interna

create table [Events] 
(
    ID int not null identity, 
    Name nvarchar(128) not null, 
    constraint PK_Events primary key(ID) 
) 

create table [Donations] 
(
    ID int not null identity, 
    EventID int not null, 
    Amount decimal(10, 2) not null, 

    constraint PK_Donations primary key(ID), 
    constraint FK_Donations_Events foreign key(EventID) references [Events](ID) on update no action on delete no action 
) 

yo uso las siguientes LINQ a Entidades consultas:

// 1 
ents.Donations.Where(d => d.Amount > 25.0m && d.Event.Name.Contains("Run")).ToList(); 

// 2 
ents.Donations.Include("Event").Where(d => d.Amount > 25.0m).ToList(); 

// 3 
ents.Donations.Include("Event").Where(d => d.Amount > 25.0m && d.Event.Name.Contains("Run")).ToList(); 

Produce (a partir de un Analizador de SQL):

-- 1 
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount] 
FROM [dbo].[Donations] AS [Extent1] 
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID] 
WHERE ([Extent1].[Amount] > 25.0) AND ([Extent2].[Name] LIKE N'%Run%') 

-- 2 
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount], 
[Extent2].[ID] AS [ID1], 
[Extent2].[Name] AS [Name] 
FROM [dbo].[Donations] AS [Extent1] 
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID] 
WHERE [Extent1].[Amount] > 25.0 

-- 3 
SELECT 
[Extent1].[ID] AS [ID], 
[Extent1].[EventID] AS [EventID], 
[Extent1].[Amount] AS [Amount], 
[Extent3].[ID] AS [ID1], 
[Extent3].[Name] AS [Name] 
FROM [dbo].[Donations] AS [Extent1] 
INNER JOIN [dbo].[Events] AS [Extent2] ON [Extent1].[EventID] = [Extent2].[ID] 
LEFT OUTER JOIN [dbo].[Events] AS [Extent3] ON [Extent1].[EventID] = [Extent3].[ID] 
WHERE ([Extent1].[Amount] > 25.0) AND ([Extent2].[Name] LIKE N'%Run%') 

¿por qué en la consulta tercero, ¿genera una LEFT OUTER JOIN en la tabla Events por segunda vez? Si bien la consulta produce resultados correctos, parece extraño, ¿por qué EF/LINQ no puede reutilizar [Extent2] en la cláusula SELECT y WHERE, y por qué es LEFT OUTER JOIN?

Estoy usando Visual Studio 2010 sp1 .NET 4 y me estoy conectando a Sql Server 2008 Express.

Respuesta

6

La combinación de la izquierda sería garantizar que no faltan filas en la tabla de Donaciones en el caso de que una donación apunte a un evento que no existe. No quieren que la palabra clave Incluir tenga el efecto secundario de hacer que falten filas en la tabla original, por lo que deben usar una combinación izquierda para mayor seguridad.

Con respecto a la inclusión de la tabla dos veces, esta es probablemente solo una limitación de EF. Lo menciona dos veces en su consulta y no es lo suficientemente inteligente como para hacer la optimización.

Debo decir que si quiere optimizar SQL, escriba SQL, no se moleste con EF. Lo que está haciendo podría compararse con descompilar C# y preguntar por qué el ensamblador no tiene una cierta optimización. Si utiliza EF luego cerró los ojos a lo que produce SQL :-)

+1

La segunda consulta usa 'Include' pero no produce una combinación left. – Matthew

+0

Muy buena pregunta, no me di cuenta. Esto parece estar de vuelta para mí. La segunda consulta debe tener una combinación a la izquierda para que Include no cause efectos secundarios y la tercera consulta debería tener una combinación interna, ya que necesita una fila de evento de todos modos. – MikeKulls

+0

Una combinación a la izquierda tendría sentido si fuera una columna con posibilidad de nulos, o si no tuviera integridad referencial en ella. – Matthew

0

respuesta no directa a su pregunta, sino un intento de apuntar en la dirección correcta después de leer sus comentarios de las otras respuestas:

Tienes todo lo que necesitas para defender el uso de ORM (incluido EF): eso es todo lo que dijiste sobre la cantidad y calidad de los SP. Cualquier enfoque tendrá problemas, incluyendo sql puro, si ese sql no está bien escrito o es difícil de mantener.

Por lo tanto, si algunas ORM (EF, etc.) a veces producen código no eficiente, y esto realmente causa problemas de rendimiento, esto se convierte en "requisito" y debe ser resuelto, incluso utilizando SP.

Por lo tanto, observe sus problemas desde el punto de vista empresarial: tiene muchos procedimientos almacenados mal estructurados y difíciles de mantener. Probablemente, la mayoría de su equipo es C# y no desarrolladores de SQL.

El uso de ORM aumentará la capacidad de mantenimiento de la base de códigos, y permitirá un mejor uso de la experiencia de todos los miembros del equipo en C#.

El código de SQL incorrecto, producido por ORM en algunas ocasiones específicas, difícilmente es "obsoleto" para usar la tecnología, a menos que se demuestre que creará más problemas que resolver los existentes.

+0

Me gustaría mirar al revés. Si los desarrolladores no tienen experiencia en sql, entonces necesitan tener experiencia. Están escribiendo aplicaciones de base de datos después de todo y la falta de conocimiento de SQL es inaceptable en estos días. La única cosa que * no * necesitan es más razones para evitar sql. – MikeKulls

+0

Definitivamente no son inexpertos en SQL, la aplicación ha pasado ~ 9 años de desarrollo constante (comenzó con ASP.net 1.0), muchos desarrolladores diferentes. La aplicación tal como está ahora no tiene separación de preocupaciones, los procesos almacenados se llaman directamente dentro del código subyacente. Es por eso que estoy buscando algo que sea muy fácil de administrar, sobre todo porque creo que la organización de los procesos almacenados en este momento es un castigo. – Matthew

Cuestiones relacionadas