问题
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:
Is there a way to prevent it from trying to update the key value?
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 arbitraryobject
- 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