Reputation: 666
In my use case I have a createdDate
field that I would like to preserve in the event that the record already exists.
case class Record(id:Long, value:String, createdDate:DateTime, updateDate:DateTime)
Is it possible to use a TableQuery.insertOrUpdate(record) such that only parts of the record are updated in the event the record already exists?
In my case I'd want only the value
and updateDate
fields to change. Using plain SQL in a stored procedure I'd do something like:
merge Record r
using (
select @id,
@value
) as source (
id,
value
)
on r.id = source.id
when matched then
update set value = source.value, updateDate = getDate()
when not matched then
insert (id, value, createdDate, updatedDate) values
(id, value, getDate(), getDate()
Upvotes: 3
Views: 561
Reputation: 45303
Can Slick's
insertOrUpdate
modify a subset of columns?
No, I don't believe this is possible with the insertOrUpdate
function. This has been requested as a feature but it is not currently implemented.
How can we work around this?
Since the update
function does support updating a specific list of columns, we can write our own upsert logic instead of using the insertOrUpdate
function. It might work like this:
def insertOrUpdate(record: Record): Future[Int] = {
val insertOrUpdateAction = for {
recordOpt <- records.filter(_.id === record.id).result.headOption
updateAction = recordOpt.map(_ => updateRecord(record))
action <- updateAction.getOrElse(insertRecord(record))
} yield action
connection.run(insertOrUpdateAction)
}
private def updateRecord(record: Record) = {
val query = for {
r <- records.filter(_.id === record.id)
} yield (r.value, r.updatedDate) // list of columns which can be updated
query.update(record.value, record.updatedDate)
}
private def insertRecord(record: Record) = records += record
Upvotes: 1