2015-05-20 10 views
6

Używam Slick 3.0 i (oczywiście) prawie wszystkie przykłady z tamtej strony obejmują Slick 2.x. Rzeczy się zmieniły i szczerze mówiąc, wydają się być skomplikowane, nie mniej."Prawidłowy" sposób na pisanie zapytań Slick 3.0 Scala w Play Framework

Oto przykład: Chcę uzyskać obiekt (GPPerson) według id. To, co mam teraz, i wydaje bardzo rozwlekły ... bardziej niż Slick 2.x:

def get(id: GPID): Option[GPPerson] = Await.result(
    db.run(
     people.filter(_.id === id).result), Duration.Inf 
    ).headOption 

W Slick rzeczy 2.x było łatwiejsze ze względu na implicits, między innymi. Ale powyższe wydaje się najbardziej zwięzłym wyrażeniem, jakie wymyśliłem.

Nie zajmuje się również obsługą wyjątków, które musiałbym dodać.

+0

Dla jasności, blokujesz swój wątek za pomocą 'Await.result'. Prawdopodobnie jesteś tego świadomy, ale po prostu przeraża to widząc go w kodzie. –

+0

Jestem świadomy - i wszystkie przykłady z Slick 3.0 z Typesafe robią to ... – Zac

Odpowiedz

4

Zacząłem używać Slick 3.0 w nowym projekcie kilka miesięcy temu i miałem te same pytania. Zrozumiałem:

Slick 3.0 został zaprojektowany dla nieblokujących aplikacji asynchronicznych (reaktywnych). Oczywiście oznacza to teraz Akka + Play/Spray. W tym świecie głównie wchodzisz w interakcje z Futures, dlatego też Slick db.run zwraca Future. Nie ma sensu używanie Await.result - jeśli potrzebujesz blokowania połączeń, lepiej wrócić do 2.x.

Ale jeśli użyjesz reaktywnego stosu, natychmiast uzyskasz korzyści. Na przykład, Spray jest biblioteką całkowicie nie blokującą, która dobrze współpracuje z Futures przy użyciu dyrektywy onComplete. Możesz wywołać metodę, która zwraca Future z wynikiem ze Slick in a Spray route, a następnie użyj tego wyniku razem z onComplete. W tym przypadku cały proces odpowiedzi-odpowiedzi nie jest blokowany.

Wspomniałeś również o obsłudze wyjątków, więc tak właśnie postępujesz - używając Futures.

Więc na podstawie mojego doświadczenia chciałbym napisać metodę w następujący sposób:

def get(id: GPID): Future[Option[GPPerson]] = db.run(
    people.filter(_.id === id).result.map(_.headOption) 
) 

a następnie pracować z przyszłością.

+0

Czy Przyszłość została zwrócona bezpośrednio w działaniu? Teraz na przykład mam kilka akcji, które wykorzystują Await do wypełnienia zapytania. Na przykład zrobię 'val r = db.run (glimpleAction); Await.result (r, Duration.Inf) 'w Akcji ... czy po prostu usunę Await i Play jest na tyle sprytny, aby poradzić sobie z konsekwencjami tego? (Ale to nie może być takie proste, ponieważ mogę zrobić "Await.result (r, Duration.Inf) .toSeq", aby uzyskać sekwencję. Jak zwrócę przyszłość w działaniu usługi sieciowej?) – Zac

+0

Zdecydowanie nie Potrzebuję Await.result. Standardowy sposób pisania zapytań w Slick: 'db.run (some_query.result)', a to zwróci typ 'Future [Seq [SomeQueryType]]'. Jeśli chodzi o grę - musisz użyć 'Action.async', aby móc używać Futures w swoich działaniach, więcej szczegółów: https://www.playframework.com/documentation/2.4.x/ScalaAsync – sap1ens

1

możesz to zrobić.

def syncResult[R](action:slick.dbio.DBIOAction[R, slick.dbio.NoStream, scala.Nothing]):R = { 
    import scala.concurrent.duration.Duration 

    val db = Database.forConfig("db") 
    try { 
     Await.result(db.run(action), Duration.Inf) 
    } finally db.close 
    } 

def get(id: GPID): Option[GPPerson] = syncResult { people.filter(_.id === id).result.headOption } 
+5

OK, to sprawia, że ​​jest trochę czystszy ... ale jak wspomniano powyżej, co z faktem, że jest to blokowanie ? Wygląda na to, że ** wszystkie ** przykłady z gatunku "Zręczny 3.0", na które patrzyłem, używają tego wzorca, ale ... on blokuje. To wydaje się bardzo złe. Wygląda też na to, że Slick 3.0 poszedł w złym kierunku, sprawiając, że rzeczy trudniejsze do wywołania niż łatwiejsze ... ale być może są zmiany w API, których właśnie nie znalazłem. Dokumentacja jest uprzejma, "niejasna i niekompletna ..." – Zac

Powiązane problemy