2009-04-27 11 views
44

Si utilizo una combinación, la incluyen() método ya no es de trabajo, por ejemplo:Linq-to-entidades - Incluir método() no cargar

from e in dc.Entities.Include("Properties") 
join i in dc.Items on e.ID equals i.Member.ID 
where (i.Collection.ID == collectionID) 
select e 

e.Properties no está cargado

Sin la unirse, el include() funciona

Lee

+0

¿Por qué crees que es así? ¿Ustedes lo valoran después de la ejecución? – pocheptsov

+0

Supongo que "Propiedades" no es la cadena real que está pasando a Incluir. Esto significa que ha omitido la parte más importante de la pregunta. Además, me pregunto por qué estás usando join en absoluto; las propiedades de navegación son generalmente la forma correcta de atravesar las relaciones en Entity Framework. –

+0

pocheptsov - Sé que Propiedades no se ha cargado porque Proeprties.IsLoaded es falso Hola Craig - "Propiedades" es la cadena correcta. La unión está en una propiedad de navegación diferente Elementos. La unión está ahí porque tengo un valor para una propiedad de un objeto Item (Collection.ID) pero quiero una entidad que esté relacionada con ella. Lee –

Respuesta

54

ACTUALIZACIÓN: En realidad, recientemente agregué otro consejo que cubre esto, y proporciona una solución alternativa probablemente mejor. La idea es retrasar el uso de include() hasta el final de la consulta, ver esto para más información: Tip 22 - How to make include really include limitación


Se conoce en el marco de la entidad cuando se utiliza include(). Ciertas operaciones simplemente no son compatibles con Include.

Parece que es posible que se han topado con uno de esas limitaciones, para evitar este debe intentar algo como esto:

var results = 
    from e in dc.Entities //Notice no include 
    join i in dc.Items on e.ID equals i.Member.ID 
    where (i.Collection.ID == collectionID) 
    select new {Entity = e, Properties = e.Properties}; 

Esto traerá de vuelta a las propiedades, y si la relación entre la entidad y Propiedades está una relación uno a muchos (pero no una de muchos a muchos) encontrará que cada tipo anónimo resultante tiene los mismos valores en:

anonType.Entity.Properties 
anonType.Properties 

Este es un efecto secundario de una característica en el marco de la entidad denominada relación de corrección.

Consulte este Tip 1 en mi EF Tips series para obtener más información.

+0

excelente respuesta, gracias por su ayuda – ChrisHDog

+1

¿Sigue siendo así? Si usa un "seleccionar nuevo elemento {...};" la declaración .Include() no funciona? – grimus

+0

@grimus, al envolver toda la consulta en un 'Include' no parece funcionar actualmente cuando el tipo de elemento producido por la consulta no es un tipo de entidad. Sin embargo, la sugerencia original de obtener los valores de propiedad de navegación dentro de la cláusula 'select' todavía parece funcionar para eludir esto. – Sam

0

Pruebe la forma más detallada a hacer más o menos lo mismo obtener los mismos resultados, pero con más llamadas de datos:

var mydata = from e in dc.Entities 
      join i in dc.Items 
       on e.ID equals i.Member.ID 
      where (i.Collection.ID == collectionID) 
      select e; 

foreach (Entity ent in mydata) { 
    if(!ent.Properties.IsLoaded) { ent.Properties.Load(); } 
} 

¿Todavía obtiene el mismo resultado (inesperado)?

EDIT: Cambió la primera oración, ya que era incorrecta. Gracias por el comentario del puntero!

+0

Eso no es en modo alguno lo mismo. Su código dará como resultado n + 1 consultas de base de datos, donde n es el número de filas recuperadas. Incluir resultados en 1 consulta de base de datos. –

+0

Sé que no estoy haciendo lo mismo, era una manera descuidada de decir que terminaría con los mismos resultados. La razón principal para hacer esto fue ver si habría propiedades cargadas de esta manera. Si no, el problema no es probable en la sintaxis .Include(), sino más bien en los datos (donde pueden faltar registros de propiedad asociados, por ejemplo ...). –

+0

Hola Tomas Si cargo las Propiedades usando Properties.Load(), las carga correctamente. Si uso Incluir ("Propiedades") en una consulta que no incluye una unión, p.: desde e en dc.Entities.Include ("Propiedades") donde (e.ID = id) seleccione e; funciona bien. Lee –

4

Entonces, ¿cuál es el nombre de la propiedad de navegación en "Entidad" que se relaciona con "Item.Member" (es decir, es el otro extremo de la navegación). Deberías usar esto en lugar de la unión. Por ejemplo, si "entidad" añadir una propiedad llamada miembro con la cardinalidad de 1 y miembros tenían una propiedad denominada Los elementos con una cardinalidad de muchos, usted puede hacer esto:

from e in dc.Entities.Include("Properties") 
where e.Member.Items.Any(i => i.Collection.ID == collectionID) 
select e 

