복붙노트

[SCALA] 하지가 슬릭 3.0.0에있는 경우 삽입

SCALA

하지가 슬릭 3.0.0에있는 경우 삽입

내가하지가 존재하는 경우 삽입하기 위해 노력하고있어, 나는, 2.0 1.0.1이 게시물을 발견했다.

나는 조각 3.0.0의 문서에서 트랜잭션 사용 발견

val a = (for {
  ns <- coffees.filter(_.name.startsWith("ESPRESSO")).map(_.name).result
  _ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionally

val f: Future[Unit] = db.run(a)

난 안가이 구조에 존재하는 경우 삽입에서 로직을 작성하기 위해 사투를 벌인거야. 나는 슬릭에 새로 온 사람과 스칼라와 약간의 경험이 있습니다. 이것은하지 트랜잭션 외부에 존재하는 경우 삽입 할 내 시도입니다 ...

val result: Future[Boolean] = db.run(products.filter(_.name==="foo").exists.result)
result.map { exists =>  
  if (!exists) {
    products += Product(
      None,
      productName,
      productPrice
    ) 
  }  
}

하지만 내가 어떻게 트랜잭션 블록이 배치해야합니까? 이것은 내가 갈 수있는 먼 :

val a = (for {
  exists <- products.filter(_.name==="foo").exists.result
  //???  
//    _ <- DBIO.seq(ns.map(n => coffees.filter(_.name === n).delete): _*)
} yield ()).transactionally

미리 감사드립니다

해결법

  1. ==============================

    1.하지 쿼리를 존재하는 경우 ... 하나의 인서트를 사용하는 것이 가능하다. 이것은 여러 데이터베이스 라운드 트립과 경쟁 조건을 방지 (트랜잭션 격리 수준에 따라 충분하지 않을 수 있습니다).

    하지 쿼리를 존재하는 경우 ... 하나의 인서트를 사용하는 것이 가능하다. 이것은 여러 데이터베이스 라운드 트립과 경쟁 조건을 방지 (트랜잭션 격리 수준에 따라 충분하지 않을 수 있습니다).

    def insertIfNotExists(name: String) = users.forceInsertQuery {
      val exists = (for (u <- users if u.name === name.bind) yield u).exists
      val insert = (name.bind, None) <> (User.apply _ tupled, User.unapply)
      for (u <- Query(insert) if !exists) yield u
    }
    
    Await.result(db.run(DBIO.seq(
      // create the schema
      users.schema.create,
    
      users += User("Bob"),
      users += User("Bob"),
      insertIfNotExists("Bob"),
      insertIfNotExists("Fred"),
      insertIfNotExists("Fred"),
    
      // print the users (select * from USERS)
      users.result.map(println)
    )), Duration.Inf)
    

    산출:

    Vector(User(Bob,Some(1)), User(Bob,Some(2)), User(Fred,Some(3)))
    

    생성 된 SQL :

    insert into "USERS" ("NAME","ID") select ?, null where not exists(select x2."NAME", x2."ID" from "USERS" x2 where x2."NAME" = ?)
    

    여기 GitHub의에서 전체 예제

  2. ==============================

    2.이것은 내가 생각 해낸 버전입니다 :

    이것은 내가 생각 해낸 버전입니다 :

    val a = (
        products.filter(_.name==="foo").exists.result.flatMap { exists => 
          if (!exists) {
            products += Product(
              None,
              productName,
              productPrice
            ) 
          } else {
            DBIO.successful(None) // no-op
          }
        }
    ).transactionally
    

    그것은의 조금 예를 들어이 삽입 또는 기존 개체를 반환하는 것이 유용 할 것입니다,하지만 부족하다.

    완성도를 들어, 테이블 정의에 여기 :

    case class DBProduct(id: Int, uuid: String, name: String, price: BigDecimal)
    class Products(tag: Tag) extends Table[DBProduct](tag, "product") {
      def id = column[Int]("id", O.PrimaryKey, O.AutoInc) // This is the primary key column
      def uuid = column[String]("uuid")
      def name = column[String]("name")
      def price = column[BigDecimal]("price", O.SqlType("decimal(10, 4)"))
    
      def * = (id, uuid, name, price) <> (DBProduct.tupled, DBProduct.unapply)
    }
    val products = TableQuery[Products]
    

    내가 매핑 테이블을 사용하고,이 솔루션은 작은 변화와 함께, 튜플도 작동합니다.

    그것은이 작업 삽입 무시 년대 설명서에 따라 선택적으로 ID를 정의 할 필요가 없습니다 것을 유의하십시오 :

    그리고 여기 방법 :

    def insertIfNotExists(productInput: ProductInput): Future[DBProduct] = {
    
      val productAction = (
        products.filter(_.uuid===productInput.uuid).result.headOption.flatMap { 
        case Some(product) =>
          mylog("product was there: " + product)
          DBIO.successful(product)
    
        case None =>
          mylog("inserting product")
    
          val productId =
            (products returning products.map(_.id)) += DBProduct(
                0,
                productInput.uuid,
                productInput.name,
                productInput.price
                )
    
              val product = productId.map { id => DBProduct(
                id,
                productInput.uuid,
                productInput.name,
                productInput.price
              )
            }
          product
        }
      ).transactionally
    
      db.run(productAction)
    }
    

    (이 솔루션에 저를 향하게를위한 Google 그룹 스레드에서 감사 마태 복음 Pocock).

  3. ==============================

    3.나는 외모보다 완벽한 솔루션으로 실행했습니다. 에센셜 슬릭 북의 삽입을 통해 제 3.1.7 더 많은 제어 예제를 가지고있다.

    나는 외모보다 완벽한 솔루션으로 실행했습니다. 에센셜 슬릭 북의 삽입을 통해 제 3.1.7 더 많은 제어 예제를 가지고있다.

    끝에서 당신은 떨어지게를 같이 얻을 :

      val entity = UserEntity(UUID.random, "jay", "jay@localhost")
    
      val exists =
        users
          .filter(
            u =>
              u.name === entity.name.bind
                && u.email === entity.email.bind
          )
          .exists
      val selectExpression = Query(
        (
          entity.id.bind,
          entity.name.bind,
          entity.email.bind
        )
      ).filterNot(_ => exists)
    
      val action = usersDecisions
        .map(u => (u.id, u.name, u.email))
        .forceInsertQuery(selectExpression)
    
      exec(action)
      // res17: Int = 1
    
      exec(action)
      // res18: Int = 0
    
  4. ==============================

    4.매끄러운 3.0 수동 삽입 조회 부 (http://slick.typesafe.com/doc/3.0.0/queries.html)에있어서, 삽입 된 값은 이하와 같은 ID로 반환 될 수있다 :

    매끄러운 3.0 수동 삽입 조회 부 (http://slick.typesafe.com/doc/3.0.0/queries.html)에있어서, 삽입 된 값은 이하와 같은 ID로 반환 될 수있다 :

    def insertIfNotExists(productInput: ProductInput): Future[DBProduct] = {
    
      val productAction = (
        products.filter(_.uuid===productInput.uuid).result.headOption.flatMap { 
        case Some(product) =>
          mylog("product was there: " + product)
          DBIO.successful(product)
    
        case None =>
          mylog("inserting product")
    
          (products returning products.map(_.id) 
                    into ((prod,id) => prod.copy(id=id))) += DBProduct(
                0,
                productInput.uuid,
                productInput.name,
                productInput.price
                )
        }
      ).transactionally
    
      db.run(productAction)
    }
    
  5. from https://stackoverflow.com/questions/30706193/insert-if-not-exists-in-slick-3-0-0 by cc-by-sa and MIT license