Question

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);
Was it helpful?

Solution

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)
{
  1. Create a new default object for the return. i.e. var result = default(T);
  2. Reflect your T target public properties:

    foreach(var property in target.GetType().GetPublicProperties()){
    

    With each reflected property:

    1. Determine whether the value changed using an EqualityComparer: if(!EqualityComparer<FieldType>.Default.Equals(targetField, sourceField))

    2. Set the value on the result object if the value is different.

  3. 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:

  • Querying the database for the entire existing record.
  • Reflecting properties on your target and source object.
  • Making comparisons of values.
  • Building a Linq Expression or new Object to keep track of what's changed.
  • Running the update function.

If you get stuck determining the changes on your objects, the answers in this question may help.

I hope this helps.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top