2014-05-09 12 views
7

Làm cách nào bạn cập nhật một vài cột trong bảng bảng trong khi trả lại toàn bộ bảng được cập nhật khi sử dụng dấu nháy?Slick 2 - Cập nhật các cột trong một bảng và trả lại toàn bộ đối tượng bảng

Giả sử SomeTables là một số TableQuery, bạn thường sẽ viết một truy vấn như thế này nếu bạn muốn, ví dụ, thêm một mục vào bảng (và trở về mục mới được bổ sung)

val returnedItem = SomeTables returning SomeTables += someTable 

Làm thế nào bạn làm như vậy nếu bạn muốn cập nhật một mục và trả lại toàn bộ lại toàn bộ mục, tôi nghi ngờ bạn sẽ làm một cái gì đó như thế này

val q = SomeTables.filter(_.id === id).map(x => (x.someColumn,x.anotherColumn)) returning SomeTables 
val returnedItem = q.update((3,"test")) 

các mã sau đây tuy nhiên không làm việc, và tôi không thể nhìn thấy bất kỳ tài liệu về cách làm thứ là

Lưu ý rằng tôi biết bạn chỉ có thể truy vấn các mục trước, cập nhật nó, và sau đó sử dụng bản sao trên đối tượng ban đầu, tuy nhiên điều này đòi hỏi rất nhiều soạn sẵn (và DB chuyến đi cũng)

+0

Tôi không hiểu liệu bạn muốn cập nhật một đối tượng và gửi lại hoặc bạn muốn cập nhật một đối tượng và sau đó có 'TableQuery' với bản cập nhật bạn chỉ cần làm, nếu thứ hai có lẽ bạn chỉ phải nối '.run' vào truy vấn bạn đang thực hiện. –

+0

