2013-12-10 64 views
7

我正在使用Scala,並且新增了Play和Slick。我開始阻止一個簡單的數據庫結構,我不確定處理外鍵和投影的正確方法。在頁面底部的示例中,它目前不編譯,因爲ForeignKey無法直接解除,那麼將查詢結果提升到我的類型(基本上這是無法使用的方法和附加構造函數)的正確方法是什麼:在Scala-Slick中輸入外鍵

case class UserCompanyPermission(pk: UUID, company: Company, user: User, accessLevel: CompanyPermissionLevel) 

要麼我想要類型投影返回一個UserCompanyPermission,否則有一種方法來包裝一切進出DAO方法,所以從外面我只是通過我的Scala類型。基本上我想確保我的業務邏輯完全與狀態分離,使測試變得更加容易,因此能夠將所有表格細節都限制在這個存儲包中。是他們的包裝方式,還是我在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

此外,我知道這個問題,但它並沒有真正詳細說明什麼是正確的設計方法,將保持乾燥。 http://stackoverflow.com/questions/17830492/how-to-use-slicks-mapped-tables-with-foreign-keys – MalucoMarinero

回答

6

與Slick一起工作的推薦方法是永遠不會嵌套持有行的值的case類。它們應該只包含實際的列,而不包含任何相關的對象,因爲那樣會硬編碼它們必須一起加載(除非你在引擎蓋下進行一些神奇的延遲加載,這使得使用和實現變得複雜)。相反,您可以編寫查詢,將您現在使用元組所需的特定數據的值關聯起來。

// 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孩子而EnumerationCompanyPermissionLevel

+0

是的,這很有道理。我想對我來說,這似乎是來自主要Python/Django背景的意外限制,但當然這是以類型安全的方式執行不會手銬使用數據庫的唯一方法。歡迎關於枚舉的提示。 – MalucoMarinero

+0

我認爲這更有效的ORM - >關係/功能混淆。 ORM使用懶加載魔術來釋放袖口。 Slick認爲,當涉及到關係時,顯式比隱式更好。歡迎來到斯卡拉土地:)。 – cvogt