2017-05-27 42 views
0

我有一個簡單的scala和播放代碼以將產品插入到數據庫中。Scala,play - 無法插入到Postgresql數據庫中

在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) 
} 

我更新模型和期權自動遞增場道,但它並沒有幫助。

+0

您是否閱讀過Evolution如何與Play一起使用? https://www.playframework.com/documentation/2.5.x/Evolutions – sheunis

+0

是的,但我的代碼創建了一些教程,沒有使用演變。你能解釋我應該添加什麼,而不是單獨的「進化」到build.sbt中來觸發查詢? – allocer

+0

在你的問題中你陳述了「偶數表不是在數據庫中創建的」。如果沒有Evolution,表格將不會爲您創建。您需要使用SQL語句在postgres數據庫中手動創建表。確保它對應於您的ProductTableDef。 – sheunis

回答

2

默認情況下在控制器中執行異步操作。因此在調用數據庫完成之前渲染完成。對數據庫的調用是一個緩慢的操作,這被認爲是副作用:網絡+ 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

不知道有你把這個邏輯在你的web應用

嘗試看看通過油滑生成的SQL:

更新你的方法相應 高清加(產品:產品):未來[INT] = { VAL行動=產品+ =產品

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) 

}

+0

謝謝,但你是否手動創建一個表或什麼?當你添加Thread.sleep()時它適用於你? – allocer

+0

爲什麼期待創建表?這裏的邏輯?如果你有一些或手動的,這應該由其他邏輯來完成。我會建議飛行路線遷移:https://flywaydb.org/對我很好,隨着項目的發展很容易使用。 – Pavel

+0

我不指望。我認爲它應該在我觸發插入功能後自動創建。 – allocer

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 
    } 

現在架構已創建並且數據被添加到數據庫中。

+1

只是一般建議小心Await.result,但只要它的工作,它的好!更多關於Await.results的文章:http://docs.scala-lang.org/overviews/core/futures.html – Pavel