2015-07-09 10 views
7

Ho un tavolo user_permissions che dispone di 46 colonne di autorizzazione insieme a id e created_date. Questo tavolo ha un corrispondente UserPermissions classe:Slick - Aggiorna oggetto completo o più di 22 colonne

class UserPermission(val id: Long, 
    val createdDate: Option[Timestamp], 
    val permission1: Boolean, 
    val permission2: Boolean, 
    ... 
    val permission46: Boolean) 

e tabella di mappatura chiazza di petrolio

class UserPermissions(tag: Tag) extends Table[UserPermission](tag, "users_permissions") { 
    def * = (
    id :: 
    createdDate :: 
    permission1 :: 
    permission2 :: 
    ... 
    permission46 :: 
    HNil).shaped <> (
    { case x => UserPermission(
     x(0), x(1), x(2), ... x(47)) 
    }, 
    { 
     UserPermission.unapply _ 
    } 
    } 
    ... <columns defined here> 
) 

Ora voglio aggiornare insieme UserPermission che viene identificato da id. La funzione che ho è:

object UserPermissions { 
    val userPermissions = TableQuery[UserPermissions] 

    def update(userPermission: UserPermission)(implicit session: Session) = { 
    userPermissions.filter(_.id === userPermission.id.get).update(userPermission) 
    } 
} 

questo non sta funzionando e gettando Eccezione:

play.api.Application$$anon$1: Execution exception[[SQLServerException: Cannot update identity column 'id'.]] 

che ha senso come l'SQL generato da Slick è:

update "users_permissions" set "id" = ?, "created_date" = ?, ... 

Problema 1 Quindi il mio primo problema è che non riesco ad aggiornare un intero oggetto UserPermission con chiazza di petrolio. Se ho una soluzione a questo problema, sarebbe fantastico.


Dal momento che sono in grado di aggiornare piena oggetto poi ho pensato a yield le colonne che voglio aggiornare poi sparare una query di aggiornamento. Il codice è simile al seguente:

def update(obj: UserPermission)(implicit session: Session) = { 
    val query = for { 
     p <- userPermissions 
     if p.id === obj.id.get 
    } yield (p.permission1, p.permission2, ... p.permission46) 
    query.update(obj.permission1, obj.permission2, ... obj.permission46) 
} 

Problema 2 Ora chiazza di petrolio non è l'aggiornamento di 46 colonne in query.update() funzione. Può gestire solo 22 colonne alla volta. Come posso aggiornare il mio oggetto UserPermissions?

Una soluzione errata che posso pensare è di aggiornare 22 prima volta, poi 22 secondi, poi 2 nella terza query. Saranno 3 query di aggiornamento db che non voglio.

Qualche soluzione al mio problema?


dipendenze sono:


scalaVersion := "2.11.4" 

"com.typesafe.play" %% "play-slick" % "0.8.1" 
"com.typesafe.slick" %% "slick-extensions" % "2.1.0" 

risposta

1

Alcuni suggerimenti per il problema 2:

  • Potresti usare Slick 3.0? Questa versione sembra avere un solution
  • Potresti cambiare il layout del database in modo tale che le autorizzazioni siano righe anziché colonne? Questo sembra più estensibile in ogni caso
+0

Grazie per aver fornito suggerimenti. Li ho già presi in considerazione prima di postare ma non riesco ad implementare nessuno di questi. Poiché l'aggiornamento di 'play' e' slick' fa parte degli sprint futuri e il layout della tabella non può essere modificato come nei suoi sistemi di produzione e molte applicazioni sono strettamente accoppiate all'attuale design della tabella in modo che ne risentano tutti. –

3

Stefan Zeiger, il vantaggio di Slick, said non abbiamo potuto.Egli ha suggerito, tuttavia, che abbiamo annidato proiezioni sul tavolo 22+ colonne piatto:

// 2 classes for the nested structure 
case class Part(i1: Int, i2: Int, i3: Int, i4: Int, i5: Int, i6: Int) 
case class Whole(id: Int, p1: Part, p2: Part, p3: Part, p4: Part) 

