Pregunta

¿Cómo se cargan de forma diferida listas anidadas sin ejecutar la consulta?Usando un ejemplo muy básico, digamos que tengo:

class CityBlock {
     IList<Building> BuildingsOnBlock;
     Person BlockOwner;
}

class Building {
     IList<Floor> FloorsInBuilding;
}

class Floor {
     IList<Cubicle> EmployeeCubicles;
}

Class Cubicle {
     System.Guid CubicleID;
     Person CubicleOccupant;
}

Y luego, en mi capa de repositorio, tengo el siguiente método:

GetCityBlocks()

Y luego, en la capa de Servicio, tendré GetCityBlocksByOwner, donde utilizo un método de extensión para que los bloques de la ciudad sean propiedad de una persona específica, digamos que solo queremos los bloques de Guido:

GetCityBlocks().ForOwner("Guido")

Si hacemos un .ToList() en el repositorio, ejecutará las consultas; eso será ridículo ya que no sabemos quiénes son los bloques que obtenemos en ese nivel.Entonces la pregunta es, ¿cómo hacemos esto de manera eficiente?

Supongamos que hay 50.000 propietarios de bloques y unos 1.000.000 de bloques de la ciudad, cargarlos todos no es una opción.El uso de IQueryables no funcionará debido al anidamiento (sin piratería extrema, al menos que yo sepa).Además, si intento usar algo como LazyList de Rob Conery, entonces esencialmente tenemos una fuga de nuestro DAL en nuestros modelos de dominio, lo que podría ser muy malo en el futuro.

Entonces, ¿cómo hago para hacer esto correctamente?

  • ¿Se trata de determinar el contexto correcto?Si es así, ¿haríamos esto en la capa de repositorio o en la capa de servicio?
  • ¿Meldico a medias la capa de servicio y mi capa de repositorio para obtener métodos de servicio muy específicos?
  • ¿O me estoy perdiendo algo por completo?(Todavía relativamente nuevo en la cosa de Linq2SQL, que se está eliminando de todos modos, así que ...)

Editar:En el patrón del repositorio, actualmente estamos asignando objetos a nuestros dominios, por lo que se vería así:

public IQueryable<CityBlock> GetCityBlocks(){
    var results = from o in db.city_blocks
                  let buildings = GetBuildingsOnBlock(o.block_id)
                  select new CityBlock {
                      BuildingsOnBlock = buildings,
                      BlockOwner = o.block_owner
                  };
    return results;
}

Para que esto funcione, tendríamos que hacer que los edificios obtengan un .ToList(), a menos que hagamos que ese campo real en el objeto CityBlock sea un IQueryable, lo cual no parece correcto, porque parece que se consumiría demasiada energía. otorgado a cualquier persona que acceda al campo CityBlock.BuildingsOnBlock.¿Es esta asignación a los objetos de nuestro dominio algo que tal vez deberíamos hacer en la capa de servicio?

¿Fue útil?

Solución

Lo hace mediante la devolución de IQueryables en lugar de ILists.

ToList () hace que las consultas para ejecutar inmediatamente, porque una conversión debe realizarse desde IQueryable a IList.

Mientras que usted está volviendo IQueryables carga diferida debe aplazar la ejecución hasta que realmente se necesitan los datos, es decir, cuando ToList () se llama.

No puedo encontrar una referencia en el momento, pero es mi entendimiento de que, si lo haces de esta manera, LINQ to SQL tiene la oportunidad de optimizar el SQL que envía al servidor. En otras palabras, que en última instancia leer estos registros:

GetCityBlocks().ForOwner("Guido")

en lugar de estos registros:

GetCityBlocks()

Otros consejos

Podrías probar un enfoque diferente al mapear los objetos de tu dominio para que funcione.El problema es que no importa lo que hagas (a menos que cambies tus listas a IQueryables en los objetos de tu dominio) terminarás haciendo ToList() mientras estás mapeando.

La otra forma es permitir que linq2Sql haga el mapeo a sus POCO creando un contexto de datos personalizado y sin usar el diseñador para el mapeo :), de esa manera mantiene limpio su modelo de dominio y deja que linq2Sql complete las dependencias en el momento correcto.Tenga en cuenta que seguir esta ruta tiene sus propios problemas, pero se puede hacer.

Aquí hay un enlace para comenzar en esta ruta.

Lograr POCO s en Linq to SQL

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top