5

Ich habe die Spezifikation Muster mit Linq umgesetzt wie hier https://www.packtpub.com/article/nhibernate-3-using-linq-specifications-data-access-layer skizzierteMit eifrig Beladung mit Spezifikation Muster

Ich möchte jetzt die Möglichkeit, zu eifrig Last und bin nicht sicher, über den besten Weg, darüber zu gehen hinzuzufügen.

Die generische Repository-Klasse in dem verknüpften 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 Spezifikation Umsetzung:

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

Diese gut funktioniert, mag ich nun die Möglichkeit, in der eifrigen Last der Lage sein, . Ich verstehe, dass NHibernate eifrig geladen werden kann, indem Sie Fetch für die Abfrage verwenden.

Was ich suchen ist, ob die Eager Ladelogik innerhalb der Spezifikation zu kapseln oder in das Repository zu übergeben, und auch die Linq/Ausdruck Baumsyntax benötigt, um dies zu erreichen (dh ein Beispiel, wie es gemacht würde).

Antwort

3

Eine mögliche Lösung wäre es, die Spezifikation Klasse erweitern hinzuzufügen:

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

Und ändern GetQuery zu so etwas wie:

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

Alles was Sie jetzt tun müssen, ist FetchRelated außer Kraft setzen, wenn nötig

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 schrieb, ist t Sie können nur Entitäten abrufen, die direkt mit der Root-Entität verbunden sind.

wäre eine Verbesserung beliebigen Ebenen zu unterstützen (mit ThenFetch), die einige Änderungen in der Art und Weise erfordern würden wir mit Generika arbeiten (I object verwendet die Kombination von Typen verschiedenen Unternehmen leicht zu ermöglichen)

+0

Das ist sicherlich eine Lösung, aber das ist eine Vermischung von Verantwortlichkeiten (Verkapseln von Abfragen und Abrufen von Strategien). Aus diesem Grund ist das Repository-Muster schwach. – jason

+0

Wahr, aber Sie können die Abrufstrategien immer in eine andere Klasse aufteilen oder FetchRelated zu einer Eigenschaft machen, die von einer Service-Schicht gesetzt werden kann. –

+0

@Diego Mijelshon: Was gewinnen wir von dieser Extralebene der Abstraktion? – jason

1

Sie würden nicht wollen um den Aufruf Fetch() in die Spezifikation zu setzen, weil es nicht benötigt wird. Spezifikation ist nur für die Begrenzung der Daten, die dann über viele verschiedene Teile Ihres Codes geteilt werden können, aber diese anderen Teile könnten drastisch unterschiedliche Bedürfnisse in welchen Daten sie dem Benutzer präsentieren möchten, weshalb an diesen Punkten würden Sie Ihre hinzufügen Anweisungen abrufen