Во-первых, этот case-класс — плохая идея:
case class BasicProfile()
Классы Case сравниваются по значениям членов, у этого их нет. Также название не очень удачное, потому что у нас такое же имя в Slick. Может вызвать путаницу.
Что касается вашего класса
class User(...) extends BasicProfile(...){
...
def unapply(i:User):Tuple12[...]= Tuple12(...)
}
Можно самостоятельно эмулировать case-классы. Вы делаете это из-за ограничения в 22 поля? К вашему сведению: Scala 2.11 поддерживает более крупные классы case. Мы делаем то же, что и вы, в Sport195, но есть несколько аспектов, о которых нужно позаботиться.
apply
и unapply
должны быть членами object User
(сопутствующего объекта class User
). .tupled
не является реальным методом, он автоматически генерируется компилятором Scala. он превращает такой метод, как .apply
, который принимает список аргументов, в функцию, которая принимает один кортеж этих аргументов. Поскольку кортежи ограничены 22 столбцами, то же самое и с .tupled
. Но вы, конечно, можете автоматически сгенерировать его самостоятельно, возможно, придется дать ему другое имя.
Мы используем генератор кода Slick в сочетании с механизмом шаблонов twirl (использует @
для вставки выражений. $
вставляются как бы в сгенерированный код Scala и оцениваются при компиляции/запуске сгенерированного кода). Вот несколько фрагментов, которые могут вам помочь:
Создать метод применения
/** 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 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(",")})"
...
case-класс, такой как метод .copy
final def copy(
@{indentN(2,columnsCopy)}
): @{name} = @{name}(@{columnsCSV})
Чтобы использовать эти классы со Slick, у вас есть несколько вариантов. Все они несколько новее и не документированы (хорошо). Обычный оператор <>
Slick проходит через кортежи, но это не вариант для > 22 столбцов. Одним из вариантов являются новые преобразователи fastpath. Другой вариант — отображение через Slick HList. Ни для того, ни для другого примеров не существует. Другой вариант — через пользовательскую форму, что мы и делаем. Это потребует от вас определения пользовательской формы для вашего класса User
и другого класса, определенного с использованием типов Column
, для отражения пользователя в запросах. Вот так: http://slick.typesafe.com/doc/2.1.0/api/#scala.slick.lifted.ProductClassShape Слишком многословно, чтобы писать вручную. Для этого мы используем следующий код шаблона:
/** 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:
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.
person
cvogt
schedule
05.08.2014
Table
. - person Ende Neu   schedule 05.08.2014