Uso loading ansiosi con pattern specifica
-
09-10-2019 - |
Domanda
Ho implementato il modello specifica con LINQ come descritto qui https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer
Ora voglio aggiungere la possibilità di carico ansiosi e sono sicuro circa il modo migliore per andare su di esso.
La classe repository generica nell'esempio collegato:
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());
}
E l'attuazione specifica:
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;
}
}
Questo funziona bene, io ora voglio aggiungere la capacità di essere in grado di caricare ansioso. Capisco NHibernate ansioso di carico può essere fatto utilizzando Fetch su la query.
Quello che sto cercando è se per incapsulare la logica eager loading all'interno della specificazione o di passarlo nel repository, e anche il / la sintassi albero Linq espressione necessaria per raggiungere questo obiettivo (vale a dire un esempio di come sarebbe stato fatto) .
Soluzione
Una possibile soluzione potrebbe essere quella di estendere la classe specifica di aggiungere:
public virtual IEnumerable<Expression<Func<T, object>>> FetchRelated
{
get
{
return Enumerable.Empty<Expression<Func<T, object>>>();
}
}
E il cambiamento GetQuery a qualcosa di simile:
return specification.FetchRelated.Aggregate(
session.Query<T>().Where(specification.IsSatisfiedBy()),
(current, related) => current.Fetch(related));
Ora tutto ciò che dovete fare è di override FetchRelated quando necessario
public override IEnumerable<Expression<Func<Movie, object>>> FetchRelated
{
get
{
return new Expression<Func<Movie, object>>[]
{
m => m.RelatedEntity1,
m => m.RelatedEntity2
};
}
}
Un importante limitazione di questa implementazione che ho appena scritto è che è possibile recuperare solo le entità che sono direttamente correlati all'entità root.
Un miglioramento sarebbe sostenere livelli arbitrari (usando ThenFetch
), che richiederebbe alcuni cambiamenti nel modo di lavorare con i generici (ho usato object
permettere combinando diversi tipi di entità facilmente)
Altri suggerimenti
Non si vorrebbe mettere la chiamata Fetch () nella specifica, perché non è necessario. Specifica è solo per limitare i dati che possono poi essere condivisi tra diverse parti del codice, ma quelle altre parti potrebbe avere esigenze drasticamente diverse in quanto i dati che vogliono presente per l'utente, che è il motivo per cui in questi punti si dovrebbe aggiungere la tua Fetch dichiarazioni.