2014-05-09 17 views
7

Tabloyu kullanarak, tabloyu kullanarak, güncellenmiş tabloyu tümüyle döndürürken birkaç sütunu nasıl güncelleştirirsiniz? SomeTables varsayarsakKaygan 2 - Bir tablodaki sütunları güncelleştirin ve tüm tablo nesnesini döndürün

genellikle, örneğin, tabloya bir öğe eklemek isterseniz böyle bir sorgu yazmak (ve yeni eklenen ürünü iade)

val returnedItem = SomeTables returning SomeTables += someTable 

Nasılsınız olur olur, bazı TableQuery olduğunu bir öğe güncellemek ve bütün madde bütünü geri dönmek istiyorsanız aynı şeyi, ben aşağıdaki kod ancak çalışmaz bu

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

böyle bir şey yapsın şüpheli ve herhangi belgelerine göremiyorum inci nasıl yapılır Az önce, önceden öğeyi sorgulamak güncellemek ve sonra orijinal nesne üzerinde kopya kullanabilirsiniz farkındayım

Bununla birlikte bu Demirbaş bir sürü gerektirir (ve DB yanı gezileri)

+0

Ben Bir nesneyi güncellemek ve bunu iade etmek isteyip anlamadığınız veya eğer, sadece yaptığımız güncelleme ile 'TableQuery' sahip sonra bir nesneyi güncellemek ve istediğiniz ikincisi muhtemelen yürütmekte olduğunuz sorguya '.run' eklemek zorundasınız. –

+0

Bir "case class" öğesinden tablonun sütunlarına tam bir projeksiyon yaptığımı varsayarak, bu sütunların bir alt kümesini güncellemek istiyorum (örn. .map (x => (x.someColumn, x.anotherColumn)) , SomeTables varsayılan anotherColumn' '*' 5 colums olurdu projeksiyon, ben bu sütunların ikisini güncelleştiriyorum ('someColumn' ve' olabilir yukarıdaki örnek Yani 've. (' SomeTables' dönen) bütün güncellenen nesneyi döndürmek), ancak 5 sütun ben güncelleme haricinde bir çıkış yolu görmüyorum benim acemi deneyim – mdedetrich

+0

içeren ve daha sonra 'update' yöntemi' satır, seçersiniz bütün' table' (veya nesneyi) dönmek istiyorum döner çağırarak yeniden bir 'Int' (bu güncellemenin başarılı olup olmadığıdır). umarım daha tecrübeli birisi cevap verecektir. –

cevap

4

Bu özellik Slick'te desteklenmiyor (v2 veya v3-M1); Ben herhangi bir özel nedeni UPDATE ... RETURNING standart bir SQL özelliği değildir, gerçekleştirimdir yasaklayan görmüyorum rağmen (örneğin, H2 bunu desteklemez: http://www.h2database.com/html/grammar.html#update). Okuyucunun, birisinin UDPATE ... RETURNING eksik olan RDBMS'ler için nasıl güvenli ve verimli bir şekilde öykünebileceğini araştırması için bir egzersiz olarak ayrılacağım.

scala.slick.lifted.Query'da "dönen" i çağırdığınızda, size bir JdbcInsertInvokerComponent$ReturningInsertInvokerDef verir. insertOrUpdate yöntemi olmasına rağmen update yöntemini bulamazsınız; Ancak, insertOrUpdate yalnızca bir ekleme gerçekleştiğinde returning ifade sonucunu döndürür, güncelleştirmeler için None döndürülür, bu nedenle burada yardım yok.

Bundan yola çıkarak, UPDATE ... RETURNING SQL özelliğini kullanmak isterseniz, StaticQuery'u kullanmanız veya kendi yamağunuzu Slick'e döndürmeniz gerektiği sonucuna varabiliriz. Manuel sorguları yazma (ve GetResult/setParameter serileştiriciler olarak masa projeksiyonları yeniden uygulamak) veya bu kod parçacığını deneyebilirsiniz:

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

Yukarıda geliştirilebilir eminim; Ben biraz Slick internals benim sınırlı bir anlayış benim dayalı olarak yazdım ve benim için çalışır ve zaten tanımladığınız projeksiyonlar/tip-mappings kaldırabilir.

Kullanımı:

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

Teşekkürler! Eğer Slick 3.0 için güncellenmiş bir versiyon varsa harika olurdu :-) –

+0

Slick 3'te bununla ilgili bir fark var mı? – Ixx

+0

Henüz Slick 3 ile ilgili bir güncelleme yapmadık. Eminim genel yaklaşım işe yarayacaktır, ancak API'ların ve veri yapılarının bir şekilde değişmesi muhtemeldir. –

İlgili konular