【问题标题】:Slick: Codegen foreign key referencesSlick:Codegen 外键引用
【发布时间】:2014-06-30 07:10:08
【问题描述】:

我正在使用slick 2.x's codegen 功能从数据库模式生成 Scala 模型。但是,是否可以遍历外键约束来生成相关模型,例如如果我有这个架构

CREATE TABLE people(id INT PRIMARY KEY AUTO INCREMENT, name VARCHAR(31));
CREATE TABLE dogs(name VARCHAR(31), ownerId INT FOREIGN KEY people(id));

我从 slick 获得以下模型:

case class PeopleRow(id: Int, name: String)
case class DogsRow(name: String, ownerId: Int)

但是,我真正想要的是:

case class PeopleRow(id: Int, name: String)
case class DogsRow(name: String, owner: PeopleRow)

甚至更好:

case class PeopleRow(id: Int, name: String) {
  def dogs: List[DogsRow]   // return items from dogs table that has this.id as ownerId
}

case class DogsRow(name: String, ownerId: People) {
  lazy val owner: People  // lazy on-demand or, can be a def too
}

是否有覆盖光滑的代码生成来做到这一点?

【问题讨论】:

  • @EndeNeu:虽然相关的问题并不相关。他正在从 Scala 模式转向生成的 SQL。我想要另一种方式。我想修改 SQL->Scala 代码生成器来为我执行此操作...
  • 我链接了这个问题,因为您不能将案例类定义为外键,您需要明确指定它们并且它们必须是某种原始类型(Int、Long 等)。您不能将结构化类型作为键,除非您的用例与 sql 父子关系不同,在这种情况下是的,该问题不相关。
  • @EndeNeu:我想知道是否可以覆盖 codegen 本身,以便将帮助程序 def dogs(参见最后一个示例)添加到生成的案例类中

标签: scala orm code-generation slick slick-2.0


【解决方案1】:

不要这样做。 Slick 的核心优势之一来自于编写查询。虽然你的意图是可能的,但你正在打破这种力量。而是编写查询!

implicit class PersonExtension(q: Query[Person,PersonRow]){
  def dogs = q.join(Dog).on(_.id === _.ownerId).map(_._2)
}
implicit class DogExtension(q: Query[Person,PersonRow]){
  def owner = q.join(Person).on(_.ownerId === _.id).map(_._2)
}

val personQuery = Person.filter(_.id === someId)
val person = personQuery.first
val dogsQuery = personQuery.dogs
val dogs = dogsQuery.run
val ownerQuery = dogsQuery.owner
val owner = ownerQuery.first

因此,请使用旧查询作为新狗查询的基础。优点是您不会以这种方式对一个查询进行硬编码,但您可以进一步编写。只想要棕色的狗吗?没问题:

val brownDogsQuery = personQuery.dogs.filter(_.color === "brown")

您当然可以使用代码生成器自动生成这些隐式类。

相关视频:

  • Scala 交换 2013
  • Scala 用户组柏林演讲,2013 年 12 月
  • 2014 年 Scala 日演讲

http://slick.typesafe.com/docs/

【讨论】:

  • 在表上使用隐式类不是更好吗?例如implicit class PersonExtension(p: Person){ def dogs = Dogs.filter(_.ownerId === p.id) } 这样你就可以在单子连接中使用它们。
  • 不!将它们放在查询中允许在应用过滤器等后仍然使用它们。
  • 为什么不在单子连接中应用过滤器(等)?示例(来自我的业务领域):val query = for{user <- Users if user.lastName === "Miller"relation <- user.loginRelationsrole <- relation.role if role.isCentralMonitorstudy <- relation.study} yield (user.firstName, user.lastName, role.name, study.name)
  • 当然,你可以做到。导致 slick 生成 WHERE 而不是 ON。
  • 啊,在文档中找到了 :) monadic → 隐式但适用性 → 显式(可能会更改)。我猜数据库引擎通常足够聪明,可以以相同的性能运行它们。没有?
猜你喜欢
  • 2021-03-11
  • 2013-01-25
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 1970-01-01
  • 2013-02-23
  • 2018-02-21
相关资源
最近更新 更多