我有一个分类有两个关系的实体:公司和位置。为了坚持分类,我需要知道它的关系的id,它可能需要先保持一个实体(也就是它可能已经存在于数据库中,否则应该插入它)。
id是由应用程序分配的UUID(即它不是由db自动增加的),因此应用程序会分配一个id,该id将最终成为实体id,或者如果实体已存在则由事务中的实际id替换
执行此操作的代码如下:
def create(classified: Classified, company: Company, location: Location): Future[String] = {
val interaction = for {
comp <- companies.filter(_.name === company.name).result.headOption flatMap {
case None => companies returning companies.map(_.id) += company
case Some(comp) => DBIO.successful(comp.id.get)
}
loc <- locations.filter(_.name === location.name).result.headOption flatMap {
case None => locations returning locations.map(_.id) += location
case Some(loc) => DBIO.successful(loc.id.get)
}
cl <- classifieds returning classifieds.map(_.id) += classified.copy(companyId = comp, locationId = loc)
} yield cl
db.run(interaction.transactionally)
}
以上对Postgres(生产数据库)运行时效果很好,但对于H2(测试和开发数据库)失败并出现错误:[SlickException:此DBMS只允许从单个AutoInc列返回一个INSERT]
看起来H2驱动程序不会返回id,除非它们属于自动增量变量。
那么,如何编写此事务以便a)在单个事务中插入b)以最小的db往返和c)以数据库中立的方式进行?
编辑:
上述方法是从像这样的控制器中使用的:
classifiedDao.create(
Classified(Some(UUID.randomUUID().toString), c.title, Jsoup.clean(c.body, Whitelist.basic()), c.refNo, "", ""),
Company(Some(UUID.randomUUID().toString), c.companyName, c.companyEmail, None, None),
Location(Some(UUID.randomUUID().toString), c.location, None)
).map(_ =>
Redirect(routes.Classifieds.form()).flashing("success" -> "Classified submitted")
)
答案 0 :(得分:1)
事实证明,从db中检索id是很容易的部分,因为执行此操作的代码已经具有所需类型(DBIOAction),困难的部分是在插入后获取id但在这种情况下我已经知道id,因为它是我设置它的代码。没有必要使用return()并依赖于RDBMS。
解决方案:
def create(classified: Classified, company: Company, location: Location): Future[String] = {
val interaction = for {
comp <- companies.filter(_.name === company.name).result.headOption flatMap {
case None => {
companies += company
DBIO.successful(company.id.get)
}
case Some(comp) => DBIO.successful(comp.id.get)
}
loc <- locations.filter(_.name === location.name).result.headOption flatMap {
case None => {
locations += location
DBIO.successful(location.id.get)
}
case Some(loc) => DBIO.successful(loc.id.get)
}
cl <- {
classifieds += classified.copy(companyId = comp, locationId = loc)
DBIO.successful(classified.id.get)
}
} yield cl
db.run(interaction.transactionally)
}
答案 1 :(得分:0)
For Slick returning
工作Id
必须auto generated primary key
Id
不仅应该是主键,还应该是自动增量ID。
注意强>
许多数据库系统只允许返回单个列,该列必须是表的自动递增主键。如果要求其他列,则在运行时抛出SlickException(除非数据库实际支持它)。
所以编写一个函数,在插入数据库之后返回Id
。
def getIdAfterInsert(entity: Entity): DBIO[EntityId] = {
(entities += entity).flatMap { _ =>
entities.filter(_.name === entity.name).result.flatMap {
case Some(entity) => DBIO.successful(entity.id)
case None => DBIO.fail(new Exception("something terrible happened"))
}
}.transactionally
}