We often encounter this problem: When you update a part of an entity's data, you usually need a new object, and then the new object is attach to the context, and the code looks like this:
/// <summary> ///Update only the Defaultaddress field in the Storedaddress data to False///change default address to not default address/// </summary> /// <param name= "storedaddress" >Address Information</param> Public voidUpdate (storedaddress storedaddress) {storedaddress s=Newstoredaddress {Storedaddressid =Storedaddress.storedaddressid}; S.defaultaddress=true; _context. Storedaddresses.attach (s); S.defaultaddress=false; _context. SaveChanges (); _context. Detach (s);}
_context. Storedaddresses.attach (s); In this sentence, the program tends to report an exception---there are already objects of the same key in the Context, which makes some of our updates unsuccessful.
After analysis, we know that there is an object in the context, this object and our new object s has the same key, then which object is this object? It is not difficult to see that this object is storedaddress by code, so we need to detach the Storedaddress object from the context. Our new code is as follows:
/// <summary> ///Update only the Defaultaddress field in the Storedaddress data to False///change default address to not default address/// </summary> /// <param name= "storedaddress" >Address Information</param> Public voidupdatestoredaddressdefaultaddress (storedaddress storedaddress) {//Undo Tracking First_context. Detach (storedaddress); storedaddress s=Newstoredaddress {Storedaddressid =Storedaddress.storedaddressid}; S.defaultaddress=true; _context. Storedaddresses.attach (s); S.defaultaddress=false; _context. SaveChanges (); _context. Detach (s);}
Usually we don't know if the object has attach, here's a way to determine if the object has attach:
Public Static BOOLIsAttached ( ThisAllurecontext context,Objectentity) { if(Entity = =NULL) { Throw NewArgumentNullException ("Entity"); } ObjectStateEntry entry; if(Context. Objectstatemanager.trygetobjectstateentry (Entity, outentry)) { return(Entry. State! =System.Data.EntityState.Detached); } return false; }
The method call above is _context. IsAttached (storedaddress), which requires that we must know an object before we can judge whether the object has been attached. This is a more general solution because our Storedaddress object has been identified. If we change the first piece of code to:
///Update only the Defaultaddress field in the Storedaddress data to False///change default address to not default address/// </summary> /// <param name= "id" >The ID of the object that needs to be modified</param> Public voidUpdate (intID) {storedaddress s=Newstoredaddress {Storedaddressid =ID}; S.defaultaddress=true; _context. Storedaddresses.attach (s); S.defaultaddress=false; _context. SaveChanges (); _context. Detach (s); }
At this point we do not know that there is no object with the same key as the S object exists in the context, even if we now know that there is an object exists in the context, and the S object has the same key, but we do not know what this object is, want to detach this object, it is more difficult, because there is only one ID , I found some methods on the Internet:
1. Method one, write directly to the SQL statement, so as to update the objects in the database
2. Method Two, the object is obtained from the database by ID, and then deatch the object
For the method one, because we are using EF, so we also want to use EF things, for method two, we need to write a method, this method is responsible for the database to get this object, a bit cumbersome, performance, not tested, just feel trouble. So does EF have to give us some way to get this object through the only information we have, the answer is yes. Methods are as follows
Object NULL = _context. Createentitykey ("storedaddresses"if out Originalitem)) { _context. Detach (Originalitem);
This approach is a bit difficult to understand and we can put it in our code:
///Update only the Defaultaddress field in the Storedaddress data to False///change default address to not default address/// </summary> /// <param name= "id" >The ID of the object that needs to be modified</param> Public voidUpdate (intID) {storedaddress s=Newstoredaddress {Storedaddressid =ID}; ObjectOriginalitem =NULL; System.Data.EntityKey Key=_context. Createentitykey ("storedaddresses", s); if(_context. Trygetobjectbykey (Key, outOriginalitem)) {_context. Detach (Originalitem); } s.defaultaddress=true; _context. Storedaddresses.attach (s); S.defaultaddress=false; _context. SaveChanges (); _context. Detach (s); }
We can modify the database by EntityKey to get this object, then detach the object and then attach our new object S. In this method, note the use of Createentitykey (), the first parameter entitysetname, note that the name is the same as the name of Navigation properties, as detailed in
Http://msdn.microsoft.com/en-us/library/system.data.objects.objectcontext.createentitykey.aspx
Well, our changes have been completed.
Entity Framework Data Section update Attach/detach (RPM)