如何编写slick2的类和表类映射而不是使用case类? [英] How to write class and tableclass mapping for slick2 instead of using case class?

查看:103
本文介绍了如何编写slick2的类和表类映射而不是使用case类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我以前使用case类将类对象转换为slick2的数据,但是当前我使用另一个play插件,plugin对象使用case类,我的类是该case类所固有的.因此,我不能将案例类用作Scala语言,禁止将案例类用于固有的案例类.

I use case class to transform the class object to data for slick2 before, but current I use another play plugin, the plugin object use the case class, my class is inherent from this case class. So, I can not use case class as the scala language forbidden use case class to case class inherent.

之前:

case class User()

class UserTable(tag: Tag) extends Table[User](tag, "User") {
  ...
  def * = (...)<>(User.tupled,User.unapply)
}

有效. 但是现在我需要从上到下更改:

it works. But now I need to change above to below:

case class BasicProfile()

class User(...) extends BasicProfile(...){
  ...
  def unapply(i:User):Tuple12[...]= Tuple12(...)
}
class UserTable(tag: Tag) extends Table[User](tag, "User") {
  ...
  def * = (...)<>(User.tupled,User.unapply)
}

我不知道如何编写元组和unapply(我不是我的写作正确与否)方法,例如自动生成案例类模板的方法.或者,您可以使用slick2将类映射到talbe的其他方法.

I do not know how to write the tupled and unapply(I am not my writing is correct or not) method like the case class template auto generated. Or you can should me other way to mapping the class to talbe by slick2.

任何人都可以给我举个例子吗?

Any one can give me an example of it?

推荐答案

首先,此案例类是个坏主意:

First of all, this case class is a bad idea:

case class BasicProfile()

案例类通过其成员值进行比较,这一类没有任何成员值.这个名字也不是很好,因为我们在Slick中有相同的名字.可能会引起混乱.

Case classes compare by their member values, this one doesn't have any. Also the name is not great, because we have the same name in Slick. May cause confusion.

关于您的课程

class User(...) extends BasicProfile(...){
  ...
  def unapply(i:User):Tuple12[...]= Tuple12(...)
}

可以自己模拟案例类.您是否因为22个字段限制而这样做?仅供参考:Scala 2.11支持更大的案例类.我们正在为您在Sport195上所做的工作,但是有几个方面需要注意.

It is possible to emulate case classes yourself. Are you doing that because of the 22 field limit? FYI: Scala 2.11 supports larger case classes. We are doing what you are trying at Sport195, but there are several aspects to take care of.

applyunapply必须是object User(class User的伴随对象)的成员. .tupled不是真正的方法,而是由Scala编译器自动生成的.它将.apply之类的方法变为将参数列表带入一个仅接受这些参数的元组的函数.由于元组限制为22列,因此.tupled也是如此.但是您当然可以自己自动生成一个,可能必须给它起另一个名字.

apply and unapply need to be members of object User (the companion object of class User). .tupled is not a real method, but generated automatically by the Scala compiler. it turns a method like .apply that takes a list of arguments into a function that takes a single tuple of those arguments. As tuples are limited to 22 columns, so is .tupled. But you could of course auto-generated one yourself, may have to give it another name.

我们正在将Slick代码生成器与twirl模板引擎结合使用(使用@来插入表达式.$就像在生成的Scala代码中一样被插入,并在编译/运行生成的代码时对其进行评估. ).以下几段代码可能对您有所帮助:

We are using the Slick code generator in combination with twirl template engine (uses @ to insert expressions. The $ are inserted as if into the generated Scala code and evaluated, when the generated code is compiled/run.). Here are a few snippets that may help you:

生成申请方法

  /** Factory for @{name} objects
    @{indentN(2,entityColumns.map(c => "* @param "+c.name+" "+c.doc).mkString("\n"))}
    */
  final def apply(
    @{indentN(2,
        entityColumns.map(c =>
          colWithTypeAndDefault(c)
        ).mkString(",\n")
    )}
  ) = new @{name}(@{columnsCSV})

生成未应用的方法:

@{if(entityColumns.size <= 22)
  s"""
  /** Extractor for ${name} objects */
  final def unapply(o: ${name}) = Some((${entityColumns.map(c => "o."+c.name).mkString(", ")}))
  """.trim
  else
  ""}

