在Scala-Slick中键入外键的投影 [英] Type Projection of Foreign Keys in Scala-Slick

查看:163
本文介绍了在Scala-Slick中键入外键的投影的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用的是Scala,还有Play和Slick的新功能。我开始阻止一个简单的数据库结构,我不知道正确的方法来处理外键和投影。在页面底部的示例中,它目前不编译,因为一个ForeignKey不能直接解除,所以什么是正确的方法来查询结果升级到我的类型(这基本上是sans方法和附加构造函数):

I'm using Scala, and new to Play and Slick. I'm starting to block out a simple database structure and I'm not sure about the correct way to handle foreign keys and projections. In the example at page bottom it currently doesn't compile because a ForeignKey cannot be lifted directly, so what's the correct way to have query results lift into my type (which is basically this sans methods and additional constructors):

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

我想让类型投影返回一个UserCompanyPermission,否则有一个方法来包装进入和退出DAO方法,所以从外部我只是传递我的Scala类型。基本上,我想要确保我的业务逻辑是完全从状态脱钩,使其更容易测试,所以能够保持所有表的具体限制到这个存储包。是他们的包装方式,还是我写在DAO对象中的每个方法需要自己进行转换?

Either I'd like to have the type projection return a UserCompanyPermission, otherwise have a way to wrap everything coming into and out of the DAO methods so from the outside I'm just passing my Scala Types in. Basically I want to ensure my business logic is entirely decoupled from state to make it easier to test, so being able to keep all table specifics restricted to this storage package. Is their way to wrap, or is each method I write in the DAO object going to need to make the conversion on its own?

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


推荐答案

推荐使用Slick的方法是不要嵌套包含行的值的case类。它们应该只包含实际的列,而不是任何相关的对象,因为这将硬代码,他们必须加载在一起(除非你做一些神奇的延迟加载下,使事情复杂的使用和实现)。

The recommended way to work with Slick is to never nest the case classes holding the values of your rows. They should only contain the actual columns, not any related objects, because that would hard-code that they have to be loaded together (unless you do some magical lazy loading under the hood which makes things complex for use and implementation). Instead you write queries, that associate the values for the particular data you need right now using tuples.

// 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或任何。它不是硬编码在我们的行类。

Here we load u and c because we say so. We could have only loaded u or c or c and ucp or whatever. It is not hardcoded in our row classes.

在架构方面,你会在我们的Scala Days 2013谈话和Scala Exchange 2013谈话中找到帮助。 http://slick.typesafe.com/docs/

Architecture-wise, you will find help in our Scala Days 2013 talk and the Scala Exchange 2013 talk. http://slick.typesafe.com/docs/

作为一个边结点,我会推荐一个 sealed trait case对象子代而不是 Enumeration CompanyPermissionLevel

As a side node I would recommend a sealed trait with case object children instead of Enumerationfor CompanyPermissionLevel.

这篇关于在Scala-Slick中键入外键的投影的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