2017-10-13 2 views
0

J'essaie d'implémenter une méthode qui récupère tous les utilisateurs en réutilisant une méthode qui récupère un seul utilisateur basé sur l'ID utilisateur, mais ne peut pas comprendre la discordance de type. Voulez-vous me dire comment résoudre ce problème?Scala & Slick: incompatibilité de type avec [Produit avec Serializable] doit être corrigé

UserDAOImpl.scala:

def findAll: Future[Seq[User]] = { 
    val dbUsers: Future[Seq[DbUser]] = db.run(users.result) 

    dbUsers.map { dbUserSeq => 
    dbUserSeq.map { dbUser => find(UUID.fromString(dbUser.userID)).value.get match { 
     case Success(Some(usr: User)) => usr 
     case _ => None 
    }} 
    } 
} 

Je laisse de côté la définition de find car il fonctionne très bien, mais voici la signature.

def find(userID: UUID): Future[Option[User]] = { 

Message d'erreur:

found : Seq[Product with Serializable] 
required: Seq[models.User] 
      dbUserSeq.map { dbUser => 
         ^

Juste au cas où, la définition des utilisateurs

private val users = TableQuery[UserTable] 

Toute suggestion serait appréciée.

+0

Cela ne semble pas se rapporter à Slick mais à votre code seulement. ffind (UUID.fromString (dbUser.userID)) renvoie un futur donc vous avez probablement besoin d'un flatmap dessus? – Edmondo1984

+0

Vous avez déjà tous les utilisateurs, non? C'est ici * val dbUsers: Futur [Seq [DbUser]] = db.run (users.result) * –

+0

@ Edmondo1984 'cas Succès (Some (usr: User)) => usr' fait cela. Merci pour la réponse, cependant. – hirofujitaaki

Répondre

1

Une approche non-blocage:

def findAll: Future[Seq[User]] = { 
    db.run(users.result) 
    .map(dbUserSeq => 
     Future.sequence(dbUserSeq.map(dbUser => find(UUID.fromString(dbUser.userID)))) 
    ) 
    .flatMap(userFutSeq => // userFutSeq is a Future[Seq[Option[User]]] 
     userFutSeq.map(userSeq => userSeq.collect { case Some(u) => u }) 
    ) 
} 

Le code ci-dessus regroupe les utilisateurs qui se trouvent et ne tient pas compte du reste.

Évitez d'utiliser Await sauf à des fins de test. Lorsque vous travaillez avec des contrats à terme, restez dans le contexte d'un Future.

+0

Merci pour le bon conseil. Je savais qu'utiliser Await n'était pas une bonne idée, mais sans elle, je n'arrivais pas à comprendre comment. Juste une chose: Le code que vous avez posté ne compile pas, en disant "valeur aplatie n'est pas un membre de scala.concurrent.Future [scala.concurrent.Future [Seq [models.User]]], peut-être un point-virgule est manquant avant Si vous remplacez la carte par flatMap, cela compile. Avez-vous une idée de ce qui en est la cause? – hirofujitaaki

+1

@hirofujitaaki: Vous obtenez probablement l'erreur parce que vous utilisez une version de Scala antérieure à la version 2.12 ; 'flatten' a été ajouté à l'API' Future' dans Scala 2.12 Cela dit, 'flatMap' est une meilleure approche, donc j'ai mis à jour la réponse – chunjef

+0

Ok, donc je ne devrais pas m'en soucier autant. ton aide! – hirofujitaaki

1

Le code précédent avait en réalité plusieurs problèmes, et le code ci-dessous est la solution que j'ai trouvée jusqu'à présent. Peut-être pas le plus simple, mais ça a marché.

def findAll: Future[Seq[User]] = { 
    db.run(users.result).map { dbUserSeq => 
     dbUserSeq.map { dbUser => 
     val userFut: Future[Option[User]] = find(UUID.fromString(dbUser.userID)) 
     Await.ready(userFut, Duration.Inf).value.get match { 
      case Success(Some(usr: User)) => usr 
      case _ => throw new RuntimeException 
     } 
     } 
    } 
    }