raoulsson
raoulsson

Reputation: 16345

Slick lifted update on an Object

I do updates on lifted entities using Slick. This code updates the firstName of a Contact object:

def updateContact(id: Int, firstName: Option[String]): Unit = {
  val q1 = for {
    c <- Contacts
    if c.id is id
  } yield c.firstName
  // Update value with same or new value
  q1.update(firstName.getOrElse(q1.list().head))
}

The option here is already useful for updating the value in case it is a Some (although it would be nicer if the update only happened if there is a new value).

What I am looking for is a way to query the object by ID, then do all the updates in memory using getOrElse and then do an update on the whole object.

Else I have to run the above for each field of the object which works but you know, feels like a dirty hack.

Upvotes: 0

Views: 1997

Answers (1)

cvogt
cvogt

Reputation: 11270

Instead of q1.update(firstName.getOrElse(q1.list().head)) you can write firstName.foreach{ fn => q1.update(fn) } which is shorter, simpler, one instead of two queries :). Using foreach on Option stops looking weird when you think of it as a collection with one or zero elements.

Regarding your idea to fetch the whole object, modify it and save it back, you can do it like this:

def updateContact(id: Int, firstName: Option[String], lastName:Option[String], ...): Unit = {
  val q1 = Query(Contacts).filter(_.id === id)
  val c = q1.first
  val modifiedC = c.copy(
    firstName = firstName.getOrElse(c.firstName),
    lastName = lastName.getOrElse(c.lastName),
    ...
  )
  q1.update(modifiedC)
}

Here is another example: http://sysgears.com/notes/how-to-update-entire-database-record-using-slick/

This is clean and simple and probably the best way to do it if performance is not mission critical as this always transfers all columns of Contacts. You can save some traffic by only transferring selected columns.

Upvotes: 3

Related Questions