Scala Slick 3.1.1:在单个交易中插入实体及其关系

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)

我有一个被分类的实体,它有两个关系:一个公司和一个地点。为了持久化分类,我需要知道其关系的ID,这可能需要首先持久化实体(也就是说,它可能已经存在于数据库中,否则应该插入)

id是由应用程序分配的UUID(即,它不是由db自动递增的),因此应用程序分配的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)
对于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)
}