2017-01-17 5 views
0

Ich versuche, diese Abfrage richtig zu bekommen, aber immer Fehler. Zunächst gibt searchUser eine Sequenz übereinstimmender UserEntries zurück, die eine eindeutige ID für den Benutzer enthalten, und für jede userID gibt es eine zweite Abfrage, die eine andere Benutzerinformation + Adresse aus einer anderen Tabelle erhält.Scala: Abfragen im Inneren für das Verständnis Fehler geben

Code:

def searchUsers(pattern: String) = auth.SecuredAction.async { 
    implicit request => 
    usersService.searchUser(pattern) flatMap { usrList => 
     for { 
     u <- usrList 
     ui <- usersService.getUsersWithAddress(u.id) 
     } yield { 
     Ok(views.html.UserList(ui)) 
     } 
    } 
} 

Unterschriften für die APIs verwendet:

def searchUser(pattern: String): Future[Seq[UserEntry]] = ...  
def getUsersWithAddress(userId: Long): Future[Seq[(UserProfile, Seq[String])]] = ... 

Fehler:

[error] modules/www/app/controllers/Dashboard.scala:68: type mismatch; 
[error] found : scala.concurrent.Future[play.api.mvc.Result] 
[error] required: scala.collection.GenTraversableOnce[?] 
[error]   ui <- usersService.getUsersWithAddress(u.id) 
[error]   ^
[error] one error found 
[error] (www/compile:compileIncremental) Compilation failed 

Wenn ich kommentieren Sie Zeile "u < - usrList" und eine Benutzer-ID hard für die nächste Zeile wie "ui < - usersService.getUsersWithAddress (1L)" funktioniert es. Irgendeine Idee, was ich vermisse?

Antwort

1

Wenn Sie mehrere Generatoren zum Verständnis verwenden, müssen die Monaden vom selben Typ sein. Z.B. Sie können nicht:

scala> for{ x <- Some("hi"); y <- List(1,2,3) } yield (x,y) 
<console>:11: error: type mismatch; 
found : List[(String, Int)] 
required: Option[?] 
      for{ x <- Some("hi"); y <- List(1,2,3) } yield (x,y) 
           ^

Was können Sie tun, ist eine konvertieren oder die andere den richtigen Typ zu entsprechen. Für das obige Beispiel, das wäre:

scala> for{ x <- Some("hi").toSeq; y <- List(1,2,3) } yield (x,y) 
res2: Seq[(String, Int)] = List((hi,1), (hi,2), (hi,3)) 

In Ihrem speziellen Fall eine Ihrer Generatoren ist ein GenTraversableOnce, und das andere ist eine Zukunft. Sie können Future.successful (theList) wahrscheinlich verwenden, um zwei Futures zu erhalten. Sehen Sie hier die Antwort zum Beispiel:

Unable to use for comprehension to map over List within Future

+0

zu ändern, wenn ich u wickeln <- usrList mit Future.successful() Ich am Ende mit „Wert-ID ist kein Mitglied von Seq [models.UserEntry] ". Ich hatte gehofft, "du" ein Gegenstand zu sein, eher eine Sequenz. 2. Generator benötigt einen Verweis auf ein einzelnes Element - wie bekomme ich das (ich kann an traditionelle for-Schleife in nicht-funktionalen Sprachen denken, aber nicht hier ..) – srvy

+0

folgte eine Kette von Antworten auf Ihre basiert und schließlich eine Lösung .. Da ich nicht in der Lage bin, ein formatiertes Stück Code in den Kommentar zu schreiben, werde ich es als meine Antwort hinzufügen - aber akzeptiere deine, um dir den richtigen Kredit zu geben! – srvy

0

Basierend auf @ Brian Antwort zu einer Lösung gekommen .. folgendes bearbeitetes (nicht Formatter Codeblock als Kommentar eingeben könnte - so als Antwort hinzufügen):

usersService.searchUser(pattern) flatMap { usrList => 
    val q = for { 
     u <- usrList 
    } yield (usersService.getUserWithAddress(u.id)) 
    val r = Future.sequence(q) 
    r map { ps => 
     Ok(views.html.UserList(ps)) 
    } 
    } 

Zum Verständnis akkumuliert die Futures und dann wurde die Sequenz abgeflacht und dann kartiert. Hoffe, so ist es gemacht!

Hinweis: Auch hatte ich die Unterschrift von getUserWithAddress zu X anstelle von Seq [X]