2013-12-10 13 views
7

私はScalaを使い、PlayとSlickを初めて使っています。私は単純なデータベース構造をブロックし始めています。私は外部キーと投影を扱う正しい方法についてはわかりません。ページ下部の例では、ForeignKeyを直接持ち上げることができないため、現在のところコンパイルされません。クエリ結果を自分の型に持ち上げる正しい方法は何ですか(これは基本的にはこのメソッドと追加のコンストラクタです)。Scala-Slickでの外部キーの投影

私は、型投影からUserCompanyPermissionを返すようにしたいと思います。そうしないと、DAOメソッドの出入りするすべてのものを外部からラップする方法があります。私はスカラ型を渡しています。私のビジネスロジックは状態から完全に切り離されてテストが容易になり、すべてのテーブルの詳細をこのストレージパッケージに限定することができます。ラップする方法はありますか、DAOオブジェクトに書き込む各メソッドは、変換を単独で行う必要がありますか?

trait CompaniesComponent { this: UsersComponent => 
    val Companies: Companies 
    val UserCompanyPermissions: UserCompanyPermissions 

    implicit val companyPermissionLevelTypeMapper = MappedTypeMapper.base[CompanyPermissionLevel.Value, Int](
    { level => level.id }, { id => CompanyPermissionLevel(id) } 
) 

    class Companies extends Table[Company]("Company") { 
    def pk = column[UUID]("pk", O.PrimaryKey) 
    def subdomain = column[String]("subdomain", O.NotNull) 
    def name = column[String]("name", O.NotNull) 

    def * = pk ~ subdomain ~ name <> (Company.apply _, Company.unapply _) 
    } 


    class UserCompanyPermissions extends Table[UserCompanyPermission]("UserCompanyPermission") { 

    def pk = column[UUID]("pk", O.PrimaryKey) 
    def company_pk = column[UUID]("company_pk", O.NotNull) 
    def user_pk = column[UUID]("user_pk", O.NotNull) 
    def accessLevel = column[CompanyPermissionLevel.Value]("access_level", O.NotNull) 

    def company = foreignKey("company_pk", company_pk, Companies)(_.pk) 
    def user = foreignKey("user_pk", user_pk, Users)(_.pk) 

    def * = pk ~ company ~ user ~ accessLevel <> (UserCompanyPermission.apply _, UserCompanyPermission.unapply _) 
    } 

} 


object Companies extends DAO { 
    def insert(company: Company)(implicit session: Session) { 
    Companies.insert(company) 
    } 
} 

object UserCompanyPermissions extends DAO { 
    def insert(perm: UserCompanyPermission)(implicit session: Session) { 
    UserCompanyPermissions.insert(perm) 
    } 
} 
+0

また、私はこの質問に気づいていますが、物事をDRYに保つ正しい設計アプローチが何であるかについて詳しくは実際にはわかりません。 http://stackoverflow.com/questions/17830492/how-to-use-slicks-mapped-tables-with-foreign-keys – MalucoMarinero

答えて

6

Slickを使用する場合は、行の値を保持するケースクラスをネストしないことをお勧めします。関連するオブジェクトではなく実際の列のみを含むべきです。なぜなら、それらが一緒にロードされなければならないハードコードなのです(フードの下でいくつかの怠惰な読み込みが行われ、使用と実装が複雑になります)。代わりに、タプルを使用して今すぐ必要な特定のデータの値を関連付けるクエリを記述します。

// FYI 
case class UserCompanyPermission(pk: UUID, company_pk: UUID, user_pk: UUID, accessLevel: CompanyPermissionLevel.Value) 

// associating data in an ad-hoc, not hard-coded way 
for(ucp <- Query(UserCompanyPermissions).filter(_.accessLevel === LevelOne); 
    c <- ucp.company; 
    u <- ucp.user 
) yield (u,c) 

ここではuとcを読み込みます。私たちはuまたはcまたはcとucpなどをロードしただけでした。私たちの行クラスではハードコードされていません。

アーキテクチャに関しては、Scala Days 2013の講演とScala Exchange 2013の講演で役立ちます。 http://slick.typesafe.com/docs/

側ノードとして、私はsealed traitcase objectを持つ子どもの代わりに、CompanyPermissionLevelためEnumerationをお勧めします。

+0

ええ、それは十分な意味があります。私は、プライマリのPython/Djangoのバックグラウンドから予期しない制限があるように思えますが、もちろん、データベースの使用を手錠ではなくタイプセーフな方法で行うことができる唯一の方法です。 Enumerationに関してもヒントをお伝えします。 – MalucoMarinero

+0

私はこれが有効なORM - >リレーショナル/機能混乱だと思います。 ORMは怠惰なローディングマジックを使用して袖口を解放します。 Slickは、関係について言えば、明示的は明示的ではないと考えています。 Scala landへようこそ:)。 – cvogt