可以混入User使其成为Scala产品的特质:

Trait that can be mixed into User to make it a Scala Product:

trait UserBase with Product{
  // Product interface
  def canEqual(that: Any): Boolean = that.isInstanceOf[@name]
  def productArity: Int = @{entityColumns.size}
  def productElement(n: Int): Any = Seq(@{columnsCSV})(n)

  override def toString = @{name}+s"(${productIterator.toSeq.mkString(",")})"
...

类似于.copy方法的案例类

  final def copy(
    @{indentN(2,columnsCopy)}
  ): @{name} = @{name}(@{columnsCSV})

要将这些类与Slick一起使用,您可以有几种选择.所有这些都是较新的并且没有记录(很好).普通的<>运算符Slick通过元组,但是对于> 22列不是这样的选择.一种选择是新的快速路径转换器.另一种选择是通过Slick HList进行映射.都不存在任何示例.另一个选择是通过自定义Shape进行操作,这就是我们要做的.这将要求您为User类和使用Column类型定义的另一个类定义自定义形状,以在查询中镜像用户.像这样: http://slick.typesafe.com/doc/2.1.0/api/#scala.slick.lifted.ProductClassShape 太冗长,无法手工书写.为此,我们使用以下模板代码:

To use those classes with Slick you have several options. All are somewhat newer and not documented (well). The normal <> operator Slick goes via tuples, but that's not an option for > 22 columns. One option are the new fastpath converters. Another option is mapping via a Slick HList. No examples exist for either. Another option is going via a custom Shape, which is what we do. This will require you to define a custom shape for your User class and another class defined using Column types to mirror user within queries. Like this: http://slick.typesafe.com/doc/2.1.0/api/#scala.slick.lifted.ProductClassShape Too verbose to write by hand. We use the following template code for this:

/** class for holding the columns corresponding to @{name}
 * used to identify this entity in a Slick query and map
 */
class @{name}Columns(
  @{indent(
    entityColumns
      .map(c => s"val ${c.name}: Column[${c.exposedType}]")
      .mkString(", ")
  )}
) extends Product{
  def canEqual(that: Any): Boolean = that.isInstanceOf[@name]
  def productArity: Int = @{entityColumns.size}
  def productElement(n: Int): Any = Seq(@{columnsCSV})(n)
}

/** shape for mapping @{name}Columns to @{name} */
object @{name}Implicits{
  implicit object @{name}Shape extends ClassShape(
    Seq(@{
      entityColumns
        .map(_.exposedType)
        .map(t => s"implicitly[Shape[ShapeLevel.Flat, Column[$t], $t, Column[$t]]]")
        .mkString(", ")
    }),
    vs => @{name}(@{
      entityColumns
        .map(_.exposedType)
        .zipWithIndex
        .map{ case (t,i) => s"vs($i).asInstanceOf[$t]" }
        .mkString(", ")
    }),
    vs => new @{name}Columns(@{
      entityColumns
        .map(_.exposedType)
        .zipWithIndex
        .map{ case (t,i) => s"vs($i).asInstanceOf[Column[$t]]" }
        .mkString(", ")
    })
  )
}
import @{name}Implicits.@{name}Shape

我们在Slick代码生成器中添加了一些帮助程序:

A few helpers we put into the Slick code generator:

  val columnsCSV = entityColumns.map(_.name).mkString(", ")
  val columnsCopy = entityColumns.map(c => colWithType(c)+" = "+c.name).mkString(", ")
  val columnNames = entityColumns.map(_.name.toString)


  def colWithType(c: Column) = s"${c.name}: ${c.exposedType}"

  def colWithTypeAndDefault(c: Column) =
    colWithType(c) + colDefault(c).map(" = "+_).getOrElse("")

  def indentN(n:Int,code: String): String = code.split("\n").mkString("\n"+List.fill(n)(" ").mkString(""))

我知道复制可能会有些麻烦,特别是如果您是Scala的新手.我希望找到时间在某个时候进入官方Slick代码生成器.

I know this may a bit troublesome to replicate, especially if you are new to Scala. I hope to to find the time get it into the official Slick code generator at some point.

这篇关于如何编写slick2的类和表类映射而不是使用case类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