scala - 使用 Slick 插入具有自动递增 ID 的值的通用存储库/DAO 方法缺少隐式
问题描述
我对 scala 相当陌生,并试图学习slick并从 play-slick-example 开始,一切都是可以理解的。
我开始创建自己的实体、表和查询。第一个技巧是解决在插入时获取自动递增的 id,但示例代码涵盖了它,尽管可以改进成语。接下来要解决的问题是将所有通用代码移动到一个地方。通用代码是指基本的 CRUD 操作,基本上是所有实体的复制粘贴。所以我去创建了基地Entity
trait Entity[T <: Entity[T, ID], ID] {
val id: Option[ID]
def withId(id: ID): T
}
有了这个我去创建BaseRepo
应该包含所有常见代码:
abstract class BaseRepo[T <: Entity[T, ID], ID] {
protected val dbConfigProvider: DatabaseConfigProvider
val dbConfig = dbConfigProvider.get[JdbcProfile]
import dbConfig._
import profile.api._
type TableType <: Keyed[ID] with RelationalProfile#Table[T]
protected val tableQuery: TableQuery[TableType]
}
WheredbConfigProvider
被注入实现并允许导入正确的配置(不确定它是否需要,但示例就是这样)。是另一个用列Keyed
表示 s 的特征:Table
id
trait Keyed[ID] {
def id: Rep[ID]
}
现在一切看起来都很好。要扩展BaseRepo
一个需要正确分配TableType
,tableQuery
并且一切都应该工作。我从以下实现开始:
case class Vehicle(override val id: Option[Long], name: String, plate: String, modelId: Long)
extends Entity[Vehicle, Long] {
override def withId(id: Long): Vehicle = this.copy(id = Some(id))
}
以及以下回购:
@Singleton
class VehicleRepository @Inject()(override val dbConfigProvider: DatabaseConfigProvider)
(implicit ec: ExecutionContext)
extends BaseRepo [Vehicle, Long]{
import dbConfig._
import profile.api._
type TableType = Vehicles
val tableQuery = TableQuery[Vehicles]
class Vehicles(tag:Tag) extends Table[Vehicle](tag:Tag, "vehicles") with Keyed[Long] {
def id = column[Long]("id", O.PrimaryKey, O.AutoInc)
def name = column[String]("name")
def plate = column[String]("plate")
def modelId = column[Long]("modelId")
def * = (id.?, name,plate,modelId) <> ((Vehicle.apply _).tupled, Vehicle.unapply)
}
一切看起来仍然很棒!现在我添加all()
到 BaseRepo:
def all() = db.run {
tableQuery.result
}
它有效!我可以通过简单Vehicle
的注入列出我的所有实体(嗯,我要准确,但谁在乎)repo:VehicleRepository
repo.all()
Future
接下来,我尝试使用自动递增的 id 概括插入并将其放入BaseRepo
:
def create(item: T, ec:ExecutionContext) = db.run{
((tableQuery returning tableQuery.map(_.id)) += item)
.map(id => item.withId(id))(ec)
}
不要介意ExecutionContext
在这里明确,但无论如何,这不起作用,我得到的错误令人沮丧:
Slick does not know how to map the given types.
Possible causes: T in Table[T] does not match your * projection,
you use an unsupported type in a Query (e.g. scala List),
or you forgot to import a driver api into scope.
Required level: slick.lifted.FlatShapeLevel
Source type: slick.lifted.Rep[ID]
Unpacked type: T
Packed type: G
]
如果我将此方法移回VehicleRepository
(替换T
为Vehicle
),一切都会像魅力一样。
经过几个小时的挖掘,我明白这tableQuery.map
需要一些(implicit shape: Shape[_ <: FlatShapeLevel, F, T, G])
作为隐式参数,我真的不知道它来自哪里,VehicleRepository
为什么它在我的范围内不可用BaseRepo
任何关于如何解决这个问题的评论或建议,或者使用 Slick 推广 CRUD 的其他一些方法,都将受到欢迎!
我正在使用 Play-2.8 Slick-3.3.2 play-slick-5.0.0 scala-2.13.1
解决方案
推荐阅读
- amazon-web-services - 如何从网络掩码 /30 到网络掩码 /28 到达特定的 IP 地址
- r - 为什么 geom_bar y 轴与实际数字不成比例?
- android - android putExtra 显示为空
- spring - 圆形视图路径 [login]:将再次分派回当前处理程序 URL [/login]
- ios - 如何在 swift 4 中检测 UIview 失去焦点或获得焦点?
- yaml - 在同一 yaml 文件中访问 yaml 映射中的项目
- excel - 使用 vba 检查列在 excel 中是否可见
- ios - 如何在 Xcode for iOS 中启用 ASLR
- javascript - 为什么 http 响应没有显示在 chrome 调试的网络选项卡中?
- angular - Ionic 创建 PWA:CLI 中的模式验证失败