2016-09-15 76 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 

希望這會幫助你。