Cox*_*xer 9 generics scala slick
我厌倦了总是做以下的事情,以便为我的每个域实体使用光滑进行数据库访问.
database withSession {
implicit session =>
val entities = TableQuery[EntityTable]
val id = //Some ID
val q = for {
e <- entities if e.id === id
} yield (e)
val entity = q.first
}
Run Code Online (Sandbox Code Playgroud)
(注:EntityTable物等规定描述这里)
所以我决定我想要一个通用的数据库访问对象来处理这个问题.用法看起来应该是这样的
[...]
val entityDAO = new GenericDAO[Entity, EntityTable, String]()
[...]
database withSession { implicit session =>
val id = // Some ID
val entity = entityDAO.get(id)
}
Run Code Online (Sandbox Code Playgroud)
我尝试实现GenericDAO看起来像这样
class GenericDAO[T, TB, PK](implicit session: Session) {
val entities = TableQuery[TB] // Line 1
def get(id: PK): T = {
val q = for {
e <- entities
} yield (e)
val res: T = q.first
res
}
}
Run Code Online (Sandbox Code Playgroud)
但是第1行给我留下了一个编译器错误,指出TB参数有问题.
此行的多个标记 - 类型参数[TB]符合值的任何重载替代值的界限:[E <:scala.slick.lifted.AbstractTable [ ]] => scala.slick.lifted.TableQuery [E ,E#TableElementType] [E <:scala.slick.lifted.AbstractTable [ ]](缺点:scala.slick.lifted.Tag => E)scala.slick.lifted.TableQuery [E,E#TableElementType] - 错误的数字重载方法值的类型参数适用于替代方法:[E <:scala.slick.lifted.AbstractTable [ ]] => scala.slick.lifted.TableQuery [E,E#TableElementType] [E <:
scala.slick.lifted .AbstractTable [ ]](缺点:scala.slick.lifted.Tag => E)scala.slick.lifted.TableQuery [E,E#TableElementType]
关于这个问题的任何建议?或许我错了,它应该以另一种方式实施.我愿意接受任何解决方案.谢谢!
首先,你可以写
val entities = TableQuery[EntityTable] // put in a central place for re-use
Run Code Online (Sandbox Code Playgroud)
然后
database.withSession(
(for {
e <- entities if e.id === /*Some ID*/
} yield e).first()(_)
)
Run Code Online (Sandbox Code Playgroud)
或这个
database.withSession(entities.filter(_.id === /*Some ID*/).first()(_))
Run Code Online (Sandbox Code Playgroud)
或这个
val get = entities.findBy(_.id) // <- reuse this
database.withSession(get(/*Some ID*/).first()(_))
Run Code Online (Sandbox Code Playgroud)
为了简洁起见.这可能会使你的整个DAO不必要(这很棒:)!).
关于你得到的错误信息.TableQuery[TB]是一个宏,它是一个简写TableQuery(tag => new TB(tag)),TB必须是Table和支持对象创建.您不能只TableQuery在从DAO包装器获得的无约束类型参数上使用宏.你可以约束TB <: Table[_]但它仍然不支持对象创建,你不能在Scala中约束它.你只能为你的DAO提供一个工厂(一个常见的模式是获取一个作为隐式参数),但是当你只需编写一次TableQuery并将其存储在一个全局可访问的地方时,这一切都没有意义.
更新:
该快捷方式适用于所有这些方法.这是普通的Scala.您只需将方法转换为函数并将其传递给带有Session的高阶函数,这需要从会话到任何事物的函数.请注意,有些Slick方法有一个空参数列表,需要()(_)将它们转换为函数,有些只有隐式参数列表,这只需要(_).例如database.withSession(entities.filter(_.id === /*Some ID*/).delete(_)).
如果你想知道_.Scala将方法与函数区分开来.def foo(a: A, b: B, ...): R是一种方法,但可以转换为(A,B,C) => R使用类型的函数foo _.这种转换称为eta扩展,谷歌搜索将会显示更多信息.有时当一个函数需要时,但是你提供了一个方法,Scala编译器会推断出它_,你不必显式地编写它.您还可以提供一些参数并_代替您不想应用的参数.在这种情况下,您将部分应用该方法并返回一个函数.这就是我们在这里所做的.我们_在方法通常期望会话的地方使用并获得一个会话的函数.如果正是你必须使用_或(_)或()(_)与方法签名做,细节隐含参数列表,无参的方法,用空参数列表的方法,这是一般的Scala知识价值在某些点研究之间的相互作用.
| 归档时间: |
|
| 查看次数: |
4302 次 |
| 最近记录: |