我目前正在使用Slick codegen(版本3.2.0-M1)为数据库生成Slick代码。我的许多表包含相同的列(具有相同的名称和类型),因此我希望有一些方法可以通用方式对这些表执行操作,例如,可以从任何一个中选择行的泛型方法这些表基于特定的共享字段。
为此,我可以创建一个包含这些共享字段的特征,然后让Slick表类扩展它们或将它们混合在一起。理想情况下,我希望代码生成器添加{{1}或者extends <trait>
给我这些课程。
我发现生成器中有一个可重写的with <trait>
方法,但我希望避免直接使用代码,例如通过正则表达式。
我还没有在网上或Slick文档中发现任何使用代码生成器定制的简单解决方案,所以我想知道是否有人知道这是否可能。
答案 0 :(得分:3)
我设法使用从slick.codegen.AbstractSourceCodeGenerator
修改的代码覆盖了几个源代码生成器的可自定义方法:
/* `TableUtils` contains the definitions of the `GenericRow`
and `GenericTable` traits. */
override def code = "import data.TableUtils._\n" + super.code
override def Table = new Table(_) {
override def EntityType = new EntityTypeDef {
/* This code is adapted from the `EntityTypeDef` trait's `code` method
within `AbstractSourceCodeGenerator`.
All code is identical except for those lines which have a corresponding
comment above them. */
override def code = {
val args = columns.map(c=>
c.default.map( v =>
s"${c.name}: ${c.exposedType} = $v"
).getOrElse(
s"${c.name}: ${c.exposedType}"
)
).mkString(", ")
if(classEnabled){
/* `rowList` contains the names of the generated "Row" case classes we
wish to have extend our `GenericRow` trait. */
val newParents = if (rowList.contains(name)) parents :+ "GenericRow" else parents
/* Use our modified parent class sequence in place of the old one. */
val prns = (newParents.take(1).map(" extends "+_) ++ newParents.drop(1).map(" with "+_)).mkString("")
s"""case class $name($args)$prns"""
} else {
s"""type $name = $types
/** Constructor for $name providing default values if available in the database schema. */
def $name($args): $name = {
${compoundValue(columns.map(_.name))}
}
""".trim
}
}
}
override def TableClass = new TableClassDef {
/* This code is adapted from the `TableClassDef` trait's `code` method
within `AbstractSourceCodeGenerator`.
All code is identical except for those lines which have a corresponding
comment above them. */
override def code = {
/* `tableList` contains the names of the generated table classes we
wish to have extend our `GenericTable` trait. */
val newParents = if (tableList.contains(name)) parents :+ "GenericTable" else parents
/* Use our modified parent class sequence in place of the old one. */
val prns = newParents.map(" with " + _).mkString("")
val args = model.name.schema.map(n => s"""Some("$n")""") ++ Seq("\""+model.name.table+"\"")
s"""class $name(_tableTag: Tag) extends profile.api.Table[$elementType](_tableTag, ${args.mkString(", ")})$prns {
${indent(body.map(_.mkString("\n")).mkString("\n\n"))}
}
""".trim()
}
}
}
}
此解决方案适用于我的目的,但复制和修改源代码感觉有点不优雅。如果有人知道更好的方法,我很乐意看到你的想法。
答案 1 :(得分:0)
使用How to mix-in a trait to instance中列出的解决方案,回答了这个问题(我的问题也几乎和你的一样)。我们希望扩展Slick模型生成的代码而不修改它(或者就发生器而言)
此处适用于自我控制,便利性以及我所拥有的特定用例。这是我的Slick代码生成代码:
/** Table description of table user. Objects of this class serve as prototypes for rows in queries. */
class User(_tableTag: Tag) extends Table[UserRow](_tableTag, "user") { ... }
但是我需要我的User
Slick数据模型来实现be.objectify.deadbolt.java.models.Subject
Java接口,因此我可以将Deadbolt2用作我的Scala Play Web应用程序的一部分。
因此我会这样做:
import be.objectify.deadbolt.java.models.Subject
/**
* Mixin framework or infrastructural code
*/
trait DynamicMixinCompanion[TT] {
implicit def baseObject[OT](o: Mixin[OT]): OT = o.obj
def ::[OT](o: OT): Mixin[OT] with TT
class Mixin[OT] protected[DynamicMixinCompanion](val obj: OT)
}
/**
* Subject Mixin implementation
*/
object SubjectMixinHelper extends DynamicMixinCompanion[Subject] {
def ::[T](o: T) = new Mixin(o) with Subject {
def getPermissions = ...
def getRoles = ...
}
}
最后:
import SubjectMixinHelper._
withSession{ implicit session =>
val user = Query(User).where(_.id === id).firstOption :: Subject
// then use user as a Subject too
user.getPermissions
user.getRoles
}
请注意,我还没有测试过(但我很快就会)
答案 2 :(得分:0)
如果您想为每个生成的表添加特征,您需要覆盖 TableClass 和 EntityType 代码生成器特征中的父方法:
class ExtSourceCodeGenerator(model: m.Model) extends SourceCodeGenerator(model: m.Model) {
//Import packages with your traits
override def code: String = "import models._\n" + super.code
override def Table = new Table(_) {
override def TableClass = new TableClass {
//Add custom traits to Table classes
override def parents: Seq[String] = {
Seq("IdentityTable")
}
}
override def EntityType = new EntityType {
//Add custom traits to rows
override def parents: Seq[String] = {
Seq("Entity")
}
}
}
}
如果您需要过滤某些表格,可以使用 model 字段获取当前表格名称:
model.name.table
希望这会对你有所帮助。