Ideally, I would like to have:
public user Update(User dto) {
var user = userRepository.GetUserById(dto.Id);
var mergedFields = Merge(user, dto); //my dream function
userRepository.UpdateOnly(user, mergedFields)
.Where(u => u.Id == user.Id); //OrmLite UpdateOnly func
return user;
}
Where Merge
is my deam function that returns a Linq Expression:
Expression<Func<T, TKey>> Merge(T target, T source)
So, Merge
knows what was updated from T source to T target. Update the values of these properties in target, and return these updated properties as Linq Expression for OrmLite UpdateOnly to use.
However, I am pulling my hair and I can't figure out how to write this Merge
function. Please throw me some help!
Thank you!
Ref: ServiceStack OrmLite is a light weight ORM. It's UpdateOnly
function takes a Linq Expression like this:
.UpdateOnly(new User {FirstName="admin", LastName="my", OtherStuff="etc..."},
u => {u.FirstName, u.LastName}).Where(u => u.Id == 123);
While I can see what you are trying to do, there as already a built in mechanism for achieving partial updates without having to build a Linq Expression of the changed values.
I think OrmLite's UpdateNonDefaults
is better suited to your task.
Your Update action should only be receiving changes to your existing record in the DTO, not a full object. So doing this, should be sufficient:
db.UpdateNonDefaults(dto, u => u.Id == 123);
Results in SQL:
UPDATE "User" SET "FirstName" = 'admin', "LastName" = 'my' WHERE ("UserId" = 123);
If your update request where to contain a full object, the database would simply overwrite all the existing values with the same values, but this action shouldn't cost anymore than the processing time to lookup the entire existing object, make comparisons to determine changes using reflection, build a Linq Expression and run an UpdateOnly
query.
If you were dead set on checking for changed fields against the original then you could do it without the complexity of the Linq Expression. Your Merge function could do this (PseudoCode):
public T Merge(T target, T source)
{
var result = default(T);
Reflect your T target
public properties:
foreach(var property in target.GetType().GetPublicProperties()){
With each reflected property:
Determine whether the value changed using an EqualityComparer
:
if(!EqualityComparer<FieldType>.Default.Equals(targetField, sourceField))
Set the value on the result
object if the value is different.
Return the result
object. It will only have the changes.
Now using UpdateNonDefaults
with the result will ensure only the changes are included in the update SQL.
Is it worthwhile to do check of the changed fields? You should perhaps run some benchmarks. Remember that checking involves:
If you get stuck determining the changes on your objects, the answers in this question may help.
I hope this helps.