Que tratar de entender algunos Slick funciona y lo que se requiere.

Aquí un ejemplo:

package models

case class Bar(id: Option[Int] = None, name: String)

object Bars extends Table[Bar]("bar") {
  def id = column[Int]("id", O.PrimaryKey, O.AutoInc)

  //This is the primary key column
  def name = column[String]("name")

  //Every table needs a * projection with the same type as the table's type parameter
  def * = id.? ~ name <>(Bar, Bar.unapply _)
}

Podía alguien me explique ¿cuál es el propósito de * método aquí, ¿qué es <>, ¿por qué unapply? y ¿cuál es la Proyección por el método de ~‘ devuelve la instancia de Projection2?

InformationsquelleAutor ses | 2012-12-16

2 Comentarios

  1. 194

    [ACTUALIZACIÓN]añadido (otro) explicación en for comprensiones de

    1. La * método:

      Devuelve el defecto de proyección – que es la forma de describir:

      ‘todas las columnas (o de los valores calculados) estoy generalmente interesado» en.

      La tabla puede tener varios campos; sólo se necesita un subconjunto de
      su defecto de proyección. El valor predeterminado de proyección debe coincidir con el tipo de
      los parámetros de la tabla.

      Vamos a tomar uno a la vez. Sin <> cosas, sólo el *:

      //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)

      Sólo una definición de tabla como la que te permitirá hacer consultas como:

      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)]

      el valor predeterminado de la proyección de (Int, String) conduce a una List[(Int, String)]
      para consultas sencillas como estas.

      //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.

      ¿Cuál es el tipo de q? Es un Query con la proyección (String, Int).
      Cuando se invoca, devuelve un List de (String, Int) tuplas como por la proyección.

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

      En este caso, se ha definido la proyección que desea en el yield cláusula
      de la for comprensión.

    2. Ahora sobre <> y Bar.unapply.

      Esto proporciona lo que se llama Asignada Proyecciones.

      Hasta ahora hemos visto cómo slick permite expresar las consultas en Scala
      que devolver un proyección de columnas (o de los valores calculados); Así que cuando la ejecución de
      estas consultas usted tiene que pensar en el resultado de la fila de una consulta como Scala tupla.
      El tipo de la tupla coincidirá con la Proyección que se define (por su
      for de comprensión como en el ejemplo anterior, de forma predeterminada * de proyección).
      Esta es la razón por la field1 ~ field2 devuelve una proyección de Projection2[A, B] donde
      A es el tipo de field1 y B es el tipo de 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 
      }

      Estamos tratando con tuplas, que puede ser engorroso si tenemos demasiados
      columnas. Nos gustaría pensar que de los resultados no se como TupleN sino algunos
      objeto con el nombre de los campos.

      (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.

      ¿Cómo funciona esto? <> toma una proyección Projection2[Int, String] y
      devuelve un mapa de proyección en el tipo de Bar. Los dos argumentos Bar, Bar.unapply _
      dígale a slick cómo este (Int, String) de proyección debe ser asignado a un caso de la clase.

      Este es un camino de dos asignación; Bar es el caso del constructor de la clase, por lo que el
      la información necesaria para ir de (id: Int, name: String) a un Bar. Y unapply
      si, lo has adivinado, es para que a la inversa.

      ¿De dónde unapply vienen? Este es un estándar de la Scala método disponible para la
      en cualquier caso ordinario de clase – de la definición de Bar le da un Bar.unapply que
      es un extractor que puede ser utilizado para volver a la id y name que el
      Bar fue construido con:

      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)]

      Por lo que su valor predeterminado de proyección puede ser asignada para el caso de la clase que más te espera utilizar:

      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 _)
      }

      O incluso puede hacer que por consulta:

      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 _))

      Aquí el tipo de q1 es un Query con un asignada proyección a Baz.
      Cuando se invoca, devuelve un List de Baz objetos:

       val result: List[Baz] = q1.list
    3. Finalmente, como un aparte, el .? ofrece Opción de Elevación – la Scala manera de
      el trato con los valores que no puede ser.

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

      Que, resumiendo, funcionará muy bien con su definición original de 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 respuesta a la observación sobre cómo Slick utiliza for de comprensión:

      De alguna manera, las mónadas siempre se las arreglan para aparecer y la demanda de la
      ser parte de la explicación…

      Para la comprensión no son específicos de colecciones solo.
      Pueden ser utilizados en cualquier tipo de Mónada, y las colecciones que se
      sólo uno de los muchos tipos de mónada tipos disponibles en la Scala.

      Pero como las colecciones son familiares, son un buen punto de partida
      punto para una explicación:

      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, ...)

      Scala, una para la comprensión sintáctica de azúcar para
      método (posiblemente anidada) llamadas de método: El código de arriba
      es (más o menos) equivalente a:

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

      Básicamente, cualquier cosa con filter, map, flatMap
      métodos (en otras palabras, un Mónada) puede ser utilizado en un
      for la comprensión en lugar de ns. Un buen ejemplo
      es el Opción mónada. Aquí está el ejemplo anterior
      donde el mismo for declaración trabaja en el
      List así como Option mónadas:

      //(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

      En el último ejemplo, la transformación sería, tal vez, buscar
      como este:

      //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)) 

      Resbaladizas, las consultas se monádico – son sólo los objetos con
      el map, flatMap y filter métodos. Así que el for comprensión
      (se muestra en la explicación de la * método) sólo se traduce en:

      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

      Como se puede ver, flatMap, map y filter se utilizan para
      generar un Query por la repetición de transformación de Query(Bars)
      con cada invocación de filter y map. En el caso de
      las colecciones de estos métodos en realidad recorrer y el filtro de la colección
      pero en la Mancha que se utilizan para generar SQL. Más detalles aquí:
      ¿Cómo Scala Slick traducir Scala código en JDBC?

    • En ‘1’ explicación bloque: no es obvio que ‘val p =’ es WrappingQuery, se ve como una Lista de<Projection2> mientras que la lectura del código. ¿Cómo es posible que la transforma para Consulta..? (Sigo jugando con sus explicaciones para entender cómo funciona. Gracias por esto!)
    • se ha añadido una (un poco largo) explicación acerca de este… También, busque en stackoverflow.com/questions/13454347/monads-with-java-8/… – me di cuenta de que es casi el mismo contenido.
    • Nota para aquellos que experimentan la misteriosa errores de compilación, el uso de foo.? para la Opción[T] columnas o usted conseguirá un difícil leer el tipo de desajuste. Gracias, Faiz!
    • Esta es una gran respuesta… sería genial, aunque si podría ser actualizado para Slick 3.0
  2. 6

    Ya que nadie ha respondido, esto podría ayudar a empezar. No sé Slick muy bien.

    De la Slick documentación:

    Levantó La Incrustación:

    Cada mesa requiere de un método de contatining un defecto de proyección. Este
    describe lo que se obtiene cuando se devuelven filas (en la forma de un
    objeto de tabla) a partir de una consulta. Del derrame * proyección no tiene que
    coincide con la de la base de datos. Usted puede agregar nuevas columnas (por ejemplo, con
    valores calculados) u omitir algunas columnas como desee. La no-levantó tipo
    correspondiente a la * proyección se da como un parámetro de tipo a
    Tabla. Simple, no asignado en las tablas, esta será una sola columna
    tipo o una tupla de tipos de columna.

    En otras palabras, una mancha necesita saber cómo lidiar con una fila que devuelve la base de datos. El método que define los usos de su analizador de combinador de funciones para combinar sus definiciones de columna en algo que puede ser utilizado en una fila.

    • ook. y la Proyección es sólo una representación de las columnas.. como: final de la clase Projection2[T1,T2]( override val _1: Columna[T1], anular val _2: Columna[T2] ) se extiende Tuple2(_1,_2) con la Proyección[(T1,T2)] { ..
    • Ahora.. ¿cómo es que: Bar tiene ‘deshacer’ método ?
    • Aha.. – todas las clases de aplicar el Producto rasgo, y deshacer es Producto del método. Magia.

Dejar respuesta

Please enter your comment!
Please enter your name here