Scala Slick 3.1.1:在单个交易中插入实体及其关系
我有一个被分类的实体,它有两个关系:一个公司和一个地点。为了持久化分类,我需要知道其关系的ID,这可能需要首先持久化实体(也就是说,它可能已经存在于数据库中,否则应该插入) id是由应用程序分配的UUID(即,它不是由db自动递增的),因此应用程序分配的id最终将成为实体id,或者如果实体已经存在,则将被事务中的实际id替换 执行此操作的代码如下所示:Scala Slick 3.1.1:在单个交易中插入实体及其关系,scala,h2,slick,Scala,H2,Slick,我有一个被分类的实体,它有两个关系:一个公司和一个地点。为了持久化分类,我需要知道其关系的ID,这可能需要首先持久化实体(也就是说,它可能已经存在于数据库中,否则应该插入) id是由应用程序分配的UUID(即,它不是由db自动递增的),因此应用程序分配的id最终将成为实体id,或者如果实体已经存在,则将被事务中的实际id替换 执行此操作的代码如下所示: def create(classified: Classified, company: Company, location: Location)
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)
对于Slick返回
工作Id
必须是自动生成的主键
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
}
事实证明,从db中检索id是最简单的部分,因为执行此操作的代码已经具有所需的类型(DBIOAction),而最难的部分是在插入之后获取id,但在这种情况下,我已经知道id,因为设置id的是我的代码。不需要使用returning()和依赖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)
}
def create(分类:分类,公司:公司,地点:地点):Future[String]={
val交互=用于{
公司{
公司+=公司
DBIO.successful(company.id.get)
}
案例部分(comp)=>DBIO.successful(comp.id.get)
}
loc{
位置+=位置
DBIO.successful(location.id.get)
}
案例部分(loc)=>DBIO.successful(loc.id.get)
}
cl只是澄清一下:company
和location
是否已经在插入时分配了UUID(行case None=>返回公司的公司.map(u.id)+=company
)?是的。控制器将id分配给所有三个实体,然后将对象传递给要持久化的DAO,如果实体已存储,则丢弃id,并使用从数据库检索到的id,而不使用始终使用的分类is。@Roman该注释纯粹是genius。在None的情况下,我已经知道了id,我所需要做的就是将结果与其他DBAction排序,我就完成了。谢谢,太棒了。PS:我在下面为子孙后代发布答案。很高兴我能帮上忙。您可以考虑使用<代码> dBeActudio,然后< <代码>确保插入成功运行:<代码>(公司+=公司)。andThen(DBIO。成功(公司。ID.GET))< /代码>。
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)
}