5

現在、Slick codegen (バージョン 3.2.0-M1) を使用して、データベースの Slick コードを生成しています。私のテーブルの多くには同じ列 (同じ名前と型) が含まれているため、これらのテーブルに対して一般的な方法で操作を実行できるいくつかのメソッドが必要です。これらのテーブルは、特定の共有フィールドに基づいています。

これを行うには、これらの共有フィールドを含むトレイトを作成し、Slick テーブル クラスにそれらを拡張または混在させることができます。理想的には、コード ジェネレーターにこれらのクラスに追加extends <trait>または追加してもらいたいと考えています。with <trait>

ジェネレーターにオーバーライド可能なメソッドがあることがわかりましたがcode、正規表現などを介してコードを直接いじる必要は避けたいと思います。

コード ジェネレーターのカスタマイズを使用した簡単な解決策を示すオンラインまたは Slick のドキュメントを見つけられなかったので、これが可能かどうかを誰かが知っているかどうか疑問に思っていました。

4

3 に答える 3

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()
      }
    }
  }
}

このソリューションは私の目的には合っていますが、ソース コードをコピーして変更するのは少し洗練されていないように感じます。誰かがこれを行うためのより良い方法を知っている場合は、あなたが思いついたものを見てみたい.

于 2016-09-22T19:25:48.903 に答える
0

How to mix-in a trait to instanceで概説されている解決策を使用して、この質問に答えます (そして私の質問もあなたのものとほぼ同じです)。Slickモデルで生成されたコードを変更せずに拡張したい(またはジェネレーター)

自己完結型、利便性、および私が持っていた特定のユースケースに合わせてここに適応しました。これは私の Slick code-gen 生成コードです:

/** 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") { ... }

しかし、 Deadbolt2を Scala Play Web アプリケーションの一部として使用できるように、Java インターフェースUserを実装するために Slick データ モデルが必要です。be.objectify.deadbolt.java.models.Subject

したがって、私は次のようにします:

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
}

まだテストしていないことに注意してください(ただし、すぐにテストします)

于 2016-11-21T22:18:10.037 に答える