5

he implementado el modelo de especificación con LINQ como se describe aquí https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layerUsando carga ansiosos con el patrón de especificación

ahora quiero añadir la capacidad de carga con ganas y estoy seguro sobre la mejor manera de hacerlo.

La clase repositorio genérico en el ejemplo enlazado:

public IEnumerable<T> FindAll(Specification<T> specification) 
{ 
    var query = GetQuery(specification); 
    return Transact(() => query.ToList()); 
} 

public T FindOne(Specification<T> specification) 
{ 
    var query = GetQuery(specification); 
    return Transact(() => query.SingleOrDefault()); 
} 

private IQueryable<T> GetQuery(
    Specification<T> specification) 
{ 
    return session.Query<T>() 
    .Where(specification.IsSatisfiedBy()); 
} 

Y la aplicación de especificación:

public class MoviesDirectedBy : Specification<Movie> 
{ 

private readonly string _director; 

public MoviesDirectedBy(string director) 
{ 
    _director = director; 
} 

public override 
    Expression<Func<Movie, bool>> IsSatisfiedBy() 
{ 
    return m => m.Director == _director; 
} 
} 

Esto está funcionando bien, ahora quiero añadir la habilidad de ser capaz de cargar con ganas . Entiendo que la carga ansiosa de NHibernate se puede hacer usando Fetch en la consulta.

Lo que estoy buscando es si encapsular la lógica de carga ansiosa dentro de la especificación o pasarla al repositorio, y también la sintaxis del árbol de expresiones/Linq requerida para lograr esto (es decir, un ejemplo de cómo se haría))

Respuesta

3

Una posible solución sería la de extender la clase Especificación para agregar:

public virtual IEnumerable<Expression<Func<T, object>>> FetchRelated 
{ 
    get 
    { 
     return Enumerable.Empty<Expression<Func<T, object>>>(); 
    } 
} 

Y cambiar GetQuery a algo como:

 return specification.FetchRelated.Aggregate(
      session.Query<T>().Where(specification.IsSatisfiedBy()), 
      (current, related) => current.Fetch(related)); 

Ahora todo lo que tiene que hacer es anular FetchRelated cuando sea necesario

public override IEnumerable<Expression<Func<Movie, object>>> FetchRelated 
{ 
    get 
    { 
     return new Expression<Func<Movie, object>>[] 
        { 
         m => m.RelatedEntity1, 
         m => m.RelatedEntity2 
        }; 
    } 
} 

Una limitación importante de esta implementación que acabo de escribir es t Solo puede obtener entidades directamente relacionadas con la entidad raíz.

Una mejora sería apoyar niveles arbitrarios (utilizando ThenFetch), lo que requeriría algunos cambios en la forma en que trabajamos con los genéricos (utilicé object para permitir la combinación de diferentes tipos de entidades fácilmente)

+0

Sin duda es una solución, pero eso es una mezcla de responsabilidades (encapsulando las estrategias de consulta y recuperación). Esta es la razón por la cual el patrón de repositorio es débil. – jason

+0

Es cierto, pero siempre puede separar las estrategias de búsqueda en otra clase, o hacer que FetchRelated sea una propiedad que puede ser configurada por una capa de servicio. –

+0

@ Diego Mijelshon: ¿Qué estamos obteniendo de ese nivel extra de abstracción? – jason

1

Usted no quiere para poner la llamada Fetch() en la especificación, porque no es necesaria. La especificación es solo para limitar los datos que luego se pueden compartir en muchas partes diferentes de su código, pero esas otras partes podrían tener necesidades drásticamente diferentes en cuanto a los datos que desean presentar al usuario, razón por la cual en esos puntos agregaría su Obtener declaraciones

Cuestiones relacionadas