supongo en las propiedades de su modelo aquí, pero esto debería darle la idea general. En la mayoría de los casos, usar join en LINQ to Entities es incorrecto, porque sugiere que sus propiedades de navegación no están configuradas correctamente o que usted no las está usando.

20

Prueba esto:

var query = (ObjectQuery<Entities>)(from e in dc.Entities 
      join i in dc.Items on e.ID equals i.Member.ID 
      where (i.Collection.ID == collectionID) 
      select e) 

return query.Include("Properties") 
1

Por lo tanto, se dan cuenta de que estoy tarde a la fiesta aquí, sin embargo pensé que me gustaría añadir mis hallazgos.Esto realmente debería ser un comentario en la publicación de Alex James, pero como no tengo la reputación, tendrá que ir aquí.

Así que mi respuesta es: parece que no funciona en absoluto como sería su intención. Alex James ofrece dos soluciones interesantes, sin embargo, si las pruebas y compruebas el SQL, es horrible.

El ejemplo que estaba trabajando es:

 var theRelease = from release in context.Releases 
         where release.Name == "Hello World" 
         select release; 

     var allProductionVersions = from prodVer in context.ProductionVersions 
            where prodVer.Status == 1 
            select prodVer; 

     var combined = (from release in theRelease 
         join p in allProductionVersions on release.Id equals p.ReleaseID 
         select release).Include(release => release.ProductionVersions);    

     var allProductionsForChosenRelease = combined.ToList(); 

Esto sigue a la más simple de las dos ejemplos. Sin incluirla produce el sql perfectamente respetable:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name] 
    FROM [dbo].[Releases] AS [Extent1] 
    INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID] 
    WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status]) 

Pero con, OMG:

SELECT 
[Project1].[Id1] AS [Id], 
[Project1].[Id] AS [Id1], 
[Project1].[Name] AS [Name], 
[Project1].[C1] AS [C1], 
[Project1].[Id2] AS [Id2], 
[Project1].[Status] AS [Status], 
[Project1].[ReleaseID] AS [ReleaseID] 
FROM (SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Name] AS [Name], 
    [Extent2].[Id] AS [Id1], 
    [Extent3].[Id] AS [Id2], 
    [Extent3].[Status] AS [Status], 
    [Extent3].[ReleaseID] AS [ReleaseID], 
    CASE WHEN ([Extent3].[Id] IS NULL) THEN CAST(NULL AS int) ELSE 1 END AS [C1] 
    FROM [dbo].[Releases] AS [Extent1] 
    INNER JOIN [dbo].[ProductionVersions] AS [Extent2] ON [Extent1].[Id] = [Extent2].[ReleaseID] 
    LEFT OUTER JOIN [dbo].[ProductionVersions] AS [Extent3] ON [Extent1].[Id] = [Extent3].[ReleaseID] 
    WHERE ('Hello World' = [Extent1].[Name]) AND (1 = [Extent2].[Status]) 
) AS [Project1] 
ORDER BY [Project1].[Id1] ASC, [Project1].[Id] ASC, [Project1].[C1] ASC 

basura total. El punto clave a tener en cuenta aquí es el hecho de que devuelve la versión unida externa de la tabla que no ha sido limitada por el estado = 1.

Esto hace que los datos erróneos que se devuelven:

Id Id1 Name  C1 Id2 Status ReleaseID 
2 1 Hello World 1 1 2  1 
2 1 Hello World 1 2 1  1 

Tenga en cuenta que el estado de las 2 está siendo devuelto allí, a pesar de nuestra restricción. Simplemente no funciona. Si me he equivocado en alguna parte, estaría encantado de descubrirlo, ya que esto es una burla a Linq. Me encanta la idea, pero la ejecución no parece ser utilizable en este momento.


Por curiosidad, probé el LinqToSql DBML en lugar de la edmx LinqToEntities que produjo el desastre anterior:

SELECT [t0].[Id], [t0].[Name], [t2].[Id] AS [Id2], [t2].[Status], [t2].[ReleaseID], (
    SELECT COUNT(*) 
    FROM [dbo].[ProductionVersions] AS [t3] 
    WHERE [t3].[ReleaseID] = [t0].[Id] 
    ) AS [value] 
FROM [dbo].[Releases] AS [t0] 
INNER JOIN [dbo].[ProductionVersions] AS [t1] ON [t0].[Id] = [t1].[ReleaseID] 
LEFT OUTER JOIN [dbo].[ProductionVersions] AS [t2] ON [t2].[ReleaseID] = [t0].[Id] 
WHERE ([t0].[Name] = @p0) AND ([t1].[Status] = @p1) 
ORDER BY [t0].[Id], [t1].[Id], [t2].[Id] 

ligeramente más compacto - Cláusula de recuento raro, pero en general misma FALLO total.

¿Alguien ha usado alguna vez esto en una aplicación comercial real? Realmente me estoy empezando a preguntar ... Por favor, dime que me he perdido algo obvio, ¡ya que realmente me gustaría Linq!

Cuestiones relacionadas