8

estoy usando Entity Framework CodeFirst donde he utilizado las relaciones entre padres e hijos utilizando ICollection como¿AsQueryable() en ICollection realmente hace la ejecución floja?

public class Person 
{ 
    public string UserName { get;set} 
    public ICollection<Blog> Blogs { get; set;} 
} 

public class Blog 
{ 
    public int id { get; set; } 
    public string Subject { get; set; } 
    public string Body { get; set; } 
} 

Ok, hasta ahora todo está funcionando bien, pero mi preocupación es, cada vez que quiero conseguir los blogs de una persona, lo entiendo como

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault(); 
var theBlogs = thePerson.Blogs.OrderBy(id).Take(5); 

Ahora, entiendo que, cuando se ejecuta la línea, todos los blogs para que la persona se carga en la memoria y luego la clasificación y selección se hace de la memoria. Eso no es ideal para un registro de Persona que tiene una gran cantidad de blogs. Quiero que el Blog secundario sea IQueryable para que la ordenación y selección se realice en la base de datos SQL antes de pasar a Memoria.

Sé que podría declarar el blogs como IQueryable en mi contexto para poder consultar directamente como

var theBlogs = _context.Blogs.Where(.....) 

pero que no es factible para mí debido al diseño elección, quiero evitar cualquier referencia circular tanto como sea posible debido al problema de serialización. Entonces, no hice ninguna referencia de la entidad matriz en mi hijo.

me encontré con que, puedo llamar al método AsQueryable() en los blogs como

var theBlogs = thePerson.Blogs.AsQueryable().OrderBy(id).Take(5); 

que se ve como una magia para mí y parece demasiado bueno para ser verdad. Entonces mi pregunta. ¿AsQueryable realmente hace ICollection como IQueryable en realidad y hace que todo el proceso de consulta en SQL Server (carga lenta) O simplemente es un casting donde los blogs se cargan en la memoria como antes, pero cambiar la interfaz de ICollection a IQueryable?

+2

Este último, no el anterior. – Enigmativity

+0

Gracias - Enigmatividad, entonces mi sospecha era cierta entonces. es triste. –

Respuesta

6

De hecho, parece que escribir su propiedad de navegación como IQueryable<T>is not possible.

Lo que podría hacer es añadir una propiedad de navegación para Blog:

public class Blog 
{ 
    public int id { get; set; } 
    public string Subject { get; set; } 
    public string Body { get; set; } 
    public virtual Person Owner { get; set; } 
} 

partir de eso, se puede consultar la siguiente manera para que no se cargue todo en la memoria:

var thePerson = _context.Persons.Where(x => x.UserName = 'xxx').SingleOrDefault(); 
var results = _context.Blogs.Where(z => z.Person.Name = thePerson.Name).OrderBy(id).Take(5) 

Sugiero para probar LINQPad para ver cómo se traduce LINQ a SQL, y qué se solicita realmente de la base de datos.

+0

Muchas gracias por su respuesta. Ok, entonces ¿significa que ICollection también es un cargador lento como IQueryable y puedo usar ICollection de forma segura en lugar de IQueryable donde quiero que la consulta tenga lugar en la base de datos? Acerca de LINQPAD, creo que da una idea térmica sobre lo que es la traducción SQL, pero tal vez algún EntityFramework Profiler pueda ayudar a ver qué QUERY se está enviando en la base de datos. No tengo ningún perfilador de Entity Framework, pero ahora estoy buscando algunos productos como ese. –

+0

Solo otra pregunta, así que si la respuesta de mi pregunta anterior es SÍ, entonces, ya no necesito usar AsQueryable() para ICollection, ¿verdad? –

+1

+1 para recomendar una herramienta que facilita el desarrollo de consultas LINQ. –

2

Un mejor enfoque se describe en Ladislav's answer. En su caso:

var theBlogs = _context.Entry(thePerson) 
         .Collection(x => x.Blogs) 
         .Query() 
         .OrderBy(x => x.id) 
         .Take(5); 
Cuestiones relacionadas