2009-02-07 29 views
14

He visto numerosos ejemplos de carga lenta: ¿cuál es tu elección?Carga lenta: ¿cuál es el mejor enfoque?

dado una clase de modelo, por ejemplo:

public class Person 
{ 
    private IList<Child> _children; 
    public IList<Child> Children 
    { 
     get { 
      if (_children == null) 
       LoadChildren(); 
      return _children; 
     } 
    } 
} 

La clase de persona no debe saber nada acerca de la forma en que los niños son cargado .... o debería? Seguramente debería controlar cuando las propiedades están pobladas, o no?

¿Tendría un repositorio que combina una persona con su colección de hijos o utilizaría un enfoque diferente, como utilizar una clase lazyload? Incluso entonces, no quiero una clase diferida borrosa en la arquitectura de mi modelo.

¿Cómo manejarías el rendimiento si primero solicitaste una Persona y luego sus Hijos (es decir, no cargas perezosas en esta instancia) o de alguna manera la carga es floja?

¿Todo esto se reduce a una elección personal?

+0

Problema: este es a menudo un gran ejemplo de optimización local a expensas de la optimización global. – dkretz

Respuesta

14

La mejor carga diferida es evitarlo;) La seguridad del hilo es un problema inmediato que tendrás que manejar. No tengo en cuenta la frecuencia con la que he visto que los sistemas de producción con 8 núcleos de CPU funcionan con carga lenta 8 veces para cada patrón de carga diferida en uso. Al menos en los inicios del servidor, todos los núcleos del servidor tienden a terminar en los mismos lugares.

Deje que un marco DI lo construya para usted, si puede. Y si no puedes, todavía prefiero la construcción explícita. Entonces, todo tipo de magia de AOP simplemente no me cortan, vaya a una construcción explícita fuera de la clase. No lo pongas dentro de la clase de persona, solo haz un servicio que construya los objetos de la manera adecuada.

Presentamos capas "mágicas" que hacen más o menos transparentemente estas cosas parecen como una buena idea, pero todavía tengo que encontrarme con implementaciones que no tienen consecuencias imprevistas y problemáticas.

+0

Gracias por su tiempo, ¿puede dar más detalles sobre el uso de un marco DI y una construcción explícita? –

+0

Creo que estaba diciendo que tener la clase Person crea explícitamente los hijos (con LoadChildren() presumiblemente) durante su propia inicialización no deja ninguna duda en cuanto al estado de _children. Y Dependency Injection, bueno, hay muchos hilos aquí que son mejores que yo en un comentario. – JMD

+0

Además, pierde la atomicidad de la consulta. Y la mayoría de las veces, la estrategia global más eficiente es emitir una sola consulta con uniones (externas) para los registros secundarios y obtener todo en una transacción, en lugar de distribuirla entre múltiples hits secundarios de la base de datos. – dkretz

0

Estoy pensando que esto es precisamente el tipo de problema que es mejor manejado por AOP (por ejemplo, PostSharp). Ten la carga floja como un aspecto y luego úsala para decorar cualquier propiedad que quieras cargar perezosamente. Descargo de responsabilidad: no lo he probado; solo pensando que es debería funcionar.

1

me hablaron de una solución que utilizo para llevar a cabo la carga diferida here

+0

Gracias por su tiempo, ¿no se trata de otra dependencia? Aunque estoy interesado en el enfoque. –

1

Puede usar el patrón Virtual Proxy, junto con el Observer pattern. Esto le daría cargas perezosas sin que la clase Persona tenga conocimiento explícito sobre cómo se cargan los Niños.

0

Acabo de hacer una pregunta relacionada here, pero fue más pesada en la inmutabilidad & Tachuela de seguridad del hilo. Muchas buenas respuestas y comentarios. Lo podrías encontrar útil.

0

Aquí es un ejemplo la implementación de carga diferida utilizando el patrón Proxy

La clase de persona que vive con el resto de sus modelos. Children se marca como virtual, por lo que se puede anular dentro de la clase PersonProxy.

public class Person { 
    public int Id; 
    public virtual IList<Child> Children { get; set; } 
} 

La clase PersonRepository que conviviría con el resto de sus repositorios. Incluí el método para incluir a los niños en esta clase, pero podrías tenerlo en una clase ChildRepository si quisieras.

public class PersonRepository { 
    public Person FindById(int id) { 
     // Notice we are creating PersonProxy and not Person 
     Person person = new PersonProxy(); 

     // Set person properties based on data from the database 

     return person; 
    } 

    public IList<Child> GetChildrenForPerson(int personId) { 
     // Return your list of children from the database 
    } 
} 

La clase PersonProxy que vive con sus repositorios. Esto hereda de Person y hará la carga diferida. También podría usar un booleano para verificar si ya se ha cargado en lugar de verificar si Children == null.

public class PersonProxy : Person { 
    private PersonRepository _personRepository = new PersonRepository(); 

    public override IList<Child> Children { 
     get { 
      if (base.Children == null) 
       base.Children = _personRepository.GetChildrenForPerson(this.Id); 

      return base.Children; 
     } 
     set { base.Children = value; } 
    } 
} 

Puedes usarla como tal

Person person = new PersonRepository().FindById(1); 
Console.WriteLine(person.Children.Count); 

Por supuesto que podría tener PersonProxy tomar en una interfaz para el PersonRepository y accede a todo a través de un servicio si no desea llamar la PersonRepository directamente.

Cuestiones relacionadas