8

tengo un método en mi clase parcial generada de esta manera:Saltee() Tomar() en las propiedades de navegación Entity Framework está ejecutando SELECT * en mi SQL Server

var pChildren = this.Children 
    .Skip(skipRelated) 
    .Take(takeRelated) 
    .ToList(); 

Cuando miro mi SQL Server , Puedo ver que el código generado está haciendo un SELECT *.* FROM Children Este código es tomado directamente de mi clase, he verificado que el orden de mi Omitir/Tomar es ANTES de mi .ToList.

Si quito el .ToList, esa línea es rápido (y sin SQL se envía a mi DB), pero en el momento que intento foreach sobre los resultados, me sale el mismo SQL enviada a mi DB: SELECT *.* FROM Children.

¿Hay algo especial que deba hacer al usar .Skip y .Take en las propiedades de navegación de mis entidades?

actualización

Voy a tratar de obtener el SQL real generada, no estoy actualmente configurado para ello. Encontré el primero porque aparece en la lista de "consultas recientemente caras" de SSMS.

La ejecución de este:

var pChildren = this.Children 
    //.Skip(skipRelated) 
    //.Take(takeRelated) 
    .ToList(); 

vuelve ~ 4.000.000 filas y tarda unos 25 segundos.

La ejecución de este:

var pChildren = this.Children 
    //.Skip(skipRelated) 
    .Take(takeRelated) 
    .ToList(); 

vuelve ~ 4.000.000 filas y tarda unos 25 segundos.

Como dije, tomaré el SQL generado para estos y los presentaré también.

+0

Lo SQL esperabas este código para generar? – cdhowie

+0

Esperaba algo así como 'SELECCIONAR TOP 10 FROM Children DONDE ParentID = @ idOfParentEntity' (Olvidé cómo EF maneja .Skip, pero he leído que se supone que lo haga. Si ejecuté esta consulta directamente contra mi contexto, parece que limite los datos devueltos a una "página" específica) – Nate

+0

La presencia de '.Skip()' impide el uso de 'TOP'. A menos que esperara que sumara 'skipRelated' y' takeRelated' y lo utilizara como parámetro para 'TOP' ... lo cual podría ser una optimización, pero también podría no tener impacto en el rendimiento. – cdhowie

Respuesta

7

El problema es que se está llevando a cabo una consulta LINQ a objetos cuando se consulta una colección infantil de esa manera. EF cargará toda la colección y realizará la consulta en la memoria.

Si está utilizando EF 4 se puede consultar como esto

var pChildren = this.Children.CreateSourceQuery() 
       .OrderBy(/* */).Skip(skipRelated).Take(takeRelated); 

En EF 4,1

var pChildren = context.Entry(this) 
        .Collection(e => e.Children) 
        .Query() 
        .OrderBy(/* */).Skip(skipRelated).Take(takeRelated) 
        .Load(); 
+0

Exactamente lo que necesitaba. Estoy usando EF4.1 pero la primera consulta funciona mejor para mí, ya que no tengo acceso a mi contexto desde este método específico. – Nate

1

¿Ayuda si llama al Skip en el resultado de Take? es decir,

table.Take(takeCount+skipCount).Skip(skipCount).ToList() 

También, ver

+5

tomar antes de omitir no tiene sentido – vittore

+1

@vittore: Claro que sí. Si desea registros 51-100, en lugar de agarrar un millón para el cliente, tirar 50, mantener 50 y tirar el resto, puede agarrar 100 al cliente y tirar 50. –

+0

@BenVoigt Si bien eso es cierto, no ayuda tanto como llegar a la última de las páginas. – Nate

Cuestiones relacionadas