Giả sử rằng tôi có một phép chiếu đầy đủ từ một 'trường hợp lớp' đến các cột của bảng, tôi muốn cập nhật một tập con của các cột đó (tức là' .map (x => (x.someColumn, x.anotherColumn)) Vì vậy, trong ví dụ trên, SomeTables có thể có một phép chiếu '*' mặc định sẽ có 5 colums, tôi đang cập nhật hai cột ('someColumn' và' anotherColumn' khác.), tuy nhiên tôi muốn trả lại toàn bộ 'bảng' (hoặc đối tượng) có chứa 5 cột – mdedetrich

+0

Từ trải nghiệm mới bắt đầu của tôi, tôi không thấy cách nào ngoại trừ cập nhật và sau đó chọn hàng, phương thức' cập nhật' bạn ' gọi lại trả về một 'Int' (đó là liệu việc cập nhật thành công hay không) Xin lỗi tôi không thể giúp, hy vọng ai đó có nhiều kinh nghiệm hơn sẽ trả lời –

Trả lời

4

Tính năng này không được hỗ trợ trong Slick (v2 hoặc v3-M1); mặc dù tôi không thấy bất kỳ lý do cụ thể nào cấm triển khai, UPDATE ... RETURNING không phải là tính năng SQL chuẩn (ví dụ: H2 không hỗ trợ tính năng này: http://www.h2database.com/html/grammar.html#update). Tôi sẽ để lại như là một bài tập cho người đọc để khám phá làm thế nào một cách an toàn và hiệu quả mô phỏng tính năng cho RDBMSes thiếu UDPATE ... RETURNING.

Khi bạn gọi "trả lại" trên số scala.slick.lifted.Query, số này cung cấp cho bạn JdbcInsertInvokerComponent$ReturningInsertInvokerDef. Bạn sẽ không tìm thấy phương thức update, mặc dù có phương thức insertOrUpdate; tuy nhiên, insertOrUpdate chỉ trả lại kết quả biểu hiện returning nếu chèn xảy ra, None được trả về để cập nhật, do đó, không có trợ giúp ở đây.

Từ điều này, chúng tôi có thể kết luận rằng nếu bạn muốn sử dụng tính năng SQL UPDATE ... RETURNING, bạn sẽ cần phải sử dụng StaticQuery hoặc cuộn bản vá của riêng bạn vào Slick. Bạn có thể tự tay viết các truy vấn của bạn (và tái thực hiện dự bảng của bạn như getResult/setParameter serializers), hoặc bạn có thể thử đoạn mã này:

package com.spingo.slick 

import scala.slick.driver.JdbcDriver.simple.{queryToUpdateInvoker, Query} 
import scala.slick.driver.JdbcDriver.{updateCompiler, queryCompiler, quoteIdentifier} 
import scala.slick.jdbc.{ResultConverter, CompiledMapping, JdbcBackend, JdbcResultConverterDomain, GetResult, SetParameter, StaticQuery => Q} 
import scala.slick.util.SQLBuilder 
import slick.ast._ 

object UpdateReturning { 
    implicit class UpdateReturningInvoker[E, U, C[_]](updateQuery: Query[E, U, C]) { 
    def updateReturning[A, F](returningQuery: Query[A, F, C], v: U)(implicit session: JdbcBackend#Session): List[F] = { 
     val ResultSetMapping(_, 
     CompiledStatement(_, sres: SQLBuilder.Result, _), 
     CompiledMapping(_updateConverter, _)) = updateCompiler.run(updateQuery.toNode).tree 

     val returningNode = returningQuery.toNode 
     val fieldNames = returningNode match { 
     case Bind(_, _, Pure(Select(_, col), _)) => 
      List(col.name) 
     case Bind(_, _, Pure(ProductNode(children), _)) => 
      children map { case Select(_, col) => col.name } toList 
     case Bind(_, TableExpansion(_, _, TypeMapping(ProductNode(children), _, _)), Pure(Ref(_), _)) => 
      children map { case Select(_, col) => col.name } toList 
     } 

     implicit val pconv: SetParameter[U] = { 
     val ResultSetMapping(_, compiled, CompiledMapping(_converter, _)) = updateCompiler.run(updateQuery.toNode).tree 
     val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain, U]] 
     SetParameter[U] { (value, params) => 
      converter.set(value, params.ps) 
     } 
     } 

     implicit val rconv: GetResult[F] = { 
     val ResultSetMapping(_, compiled, CompiledMapping(_converter, _)) = queryCompiler.run(returningNode).tree 
     val converter = _converter.asInstanceOf[ResultConverter[JdbcResultConverterDomain, F]] 
     GetResult[F] { p => converter.read(p.rs) } 
     } 

     val fieldsExp = fieldNames map (quoteIdentifier) mkString ", " 
     val sql = sres.sql + s" RETURNING ${fieldsExp}" 
     val unboundQuery = Q.query[U, F](sql) 
     unboundQuery(v).list 
    } 
    } 
} 

Tôi chắc chắn ở trên có thể được cải thiện; Tôi đã viết nó dựa trên sự hiểu biết hơi hạn chế của tôi về nội dung Slick, và nó làm việc cho tôi và có thể tận dụng các dự báo/loại ánh xạ mà bạn đã xác định.

Cách sử dụng:

import com.spingo.slick.UpdateReturning._ 
val tq = TableQuery[MyTable] 
val st = tq filter(_.id === 1048003) map { e => (e.id, e.costDescription) } 
st.updateReturning(tq map (identity), (1048003, Some("such cost"))) 
+2

Cảm ơn! Nó sẽ là tuyệt vời nếu có một phiên bản cập nhật cho Slick 3.0 :-) –

+0

Có bất kỳ sự khác biệt liên quan đến điều này trong Slick 3? – Ixx

+0

Chúng tôi chưa cập nhật Slick 3 tại đây; Tôi chắc chắn cách tiếp cận chung sẽ hoạt động nhưng có khả năng là các API và cấu trúc dữ liệu có thay đổi đôi chút. –

Các vấn đề liên quan