88 votes

méthode slick Scala, que je ne comprends pas si loin

J’ai essayer de comprendre quelques luisante et ce qu’elle exige.

Ici it un exemple :

Quelqu'un pourrait m’expliquer quel est le but de méthode ici, ce qui est , pourquoi ? et quelle est la Projection - méthode ' retourne l’instance de `` ?

196voto

Faiz Points 8115

[Mise à JOUR] - ajouté (encore un autre) explication sur for des compréhensions

  1. L' * méthode:

    Cette propriété renvoie la valeur par défaut de projection - qui est de savoir comment vous décrire:

    "toutes les colonnes (ou des valeurs calculées) je suis généralement intéressées".

    Votre table peut avoir plusieurs champs; vous avez seulement besoin d'un sous-ensemble de votre défaut de projection. La valeur par défaut de projection doit correspondre au type les paramètres de la table.

    Nous allons les prendre un à la fois. Sans l' <> trucs, juste l' *:

    // First take: Only the Table Defintion, no case class:
    
    object Bars extends Table[(Int, String)]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
    
      def * = id ~ name // Note: Just a simple projection, not using .? etc
    }
    
    // Note that the case class 'Bar' is not to be found. This is 
    // an example without it (with only the table definition)
    

    Juste la définition d'un tableau comme ça vous permettra de faire des requêtes comme:

    implicit val session: Session = // ... a db session obtained from somewhere
    
    // A simple select-all:
    val result = Query(Bars).list   // result is a List[(Int, String)]
    

    la valeur par défaut de la projection de l' (Int, String) conduit à une List[(Int, String)] pour les requêtes simples comme ceux-ci.

    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1)
         // yield (b.name, 1) // this is also allowed: 
                              // tuples are lifted to the equivalent projection.
    

    Quel est le type d' q? C'est un Query avec la projection (String, Int). Lorsqu'il est invoqué, il renvoie une List de (String, Int) n-uplets que par la projection.

     val result: List[(String, Int)] = q.list
    

    Dans ce cas, vous avez défini la projection que vous voulez dans l' yieldclause de la for de la compréhension.

  2. Maintenant, à propos de <> et Bar.unapply.

    Cela fournit ce qu'on appelle Mappé Projections.

    Jusqu'à présent nous avons vu comment nappe permet de formuler des requêtes en Scala que le retour d'une projection des colonnes (ou des valeurs calculées); de Sorte que lors de l'exécution de ces requêtes que vous devez penser à la ligne de résultat d'une requête comme un Scala tuple. Le type de la n-uplet va correspondre à la Projection, qui est défini par votre for de la compréhension comme dans l'exemple précédent, de par la valeur par défaut *de la projection). C'est pourquoi, field1 ~ field2 renvoie une projection de l' Projection2[A, B]A est le type d' field1 et B est le type d' field2.

    q.list.map {
      case (name, n) =>  // do something with name:String and n:Int
    }
    
    Queury(Bars).list.map {
      case (id, name) =>  // do something with id:Int and name:String 
    }
    

    Nous avons affaire à des tuples, ce qui peut être fastidieux, si nous avons trop de les colonnes. Nous aimerions penser à des résultats non comme TupleN plutôt qu'à une certaine objet avec des champs nommés.

    (id ~ name)  // A projection
    
    // Assuming you have a Bar case class:
    case class Bar(id: Int, name: String) // For now, using a plain Int instead
                                          // of Option[Int] - for simplicity
    
    (id ~ name <> (Bar, Bar.unapply _)) // A MAPPED projection
    
    // Which lets you do:
    Query(Bars).list.map ( b.name ) 
    // instead of
    // Query(Bars).list.map { case (_, name) => name }
    
    // Note that I use list.map instead of mapResult just for explanation's sake.
    

    Comment cela fonctionne? <> prend une projection Projection2[Int, String]et retourne un mappage de la projection sur le type Bar. Les deux arguments Bar, Bar.unapply _ dire de la nappe de la façon dont cette (Int, String) de projection doit être mappé à une classe de cas.

    C'est dans les deux sens de cartographie, Bar est le cas du constructeur de la classe, de sorte que la les informations nécessaires pour aller d' (id: Int, name: String) d'un Bar. Et unapply si vous l'avez deviné, est pour l'inverse.

    Où est - unapply proviennent de? C'est un standard de Scala méthode disponible pour tout cas ordinaire de la classe juste la définition d' Bar vous donne un Bar.unapply qui est un extracteur qui peut être utilisé pour récupérer l' id et name que le Bar a été construit avec:

    val bar1 = Bar(1, "one")
    // later
    val Bar(id, name) = bar1  // id will be an Int bound to 1,
                              // name a String bound to "one"
    // Or in pattern matching
    val bars: List[Bar] = // gotten from somewhere
    val barNames = bars.map {
      case Bar(_, name) => name
    }
    
    val x = Bar.unapply(bar1)  // x is an Option[(String, Int)]
    

    Afin que votre défaut de projection peut être adressé à la classe de cas de vous la plupart s'attendent à utiliser:

    object Bars extends Table[Bar]("bar") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc)
      def name = column[String]("name")
      def * = id ~ name <>(Bar, Bar.unapply _)
    }
    

    Ou vous pouvez même lui demander par requête:

    case class Baz(name: String, num: Int)
    
    // SELECT b.name, 1 FROM bars b WHERE b.id = 42;
    val q1 = 
       for (b <- Bars if b.id === 42) 
         yield (b.name ~ 1 <> (Baz, Baz.unapply _))
    

    Ici le type d' q1 est Query avec un mappé projection d' Baz. Lorsqu'il est invoqué, il renvoie une List de Baz objets:

     val result: List[Baz] = q1.list
    
  3. Enfin, en aparté, l' .? offre l'Option de Levage - la Scala façon de traiter les valeurs que peut-être pas.

     (id ~ name)   // Projection2[Int, String] // this is just for illustration
     (id.? ~ name) // Projection2[Option[Int], String]
    

    Qui, enveloppant, fonctionnent bien avec votre définition originale de l' Bar:

    case class Bar(id: Option[Int] = None, name: String)
    
    // SELECT b.id, b.name FROM bars b WHERE b.id = 42;
    val q0 = 
       for (b <- Bars if b.id === 42) 
         yield (b.id.? ~ b.name <> (Bar, Bar.unapply _))
    
    
    q0.list // returns a List[Bar]
    
  4. En réponse à l'observation sur la façon dont Slick utilise for des compréhensions:

    En quelque sorte, les monades toujours gérer pour afficher et demande à faire partie de l'explication...

    Pour les interprétations ne sont pas spécifiques aux collections. Elles peuvent être utilisées sur tout type de Monade, et les collections sont juste un des nombreux types de monade types disponibles en Scala.

    Mais comme les collections sont familiers, ils font un bon début point pour une explication:

    val ns = 1 to 100 toList; // Lists for familiarity
    val result = 
      for { i <- ns if i*i % 2 == 0 } 
        yield (i*i)
    // result is a List[Int], List(4, 16, 36, ...)
    

    En Scala, un pour la compréhension est sucre syntaxique pour méthode (éventuellement imbriquées) les appels de méthode: Le code ci-dessus est (plus ou moins) ce qui équivaut à:

    ns.filter(i => i*i % 2 == 0).map(i => i*i)
    

    Fondamentalement, quelque chose avec filter, map, flatMap méthodes (en d'autres termes, une Monade) peut être utilisé dans un for de la compréhension à la place de ns. Un bon exemple est l' Option monade. Voici l'exemple précédent où la de même for déclaration de travaux sur le List ainsi que Option monades:

    // (1)
    val result = 
      for { 
        i <- ns          // ns is a List monad
        i2 <- Some(i*i)  // Some(i*i) is Option
          if i2 % 2 == 0 // filter
      } yield i2
    
    // Slightly more contrived example:
    def evenSqr(n: Int) = { // return the square of a number 
      val sqr = n*n         // only when the square is even
      if (sqr % 2 == 0) Some (sqr)
      else None
    }
    
    // (2)
    result = 
      for { 
        i <- ns  
        i2 <- evenSqr(i) // i2 may/maynot be defined for i!
      } yield i2
    

    Dans le dernier exemple, la transformation ne serait peut-être regarder comme ceci:

    // 1st example
    val result = 
      ns.flatMap(i => Some(i*i)).filter(i2 => i2 %2 ==0)
    
    // Or for the 2nd example
    result = 
      ns.flatMap(i => evenSqr(i)) 
    

    Dans la Nappe, les requêtes sont monadique - ils sont juste des objets avec l' map, flatMap et filter méthodes. Si l' forcompréhension (illustré dans l'explication de l' * méthode) se traduit par:

    val q = 
      Query(Bars).filter(b => b.id === 42).map(b => b.name ~ 1)
    // Type of q is Query[(String, Int)]
    
    val r: List[(String, Int)] = q.list // Actually run the query
    

    Comme vous pouvez le voir, flatMap, map et filter sont utilisés pour générer un Query par la répétition de la transformation de l' Query(Bars) avec chaque invocation d' filter et map. Dans le cas de les collections de ces méthodes d'itération et le filtre de la collection mais en Slick ils sont utilisés pour générer du SQL. Plus de détails ici: Comment Scala de la Nappe de traduire Scala code JDBC?

6voto

Dominic Bou-Samra Points 4343

Puisque personne n'a répondu, ceci pourrait aider à obtenir vous avez commencé. Je ne sais pas Lisse très bien.

À partir de la Nappe de la documentation:

Levée De L'Incorporation:

Chaque table nécessite un * méthode contatining un défaut de projection. Cette décrit ce que vous obtiendrez lorsque vous renvoyer les lignes (sous la forme d'un objet de la table) à partir d'une requête. Slick * projection n'a pas à correspondre à celui de la base de données. Vous pouvez ajouter de nouvelles colonnes (par exemple avec valeurs calculées) ou d'omettre certaines colonnes que vous le souhaitez. La non-levée de type correspondant à l' * projection est donnée comme un paramètre de type d' Table. Pour simple, non cartographié les tables, ce sera une seule colonne type ou un n-uplet de types de colonne.

En d'autres termes, slick a besoin de savoir comment traiter avec une ligne retournée à partir de la base de données. La méthode que vous avez défini utilise leurs analyseur combinator fonctions de combiner vos définitions de colonne en quelque chose qui peut être utilisé sur une ligne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X