5 Stimmen

Eager Loading mit Spezifikationsmuster verwenden

Ich habe das Spezifikationsmuster mit Linq implementiert, wie hier skizziert https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer

Ich möchte nun die Möglichkeit des eifrigen Ladens hinzufügen und bin mir nicht sicher, wie ich das am besten anstellen soll.

Die generische Repository-Klasse aus dem verlinkten Beispiel:

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());
}

Und die Umsetzung der Spezifikation:

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;
 }
}

Das funktioniert gut, jetzt möchte ich die Fähigkeit hinzufügen, eifrig zu laden. Ich verstehe NHibernate eager Laden kann getan werden, indem Sie abrufen. auf die Abfrage.

Was ich suche, ist, ob die Eager-Loading-Logik innerhalb der Spezifikation zu kapseln oder in das Repository zu übergeben, und auch die Linq/Ausdrucksbaum-Syntax erforderlich, um dies zu erreichen (d.h. ein Beispiel, wie es getan werden würde).

3voto

Diego Mijelshon Punkte 52110

Eine mögliche Lösung wäre, die Klasse Specification zu erweitern und hinzuzufügen:

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

Und ändern Sie GetQuery in etwas wie:

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

Jetzt müssen Sie nur noch FetchRelated bei Bedarf außer Kraft setzen

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

Eine wichtige Einschränkung dieser Implementierung, die ich gerade geschrieben habe, ist, dass Sie nur Entitäten abrufen können, die direkt mit der Root-Entität verbunden sind.

Eine Verbesserung wäre die Unterstützung beliebiger Ebenen (mit ThenFetch ), was einige Änderungen in der Art und Weise erfordern würde, wie wir mit Generika arbeiten (ich habe object um verschiedene Entitätstypen einfach kombinieren zu können)

1voto

Darren Kopp Punkte 74401

Der Fetch()-Aufruf sollte nicht in die Spezifikation aufgenommen werden, da er nicht benötigt wird. Die Spezifikation dient nur zur Begrenzung der Daten, die dann von vielen verschiedenen Teilen Ihres Codes gemeinsam genutzt werden können, aber diese anderen Teile könnten ganz andere Anforderungen an die Daten haben, die sie dem Benutzer präsentieren wollen, weshalb Sie an diesen Stellen Ihre Fetch-Anweisungen hinzufügen würden.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X