2016-09-15 47 views
4

我目前使用Slick codegen(版本3.2.0-M1)为数据库生成Slick代码。我的很多表都包含相同的列(具有相同的名称和类型),所以我希望有一些方法可以通用方式对这些表执行操作,例如,可以从任何这些表格基于特定的共享字段。是否有可能自定义生成的代码生成类扩展自定义特征?

要做到这一点,我可以创建将包含这些共享的域,然后有油滑的表类扩展它们或它们在理想情况下,我想有代码生成添加extends <trait>with <trait>这些。混个特征为我而设的课程。

我看到,有在所述发电机的覆写投放code的方法,但我想避免乱用的代码直接,例如通过正则表达式。

我没有发现任何在线或倾向于使用代码生成自定义一个简单的解决指明了油滑文档中,所以我想知道是否有任何人知道,如果这甚至有可能。

回答

1

我已经成功地覆盖几个使用修改后的代码的源代码生成的定制方法从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() 
     } 
    } 
    } 
} 

该解决方案适用于我的目的,但复制和修改源代码的感觉有点不雅。如果有人知道更好的方法来做到这一点,我很乐意看到你的想法。

+0

哇,你找到了解决办法。诚然!不是很漂亮,但哎! code-gen只是运行天堂,并得到你的干净的Scala数据模型。这就是说。我认为可能有一种方法可以在Scala中做到这一点。我正在检查,因为我有一个类似的用例,可以在不更改代码的情况下为某个类动态添加功能。 –

0

使用在How to mix-in a trait to instance列出的解决方案,回答了这个问题(和我的问题也几乎是完全一样你的)。我们希望在不修改它(或为此事发电机)延长斯利克模型生成的代码

这里适合自我封闭,方便性和具体使用情况我了。这是我的油滑的代码生成器生成的代码:

/** 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油滑的数据模型来实现be.objectify.deadbolt.java.models.Subject Java接口,所以我可以用Deadbolt2我的斯卡拉剧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 
} 

请注意,我没有测试它尚未(但我会很快)

0

如果你想添加特征到您需要覆盖的每个生成表格父母方法表类E ntityType特征代码生成的:

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.name.table 

希望这会帮助你。