2016-03-28 4 views
2

Wir verwenden die Repository-Muster für unseren Datenzugriff in Scala und so weit wir haben so etwas in unserem Repository[A] Merkmale:Wie skaliert man das Repository-Muster in Scala?

trait Repository[A] { 

    /** 
    * Create a new record in the database. 
    * 
    * @param model 
    * @param connection 
    * @return 
    */ 
    def create(model: A)(implicit connection: Connection): A 

    /** 
    * Retrieve a record from the database with the corresponding id. 
    * 
    * @param id 
    * @param connection 
    * @return 
    */ 
    def getById(id: UUID)(implicit connection: Connection): Option[A] 

    /** 
    * Update the corresponding record in the database. 
    * 
    * @param model 
    * @param connection 
    * @return The updated model, or None if it was not found 
    */ 
    def update(model: A)(implicit connection: Connection): Option[A] 

    /** 
    * Delete a record from the database with the corresponding id. 
    * 
    * @param id 
    * @param connection 
    * @return The deleted model, or None if it was not found 
    */ 
    def deleteById(id: UUID)(implicit connection: Connection): Option[A] 

} 

Und das ist in Ordnung. Dieses Problem tritt bei den "query" -Methoden auf. Zum Beispiel vorstellen, ich eine Methode für das Erhalten alle Blog-Posts, wo:

  • der Benutzer-ID ist X oder
  • der Benutzer ein Gast

Ich möchte auch das Blog-Objekt umfassen . Unter unserem aktuellen System würden wir ein Verfahren wie diese:

def getWithBlogByUserIdOrUserGuest(userId: UUID, guest: Boolean): List[Post] 

Das ist ziemlich hässlich, und wenn Sie eine Reihe von Beziehungen zu einer Einheit zurückkehren wollen (die langen Namen haben) kann es aus der Hand schnell. Es ist auch schwierig, eine Eigenschaft zu verwenden, um eine gewisse Konsistenz zu erreichen.

Einige Beispiele, die ich gesehen habe, sind nur ein Abfrage-Objekt zu verwenden:

def query(criteria: Criteria): List[A] 

Dies erfordert jedoch für die Definition Kriterien mit irgendeiner Art von DSL kommen, und es erfordert auch das Schreiben von Code, der die Kriterien konvertieren zu SQL, das ist fehleranfällig und viel Arbeit, und wird wahrscheinlich saugen.

Meine Frage ist also, wie gehen die meisten Leute damit um, eine generalisierte Möglichkeit zu haben, Abfrage-Methoden in Repositories zu schreiben?

+0

Das hängt sehr davon ab, was Sie unter "generalisiert" verstehen. Wenn Sie mehr oder weniger äquivalent zu SQL meinen, dann ist das etwas fragend. Aber optimieren Sie vorzeitig? Welche Art von Anfragen erhalten Sie wirklich in Ihrer Anwendung? Und ist es in einigen Fällen am besten, wenn der Client eine einfachere Abfrage durchführt und die Ergebnisse selbst weiter filtert? –

+1

@TheArchetypalPaul: Im Moment haben wir aktuelle Methoden wie 'getOneWithWidgetAndTaskTemplateByChecklistRevisionIdAndWidgetId' und ich suche nach einem besseren Weg, es zu tun. Es muss keine allgemeine Kriterien-API sein, sondern nur eine überschaubare Methode zur Definition der Methoden. – cdmckay

+0

Müssen * sie * generisch sein? Meiner Erfahrung nach gibt es normalerweise nur wenige Möglichkeiten, wie Ihr Geschäftscode Objekte abruft, also codieren Sie diese Methoden einfach. YAGNI trifft zu! – Paolo

Antwort

0

Wie Sie bereits herausgefunden haben, können Sie das "Query Object" implementieren.

Was nicht „das Schreiben von Code, der die Kriterien für SQL umwandelt, die fehleranfällig und viel Arbeit ist“ Sie einen Rahmen wie Slick verwenden können, die für Sie alle SQL-Generierung tun und ermöglicht es Ihnen, zu behandeln Tabellen als Sammlungen und Dinge tun, wie:

posts.filter(post => post.userId == "USER-ID-1" || post.guest) 

Slicks abstract class Query einen HOF hat filter genannt, so dass Sie in Ihrer benutzerdefinierten Funktion, um es zu bestimmen, ob ein Datensatz herausgefiltert werden soll oder nicht passieren können.