我加入了那些试图将Squeryl用作我的网络应用程序ORM框架的人们。 (为了记录,我使用Scalatra作为实际的Web框架 - 但我不认为这是一个Scalatra问题。)这意味着我加入了试图建立一个有效的抽象层来干我们的人的行列。常见的操作。例如,看到这样的例子很常见:
// First Model
package com.myproj
import com.myproj.Schema
class Foo() extends KeyedEntity {
val id = 0
def getAll() = { from(Schema.Foo)(s => select(s)) }
}
// Different Model
package com.myproj
import com.myproj.Schema
class Bar() extends KeyedEntity {
val id = 0
def getAll() = { from(Schema.Boo)(s => select(s)) }
}
所以一方面,我正在挖掘Squeryl语法的简洁性。另一方面:这是非常重复的。我想要的更像是:
// Base
class BaseEntity extends KeyedEntity {
val id = 0
def getAll() = { from(table)(s => select(s)) }
}
// New model
class Foo extends BaseEntity
// New model
class Bar extends BaseEntity
所以我主要有这个工作。扩展KeyedEntity
非常简单。只有一个问题:你如何在BaseEntity
中定义一个表,以便扩展它的类可以访问它?说实话,这可能从根本上说是我对Scala类型系统缺乏足够深入理解的问题。无论如何我在这里摆姿势。
我尝试了几件事:
val table
中声明BaseEntity
。这让我陷入了一个非常荒谬的类型检查混乱。 val table: Table[T]
仅在我将T定义为类型时才有效,然后子类在尝试提供不同类型的表时会导致编译器错误。 table
参数。 TypeTags
攻击了this SO post。但是,海报并没有为我提供足够的信息来理解他的实施情况。前面提到的SO帖子有一个评论,其中建议使用org.squeryl.Schema.findTablesFor方法。再次提出潜在的新手问题:我没有在如何实现这一点作为答案方面取得进展。我尝试过这样的事情:
class BaseEntity {
val table = findTablesFor(this)
}
然而,我回到了一个Iterable,我有点不确定该如何处理它。
因此。有没有“正确”的方法来做到这一点?当然有一种干净的方法可以将CRUD操作转移到基类中 - 我似乎无法弄明白。
修改的
所以,这就是我所拥有的,使用Squeryl 9.5-6:
// Schema
package com.myproj.schema
object MySchema extends Schema {
val foo = table[Foo]("foos")
val bar = table[Bar]("bars")
}
// BaseEntity
package com.myproj.models
import com.myproj.schema.MySchema
abstract class BaseEntity extends Keyedentity[Long] {
val id: Long = 0
val table = MySchema.findTablesFor(this).head
}
// Class
package com.myproj.models
case class Foo (
val name: String,
val extra: Option[String]
) extends BaseEntity {
def this() = this("", None)
}
像这样设置。 findTablesFor
总是返回一个空的迭代器。它编译,但在运行时抛出错误,试图在空迭代器上调用head(正如你所说的那样)。处理错误不是问题;无法找到一张桌子。
思想?
答案 0 :(得分:3)
val表:表[T]仅在我将T定义为类型时才有效,然后子类在尝试提供不同类型的表时会导致编译器错误。
您可以使用自我类型执行此操作。我不确定我会推荐它,但它应该有效:
class BaseEntity[T] {
self: T =>
val table: Table[T]
}
然后您的实现将如下所示:
class MyEntity extends BaseEntity[MyEntity]
使用findTablesFor可能是更好的解决方案。没有什么可以阻止您将类映射到Squeryl模式中的多个表。你可以:
val tableA = table[MyEntity]
val tableB = table[MyEntity]
因此,为所有匹配表返回Iterable的原因。如果你知道你不打算这样做,你可以使用第一个结果:
val table = MySchema.findTableFor(this).head
请注意,如果找不到相关的表,这将抛出异常。