62

Play Framework 2.1 でSlickを使用していますが、いくつか問題があります。

次のエンティティが与えられた場合...

package models

import scala.slick.driver.PostgresDriver.simple._

case class Account(id: Option[Long], email: String, password: String)

object Accounts extends Table[Account]("account") {
  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
  def email = column[String]("email")
  def password = column[String]("password")
  def * = id.? ~ email ~ password <> (Account, Account.unapply _)
}

...特定のデータベース ドライバーのパッケージをインポートする必要がありますが、H2テスト用に使用し、PostgreSQL運用環境に使用したいと考えています。どのように進めればよいですか?

単体テストでドライバー設定をオーバーライドすることで、これを回避できました。

package test

import org.specs2.mutable._

import play.api.test._
import play.api.test.Helpers._

import scala.slick.driver.H2Driver.simple._
import Database.threadLocalSession

import models.{Accounts, Account}

class AccountSpec extends Specification {

  "An Account" should {
    "be creatable" in {
      Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver") withSession {
        Accounts.ddl.create                                                                                                                                          
        Accounts.insert(Account(None, "user@gmail.com", "Password"))
        val account = for (account <- Accounts) yield account
        account.first.id.get mustEqual 1
      }
    }
  }
}

私はこの解決策が好きではありません.DBに依存しないコードを書くためのエレガントな方法があるかどうか疑問に思っています.2つの異なるデータベースエンジンが使用されています.1つはテスト用で、もう1つは本番用ですか?

私も進化を使いたくないので、Slick にデータベース テーブルを作成してもらいたいと思います。

import play.api.Application
import play.api.GlobalSettings
import play.api.Play.current
import play.api.db.DB

import scala.slick.driver.PostgresDriver.simple._
import Database.threadLocalSession

import models.Accounts

object Global extends GlobalSettings {

  override def onStart(app: Application) {
    lazy val database = Database.forDataSource(DB.getDataSource())

    database withSession {
      Accounts.ddl.create
    }
  }
}

最初にアプリケーションを起動すると、すべてが正常に機能します...もちろん、アプリケーションを 2 回目に起動すると、テーブルが PostgreSQL データベースに既に存在するため、アプリケーションがクラッシュします。

そうは言っても、私の最後の2つの質問は次のとおりです。

  1. データベース テーブルが既に存在するかどうかを確認するにはどうすればよいですか?
  2. onStartでアプリケーションをテストできるように、上記のメソッドを DB に依存しないようにするにはどうすればよいFakeApplicationですか?
4

4 に答える 4

39

Cake パターン/依存性注入を使用して Slick ドライバーをデータベース アクセス レイヤーから分離する方法の例は、https ://github.com/slick/slick-examples にあります。

Slick ドライバーとテスト アプリケーションを FakeApplication で分離する方法

数日前、私は Play 用の Slick 統合ライブラリを作成しました。これは、ドライバーの依存関係を Play プロジェクトの application.conf に移動します: https://github.com/danieldietrich/slick-integration

このライブラリの助けを借りて、例は次のように実装されます。

1) 依存関係を project/Build.scala に追加します

"net.danieldietrich" %% "slick-integration" % "1.0-SNAPSHOT"

スナップショット リポジトリの追加

resolvers += "Daniel's Repository" at "http://danieldietrich.net/repository/snapshots"

または、slick-integration がローカルで公開されている場合は、ローカル リポジトリ

resolvers += Resolver.mavenLocal

2) Slick ドライバーを conf/application.conf に追加します。

slick.default.driver=scala.slick.driver.H2Driver

3) app/models/Account.scala を実装する

スムーズな統合の場合、自動インクリメントされる Long 型の主キーを使用することが想定されています。pk 名は「id」です。テーブル/マッパーの実装には、デフォルトのメソッド (delete、findAll、findById、insert、update) があります。エンティティは、'insert' メソッドで必要な 'withId' を実装する必要があります。

package models

import scala.slick.integration._

case class Account(id: Option[Long], email: String, password: String)
    extends Entity[Account] {
  // currently needed by Mapper.create to set the auto generated id
  def withId(id: Long): Account = copy(id = Some(id))
}

