【问题标题】:Scala, play - cannot insert into Postgresql databaseScala,播放 - 无法插入 Postgresql 数据库
【发布时间】:2017-05-27 11:47:57
【问题描述】:

我有一个简单的 scala 和 play 代码,用于将产品插入数据库。

我在 application.conf 中的数据库配置如下:

db.default.hikaricp.connectionTestQuery = "SELECT 1"

db.default.driver=org.postgresql.Driver
db.default.url="jdbc:postgresql://localhost:5432/shop"
db.default.user="postgres"
db.default.password="root"

表定义和crud操作:

case class Product(id: Long, name: String, description: String, price: BigDecimal, amount: Int)

case class ProductFormData(name: String, description: String, price: BigDecimal, amount: Int)

object ProductForm {

  val form = Form(
    mapping(
      "name" -> nonEmptyText,
      "description" -> nonEmptyText,
      "price" -> bigDecimal,
      "amount" -> number
    )(ProductFormData.apply)(ProductFormData.unapply)
  )
}

class ProductTableDef(tag: Tag) extends Table[Product](tag, "product") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)

  def name = column[String]("name")

  def description = column[String]("description")

  def price = column[BigDecimal]("price")

  def amount = column[Int]("amount")

  override def * =
    (id, name, description, price, amount) <> (Product.tupled, Product.unapply)
}

object Products {

  val products = TableQuery[ProductTableDef]

  private def db: Database = Database.forDataSource(DB.getDataSource())

  def add(product: Product): Future[Int] = {
    try db.run(products += product)
    finally db.close
  }

  def delete(id: Long): Future[Int] = {
    db.run(products.filter(_.id === id).delete)
  }

  def get(id: Long): Future[Option[Product]] = {
    db.run(products.filter(_.id === id).result.headOption)
  }

  def listAll: Future[Seq[Product]] = {
    db.run(products.result)
  }
}

服务:

object ProductService {
  def addProduct(product: Product): Future[Int] = {
    Products.add(product)
  }
}

和控制器:

def create() = Action(parse.json) { request =>
    val name = (request.body \ "name").as[String]
    val description = (request.body \ "description").as[String]
    val price = (request.body \ "price").as[BigDecimal]
    val amount = (request.body \ "amount").as[Int]

    val product = Product(0, name, description, price, amount)
    ProductService.addProduct(product)

    Ok("name : " + product.name)
  }

一切看起来都很好,过程中没有错误(我使用邮递员,创建 json 并将其发送到服务器)。但毕竟数据库中没有数据。甚至没有在数据库中创建表。我真的不知道为什么这不能添加到数据库中。

编辑:

create table "Product" ("id" BIGSERIAL NOT NULL PRIMARY KEY,"name" VARCHAR(254) NOT NULL,"description" VARCHAR(254) NOT NULL,"price" Decimal, "amount" BIGINT NOT NULL);

这是我用来手动创建表的脚本,然后我尝试将数据frm请求保存到数据库中。从请求中读取一切正常(创建了对象产品),但没有数据仍然可以安全地存储到数据库中。

编辑 2:

case class Product(id: Option[Long], name: String, description: String, price: BigDecimal, amount: Int)

class ProductTableDef(tag: Tag) extends Table[Product](tag, "product") {

  def id = column[Long]("id", O.PrimaryKey, O.AutoInc)

  def name = column[String]("name")

  def description = column[String]("description")

  def price = column[BigDecimal]("price")

  def amount = column[Int]("amount")

  override def * =
    (id.?, name, description, price, amount) <> (Product.tupled, Product.unapply)
}

我使用 Option auto increment 字段更新了模型和 dao,但没有帮助。

【问题讨论】:

  • 您是否了解了 Evolutions 如何与 Play 协同工作? playframework.com/documentation/2.5.x/Evolutions
  • 是的,但是我的代码是使用一些未使用进化的教程创建的。你能解释一下我应该在 build.sbt 中添加什么而不是单独“进化”来触发查询吗?
  • 在您的问题中,您说“甚至没有在数据库中创建表。”。如果没有 Evolutions,将不会为您创建该表。您需要使用 SQL 语句在 postgres 数据库中手动创建表。确保它对应于您的 ProductTableDef。
  • 我在数据库中手动创建了“产品”表,但仍然没有添加数据。
  • 如果您需要有关 play+slick 的教程,请查看我几个月前编写的(针对 play2.4.x)的教程:pedrorijo.com/blog/play-slick 代码可在 Github 上找到:@ 987654323@ 甚至还有一个 play2.5.x 分支:github.com/pedrorijo91/play-slick3-steps/tree/play2.5 希望对您有所帮助

标签: database postgresql scala playframework slick


【解决方案1】:

默认情况下在控制器中异步播放动作。所以渲染在调用数据库完成之前完成。调用数据库是一个缓慢的操作,这被认为是副作用:网络 + IO 操作。 检查这一点的简单方法是在渲染之前放置下一个代码:

 Thread.sleep(2000)

你实际上应该做的是:

def add = Action.async( parse.json(userReads) ) { request =>
    val results = userRepo.insert(  UserData( None, request.body.name, request.body.note ) )
    results.map(_ => Ok("done") )

要创建所需的表,您应该使用以下内容:

val setup = DBIO.seq(
  // Create the tables, including primary and foreign keys
  (suppliers.schema ++ coffees.schema).create,


  //
)

val setupFuture = db.run(setup)

这里是漂亮的 api 文档:http://slick.lightbend.com/doc/3.0.0/gettingstarted.html#schema

不确定你是否会在你的 webApp 中放置这个逻辑

尝试查看 Slick 生成的 SQL:

相应地更新您的方法 def add(product: Product): Future[Int] = { val action = products += product

   val sql = action.result.statements.toString()

   // this is SQL query which slick will try run against postGreed 
   // you should be able to run it manually from SQL console to see reason why this failing 
   println(sql)

db.run( action )

}

【讨论】:

  • 谢谢,但是您是手动创建表还是什么?当你添加 Thread.sleep() 时它对你有用吗?
  • 为什么要创建表?这个逻辑在哪里??如果您有一些或手动的,这应该由其他逻辑来完成。我建议 flyway 迁移:flywaydb.org 对我有用,并且随着项目的发展易于使用。
  • 我没想到。我认为它应该在我触发插入功能后自动创建。
  • 好吧,有一个选项可以查看 Slick 生成的 SQL:可以通过这种方式打印到终端: val sql = query.result.statements.toString() println(sql) 我会更新我的答案给你的例子
  • 请更新您的问题或发布新答案以关闭此线程。谢谢
【解决方案2】:

终于成功了。我将添加功能更改为:

 def add(product: Product): Unit = {
    try {
      Await.result(db.run(DBIO.seq(
        products.schema.create,
        products += (product),
        products.result.map(println))), Duration.Inf)
    } finally db.close
  }

现在架构已创建并将数据添加到数据库中。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-16
  • 2014-12-29
  • 2018-10-14
相关资源
最近更新 更多