Frage

Der Versuch, ein wirklich einfaches Repository und Service-Layer-Muster hier zu machen. (NET-4, C #, LINQ, obwohl diese Frage teilweise sprachunabhängig ist). . Hinweis: Dies ist nur F & E

Mein Ziel ist es, die Menge der Methodendefinitionen in meiner Dienstschicht zu minimieren.

Hier ist mein Repository Vertrag:

interface IFooRepository
{
   IEnumerable<Foo> Find();
   void Insert(Foo foo);
   void Update(Foo foo);
   void Delete(Foo foo);
}

Nichts Neues gibt.

Nun, hier ist was im (Versuch) in meinem Service-Vertrag haben:

interface IFooDataService
{
   public IEnumerable<Foo> Find(FooSearchArgs searchArgs);
}

Im Wesentlichen eine bestimmte „Foo“ hat viele Eigenschaften (ID, Name, etc.), die Ich mag wäre in der Lage sein, auf suchen.

Also, ich mag nicht für jede andere Eigenschaft Methode haben 1x zu finden, ich möchte nur einen -., Dass die Art und Weise, wenn ich zusätzliche Eigenschaften erstellen i dont haben, die Verträge ändern

Der "FooSearchArgs" ist nur ein einfaches POCO mit all den verschiedenen "Foo" Eigenschaften es.

Also, das ist, etwas zu tun im Versuch, hier ist meine Fragen:

  • Ist das ein schlechtes Design? Wenn ja, was sind die Alternativen?
  • Wie kann ich diese Filterung in der Dienstschicht implementieren? Habe ich zu überprüfen, welche Eigenschaften von „FooSearchArgs“ gesetzt sind, dann hält Filterung nach unten? (Wenn dies, dann query.where wenn diese, query.where, usw.) Jeder habe eine Idee von einer cleveren LINQ IEnumerable-Extension-Methode, dies zu tun? (Dh repository.WhereMeetsSearchCriteria(fooSearchArgs))

Schätzen Sie die Hilfe.

War es hilfreich?

Lösung

Wir verwenden etwas sehr ähnlich. Eine Sache, die Sie sich entscheiden müssen, ist, wenn du gehst, IQueryable außerhalb des Repositorys belichten. Ihre Entdeckung Methode gibt IEnumerable, die die IQueryable von Ihrem wenn Klausel zurückgegeben werden könnten.

Der Vorteil der IQueryable Rückkehr ist, dass Sie weiterhin Ihren Kriterien bis außerhalb des Repository-Schicht verfeinern.

repository.Find(predicate).Where(x => x.SomeValue == 1);

Der Ausdruck wird nur dann kompiliert werden, wenn Sie die zurückgegebenen Daten zu verwenden, die hier in Lügen der Nachteil. Da Sie die Datenbank nur treffen, wenn Sie tatsächlich kommen, um die Ergebnisse verwenden Sie versuchen, am Ende könnte die Datenbank nach Ihrer Sitzung (nhibernate) oder Verbindungen zu nennen geschlossen wurden.

Meine persönliche Präferenz ist die Spezifikation Muster zu verwenden, wo Sie Ihre Methode find ein ISpecification Objekt übergeben verwendet wird, um die Abfrage zu tun.

public interface ISpecification<TCandidate>
{
    IQueryable<TCandidate> GetSatisfyingElements(IQueryable<TCandidate> source);
}

public class TestSpecification : ISpecification<TestEntity>
{
    public IQueryable<TestEntity> GetSatisfyingElements(IQueryable<TestEntity> source)
    {
        return source.Where(x => x.SomeValue == 2);
    }
}

public class ActiveRecordFooRepository: IFooRepository
{
    ...

    public IEnumerable<TEntity> Find<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        ...

        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).ToArray();

        ...
    }

    public TEntity FindFirst<TEntity>(ISpecification<TEntity> specification) where TEntity : class 
    {
        return specification.GetSatisfyingElements(ActiveRecordLinq.AsQueryable<TEntity>()).First();
    }
}

Nachdem die Abfrage die Repository-Anrufe ToArray oder ToList auf der resultierende IQueryable ausgeführt wird aus der Beschreibung zurückgeführt, so dass die Abfrage dort ausgewertet wird und dann. Während dies möglicherweise weniger flexibel scheint als IQueryable Belichtung kommt es mit mehreren Vorteilen.

  1. Abfragen werden sofort ausgeführt und verhindert ein Aufruf an die Datenbank vorgenommen werden, nachdem Sitzungen geschlossen haben.
  2. Da Ihre Fragen jetzt in Spezifikationen gebündelt sind, sie sind Einheit prüfbar.
  3. Technische Daten sind wiederverwendbar Bedeutung Sie nicht Code-Duplizierung haben bei dem Versuch, ähnliche Abfragen und alle Fehler in den Abfragen nur ausführen müssen an einem Ort fixiert werden.
  4. Mit der richtigen Art der Implementierung Sie auch zusammen, um Ihre Spezifikationen Kette kann.

repository.Find(
    firstSpecification
        .And(secondSpecification)
        .Or(thirdSpecification)
        .OrderBy(orderBySpecification));

Andere Tipps

Ist Leiten eines Func als Parameter an Ihrem Service Layers finden Methode anstelle der FooSearchArgs, eine Option? Enumerables haben eine Wo-Methode (Linq), die eine Func als Parameter übernimmt, so dass Sie es verwenden könnte, die Ergebnisse zu filtern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top