// use cake pattern to 'inject' the Slick driver
trait AccountComponent extends _Component { self: Profile =>

  import profile.simple._

  object Accounts extends Mapper[Account]("account") {
    // def id is defined in Mapper
    def email = column[String]("email")
    def password = column[String]("password")
    def * = id.? ~ email ~ password <> (Account, Account.unapply _)
  }

}

4) app/models/DAL.scala を実装する

これは、コントローラーがデータベースにアクセスするために使用するデータ アクセス レイヤー (DAL) です。トランザクションは、対応するコンポーネント内のテーブル/マッパーの実装によって処理されます。

package models

import scala.slick.integration.PlayProfile
import scala.slick.integration._DAL
import scala.slick.lifted.DDL

import play.api.Play.current

class DAL(dbName: String) extends _DAL with AccountComponent
    /* with FooBarBazComponent */ with PlayProfile {

  // trait Profile implementation
  val profile = loadProfile(dbName)
  def db = dbProvider(dbName)

  // _DAL.ddl implementation
  lazy val ddl: DDL = Accounts.ddl // ++ FooBarBazs.ddl

}

object DAL extends DAL("default")

5) test/test/AccountSpec.scala を実装する

package test

import models._
import models.DAL._
import org.specs2.mutable.Specification
import play.api.test.FakeApplication
import play.api.test.Helpers._
import scala.slick.session.Session

class AccountSpec extends Specification {

  def fakeApp[T](block: => T): T =
    running(FakeApplication(additionalConfiguration = inMemoryDatabase() ++
        Map("slick.default.driver" -> "scala.slick.driver.H2Driver",
          "evolutionplugin" -> "disabled"))) {
      try {
        db.withSession { implicit s: Session =>
          try {
            create
            block
          } finally {
            drop
          }
        }
      }
    }

  "An Account" should {
    "be creatable" in fakeApp {
      val account = Accounts.insert(Account(None, "user@gmail.com", "Password"))
      val id = account.id
      id mustNotEqual None 
      Accounts.findById(id.get) mustEqual Some(account)
    }
  }

}

データベース テーブルが既に存在するかどうかを確認する方法

この質問に十分な答えを出すことはできません...

...しかし、おそらくこれはあなたがやりたいことではありません。たとえば、テーブルに属性を追加するとどうなるでしょAccount.activeうか? テーブル内に現在格納されているデータを保護したい場合は、alter スクリプトがその役割を果たします。現在、このような変更スクリプトは手動で作成する必要があります。を使用DAL.ddl.createStatementsして、create ステートメントを取得できます。以前のバージョンと比較しやすいように並べ替える必要があります。次に、差分 (以前のバージョンとの) を使用して手動で変更スクリプトを作成します。ここでは、db スキーマを変更するために進化が使用されます。

(最初の) 進化を生成する方法の例を次に示します。

object EvolutionGenerator extends App {

  import models.DAL

  import play.api.test._
  import play.api.test.Helpers._

    running(FakeApplication(additionalConfiguration = inMemoryDatabase() ++
        Map("slick.default.driver" -> "scala.slick.driver.PostgresDriver",
          "evolutionplugin" -> "disabled"))) {


    val evolution = (
      """|# --- !Ups
         |""" + DAL.ddl.createStatements.mkString("\n", ";\n\n", ";\n") +
      """|
         |# --- !Downs
         |""" + DAL.ddl.dropStatements.mkString("\n", ";\n\n", ";\n")).stripMargin

    println(evolution)

  }

}
于 2012-12-02T02:31:42.160 に答える
2

play-slickは、他の回答で提案されているものとまったく同じことを行い、Play/Typesafe の傘下にあるようです。

インポートするだけimport play.api.db.slick.Config.driver.simple._ で、 に従って適切なドライバーが選択されconf/application.confます。

また、接続プーリング、DDL 生成などの機能も提供しています...

于 2015-01-27T15:39:36.390 に答える
-1

私のように、Play! を使っていないのなら。プロジェクトの場合、ソリューションは Nishruu によって提供されています。

于 2016-12-21T17:38:50.800 に答える