how to stop dbentityentry.currentvalues.setvalues trying to change entitykey value

和自甴很熟 提交于 2019-12-10 17:41:57

问题


I am using the following code to update an entity object with the new information gathered from the my code. I am using Entity Framework 5.

I use the following extension method (as a alternative to the reattach code I used to use in EF4):

public static void ApplyValues(this object currentObject, object sourceObject, System.Data.Entity.DbContext obj)
{
  obj.Entry(currentObject).CurrentValues.SetValues(sourceObject);
}

The problem is that when this method is called the SetValues method tries to modify the EntityKey value on the attached object (obviously I do not want it to do this) and so it throws an error.

I suppose there are two questions here:

  1. Is there a way to prevent it from trying to update the key value?

  2. if not how do I replicate the ObjectContext.ApplyCurrentValues() code that used to work fine in EF4?

----UPDATE----

My previous code I used for EF4 is as follows:

public static System.Data.Objects.DataClasses.EntityObject ReAttach(this System.Data.Objects.ObjectContext obj, System.Data.Objects.DataClasses.EntityObject objectDetached)
{
    if (objectDetached.EntityKey != null)
    {
        object original = null;
        if (obj.TryGetObjectByKey(objectDetached.EntityKey, out original))
        {
            objectDetached = obj.ApplyCurrentValues(objectDetached.EntityKey.EntitySetName, objectDetached);
            return objectDetached;
        }
        else
        {
            throw new ObjectNotFoundException();
        }
    }
    else
    {
        return objectDetached;
    }
}

回答1:


In my opinion this exception indicates that something is wrong - or at least unusual - in your calling code.

currentObject is an attached entity while sourceObject is (normally) a detached object (not necessarily an entity) that should have the same key values (or no key properties at all).

Indeed setting the current values works differently with DbContext because you have to supply the current attached entity explicitly in order to update its current values. Using ApplyCurrentValues of ObjectContext you don't supply this entity:

objectContext.ApplyCurrentValues("MyEntitySet", sourceObject);

This is different because...

  • sourceObject must be an entity and cannot be an arbitrary object
  • it updates the values of the attached entity that has the same key values as sourceObject

In your example it would update another entity than currentObject because apparently currentObject is not the entity that has the same key as sourceObject.

If you have used ObjectStateEntry.ApplyCurrentChanges (which is closer to the new version in DbContext) you would get the same exception:

var objectContext = ((IObjectContextAdapter)obj).ObjectContext;

var entry = objectContext.ObjectStateManager.GetObjectStateEntry(currentObject);
entry.ApplyCurrentValues(sourceObject);

EF will complain here that you try to change the key values. And it will complain if sourceObject is not of the same type as currentObject while DbContext would allow that (which makes the procedure with DbContext more useful in my opinion because you can use arbitrary objects with matching property names - for example DTOs - to update the entity).

Edit

The main problem to reproduce the method you have used with EF 4 is that entities with EF 5/DbContext don't derive from EntityObject but are POCOs. Because of this you don't have an EntityKey available that would allow a generic implementation of this method.

What you could do is to introduce an interface that marks the key property of your entities, like so for example:

public interface IEntity
{
    int Id { get; set; }
}

Your entity classes would implement this interface, for instance an Order entity:

public class Order : IEntity
{
    public int Id { get; set; }
    public DateTime ShippingDate { get; set; }
    // etc.
}

You could create a generic method with a constraint for this interface:

public static T ReAttach<T>(DbContext context, T objectDetached)
    where T : class, IEntity
{
    T original = context.Set<T>().Find(objectDetached.Id);
    if (original == null)
        throw new ObjectNotFoundException();

    context.Entry(original).CurrentValues.SetValues(objectDetached);

    return objectDetached;
}

If your entities do not always have an int property Id but their keys have different types, names or could be composite it is probably the easier way to pass in the entity's key into the method instead of using an interface:

public static T ReAttach<T>(DbContext context, T objectDetached,
    params object[] keyValues) where T : class
{
    T original = context.Set<T>().Find(keyValues);
    if (original == null)
        throw new ObjectNotFoundException();

    context.Entry(original).CurrentValues.SetValues(objectDetached);

    return objectDetached;
}


来源:https://stackoverflow.com/questions/16646922/how-to-stop-dbentityentry-currentvalues-setvalues-trying-to-change-entitykey-val

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!