// Note that it's a Table[Int] -- we only map the primary key in * 
object T extends Table[Int]("t_wide") { 
    def id = column[Int]("id", O.PrimaryKey) 
    def p1i1 = column[Int]("p1i1") 
    def p1i2 = column[Int]("p1i2") 
    def p1i3 = column[Int]("p1i3") 
    def p1i4 = column[Int]("p1i4") 
    def p1i5 = column[Int]("p1i5") 
    def p1i6 = column[Int]("p1i6") 
    def p2i1 = column[Int]("p2i1") 
    def p2i2 = column[Int]("p2i2") 
    def p2i3 = column[Int]("p2i3") 
    def p2i4 = column[Int]("p2i4") 
    def p2i5 = column[Int]("p2i5") 
    def p2i6 = column[Int]("p2i6") 
    def p3i1 = column[Int]("p3i1") 
    def p3i2 = column[Int]("p3i2") 
    def p3i3 = column[Int]("p3i3") 
    def p3i4 = column[Int]("p3i4") 
    def p3i5 = column[Int]("p3i5") 
    def p3i6 = column[Int]("p3i6") 
    def p4i1 = column[Int]("p4i1") 
    def p4i2 = column[Int]("p4i2") 
    def p4i3 = column[Int]("p4i3") 
    def p4i4 = column[Int]("p4i4") 
    def p4i5 = column[Int]("p4i5") 
    def p4i6 = column[Int]("p4i6") 
    // This is just the default projection -- It doesn't have to contain all columns 
    def * = id 
    // Instead, we use nested tuples for a full projection: 
    def all = (
    id, 
    (p1i1, p1i2, p1i3, p1i4, p1i5, p1i6), 
    (p2i1, p2i2, p2i3, p2i4, p2i5, p2i6), 
    (p3i1, p3i2, p3i3, p3i4, p3i5, p3i6), 
    (p4i1, p4i2, p4i3, p4i4, p4i5, p4i6) 
) 
    // And override create_* to get the DDL for all columns. 
    // Yeah, this is ugly. It used to be much simpler in ScalaQuery. 
    // We can add a helper method to simplify it. 
    override def create_* = 
    all.shaped.packedNode.collect { 
     case Select(Ref(IntrinsicSymbol(in)), f: FieldSymbol) if in == this => f 
    }.toSeq.distinct 
} 

T.ddl.create 
// Insert into T.all. The extra ".shaped" call is needed because we cannot 
// get the types in an implicit conversion due to SI-3346 
T.all.shaped.insert(
    0, 
    (11, 12, 13, 14, 15, 16), 
    (21, 22, 23, 24, 25, 26), 
    (31, 32, 33, 34, 35, 36), 
    (41, 42, 43, 44, 45, 46) 
) 

// Get the nested tuples in a query 
val q1 = T.map(_.all) 
println(q1.first) 

// Map the result to the case classes 
val i2 = q1.mapResult { case (id, p1, p2, p3, p4) => 
    Whole(id, Part.tupled.apply(p1), Part.tupled.apply(p2), Part.tupled.apply(p3), Part.tupled.apply(p4)) 
} 
println(i2.first) 

che ora è un test a Slick tra cui una per version 3. Per quanto riguarda l'aggiornamento:

val oData = Whole(0, 
    Part(11, 12, 13, 14, 15, 16), 
    Part(21, 22, 23, 24, 25, 26), 
    Part(31, 32, 33, 34, 35, 36), 
    Part(41, 42, 43, 44, 45, 46) 
) 
val oData2 = Whole(10, 
    Part(111, 12, 13, 14, 15, 16), 
    Part(121, 22, 23, 24, 25, 26), 
    Part(131, 32, 33, 34, 35, 36), 
    Part(141, 42, 43, 44, 45, 46) 
) 

ts.ddl.create 

ts.insert(oData) 
assertEquals(oData, ts.first) 

ts.filter(_.p1i2 === 12).update(oData2) 
assertEquals(oData2, ts.first) 

Gli oggetti nidificati con proiezioni di Slick possono essere appiattiti per il singolo oggetto che si mettono in, o da portare via con.

Problemi correlati