Dapper.Contrib
Dapper.Contrib copied to clipboard
Dapper Snapshotter Updates "modified" Properties rather than "changed"
Instead of Full Change tracking simply knowing which properties have had their setters called since the object was were returned by a Dapper would be a great feature.
If you retrieve a fresh object from the database and explicitly set a property, no matter what it should be issuing an update statement for that column when persisted . Dapper Snapshotter only looks at "modified" properties, instead of "changed" properties, therefore it may or may not issue and update for the column depending on original value held in memory. This is usually fine if concurrent connections are not updating the same columns or performing pessimist locking, however it can cause issues like: Client A fetches a column value of "Monday", Client B Updates the column to "Tuesday", then Client A sets the value on the object to "Monday" then performs an update, the outcome would be "Tuesday" even though Client A was last, this is because the Snapshotter thinks nothing has changed as the memory value is stale.
This causes unexpected results especially when implementing HTTP PUT requests that should replace the entire resource. A great explanation of this exists at: https://blog.jooq.org/2017/06/28/orms-should-update-changed-values-not-just-modified-ones/
Has anybody encountered any similar race conditions at scale? I was thinking of rolling my own Proxy implementation to keep track of calls made to setters as I can't see to find anything that suits my needs.
The usual solution in fully baked ORMs is to use versioning -- add a Version column, initially set to 0 or 1 on row creation. When updating the row, increment the Version but also condition it so the update fails unless the Version column has the same value as when the row was originally fetched. If it fails, then you have to re-fetch the row (with new Version) and reapply any updates that were intended (or just make it the user's problem to re-edit, depending on context).