0

My manager has a requirement where he wants the developer to personally set the ModifiedUserId field for any entity changes made to that entity. Therefore I have overridden the SaveChanges method so that we check the ModifiedUserId property of any modified entity to see if it has been set. If it has not been set we throw an error.

This works great except that our EF is using snapshot change detection so if ModifiedUserId is already 83, and the developer sets the value, per our requirements, to the same userid then the ModifiedUserId is not marked as a changed property so my check ultimately fails.

I have researched creating our own change proxies but have heard that it can be slow. Is there a way to have EF detect that we have in fact set the ModifiedUserId property even if it is the same while in snapshot mode? Any other ideas? Thank You.

  • 1
    Instead of throwing an error, you can set the value to the threads current identity. This removes responsibility from each developer having to remember to set it. You can then always set it when the entity is changed. Don't need to check anything besides "did this thing change" and "who is making the change", which you can get from the current thread or some other means. –  Apr 28 '17 at 22:18
  • We can't set it to the thread's current identity because the ModifiedUserId may not be the current identity and it doesn't force us as a developer to programmatically set it. I made that same suggestion to my mgr and he wants us to set it in code to ensure that we can track changes so if we forget, we can make the code change. - Thank You. –  Apr 28 '17 at 22:22
  • So the modified user id isn't related to the current user of the application? –  Apr 28 '17 at 22:26
  • All that kind of stuff is a unit test job – Sir Rufo Apr 28 '17 at 22:45

1 Answers1

0

Foreword: I really don't like the idea of throwing that exception, and I'd only set the entity as modified when it's not on a handful of occasions.

This said, if you have access to the context, you can do something like this :

DbEntityEntry entry = context.Entry(myTrackedEntity);
entry.State = EntityState.Modified;

If you don't have access to the context, or let's say you'd want that to happen "automatically" when you set the property, you could do something like this :

public class MyTrackedEntity
{
    // Your class stuff goes here.

    private int _modifiedUserId
    public int ModifiedUserId
    {
        get
        {
            return _modifiedUserId;
        }
        set
        {
            if (value != _modifiedUserId)
                _modifiedUserId = value;

            // This will be heavy, cpu-wise.
            var field = this.GetType().GetField("_entityWrapper");
            if (field != null)
            {
                var wrapper  = field.GetValue(this);
                var property = wrapper.GetType().GetProperty("Context");
                var context  = (ObjectContext)property.GetValue(wrapper, null);
                DbEntityEntry entry = context.Entry(this);
                entry.State = EntityState.Modified;
            }
            else
            {
                // If you're here, your entity isn't tracked.
            }
        }
    }
}

This is Heavily inspired from this post and that article.

Community
  • 1
  • 1
Tipx
  • 7,367
  • 4
  • 37
  • 59