4

Scala Slick を使用したデータ アクセス レイヤーがどのように見えるべきかについての考えはありますが、それが本当に可能かどうかはわかりません。

ID、メール、パスワードなどの通常のフィールドを持つ User テーブルがあるとします。

  object Users extends Table[(String, String, Option[String], Boolean)]("User") {
    def id = column[String]("id", O.PrimaryKey)
    def email = column[String]("email")
    def password = column[String]("password")
    def active = column[Boolean]("active")
    def * = id ~ email ~ password.? ~ active
  }

そして、私はさまざまな方法でそれらを照会したいと考えています。現在、醜い方法は、新しいデータベースセッションを作成し、for 内包を実行してから、別の if ステートメントを実行して、目的を達成することです。

例えば

  def getUser(email: String, password: String): Option[User] = {
    database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
          if user.email === email &&
             user.password === password &&
             user.active === true
      } //yield and map to user class, etc...
  }

  def getUser(identifier: String): Option[User] = {
    database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
        if user.id === identifier &&
           user.active === true
      } //yield and map to user class, etc...
  }

私が好むのは、クエリのプライベートメソッドと、次の行に沿ってクエリを定義するパブリックメソッドを持つことです

type UserQuery = User => Boolean

private def getUserByQuery(whereQuery: UserQuery): Option[User] = {
  database withSession { implicit session: Session =>
      val queryUser = (for {
        user <- Users
          somehow run whereQuery here to filter
      } // yield and boring stuff
  }

def getUserByEmailAndPassword(email, pass){ ... define by query and call getUserByQuery ...}

getUserById(id){….}

getUserByFoo{….} 

このようにして、クエリ ロジックは関連するパブリック関数にカプセル化され、ユーザー オブジェクトへの実際のクエリとマッピングは、他の人が関与する必要のない再利用可能な関数になります。

私が抱えている問題は、「where」ビットを、渡すことができる関数にリファクタリングしようとすることです。intellij でそれらを選択し、リファクタリングを使用するなどのことをしようとすると、かなりクレイジーなタイピングが行われます。

私が達成しようとしていることに近いことを示すことができる例はありますか?

4

2 に答える 2

6

1) クエリを def でラップすると、リクエストごとにクエリ ステートメントが再生成され、クエリ パラメータがバインドされていないため、準備されたステートメントが基になる DBMS に渡されないことを意味します。

2) コンポジションを利用していない

代わりに、def クエリ ラッパーが呼び出すパラメーター化されたクエリ val を定義すると、両方の長所を活かすことができます。

val uBase = for{
  u  <- Users
  ur <- UserRoles if u.id is ur.UserID
} yield (u,ur)

// composition: generates prepared statement one time, on startup
val byRole = for{ roleGroup <- Parameters[String]
  (u,ur) <- uBase
  r <- Roles if(r.roleGroup is roleGroup) && (r.id is ur.roleID)
} yield u

def findByRole(roleGroup: RoleGroup): List[User] = {
  db withSession { implicit ss:SS=>
    byRole(roleGroup.toString).list
  }
}

1 つのプロパティに対して 1 回限りのファインダーが必要な場合は、次を使用します。

val byBar = Foo.createFinderBy(_.bar)
val byBaz = Foo.createFinderBy(_.baz)

おそらくSO、またはSlickユーザーグループのどこかを思い出せませんが、基本的にcreateFinderByはステロイドで、複数のバインドされたパラメーターを許可する非常に創造的なソリューションを見ました。ただし、ソリューションは単一のマッパー/テーブル オブジェクトに限定されていたため、私にはあまり役に立ちませんでした。

とにかく、理解のために作曲することは、あなたがやろうとしていることをしているようです。

于 2013-01-24T13:59:11.277 に答える