Reputation: 903
I have a class Customer
. I am trying to clone a Customer
object and modify it, then I want those modifications to be reflected in the context (database as well). I am using following code to do that.
Customer old = context.Customers.Where(c=>c.CustomerID ==1 ).SingleOrDefault();
Customer m = CustomExtensions.ShallowCopyEntity<Customer>(old);
m.Name = "Modified";
m.MobileNo = "9999999999";
context.Customers.Attach(m);
But its throwing following exception
Attaching an entity of type 'DataBindingSample.Customer' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.
I tried changing EntityState
to Modified
but it didn't work.
Can anyone tell me how to achieve this?
My main goals are
EDIT
As pointed out in this comment i am trying to attach object which aready exists in context. So i can detach it first and then atttach again as shown bellow if attach is compulsory.
Customer old = context.Customers.Where(c=>c.CustomerID ==1 ).SingleOrDefault();
Customer m = CustomExtensions.ShallowCopyEntity<Customer>(old);
m.Name = "Modified789789";
m.MobileNo = "9999999999";
((IObjectContextAdapter)context).ObjectContext.Detach(old);
context.Customers.Attach(m);
context.Entry(m).State = EntityState.Modified;
context.SaveChanges();
Otherwise i can follow 2 options mentioned in this answer.
Upvotes: 2
Views: 4297
Reputation: 7797
There are 2 options that I can think of:
DbContext
and then save changes.Options 1
Just copy the updated values back to the originally loaded entity. Automapper is your friend in tasks like this. This approach can later be extended to allow user to change a model of your entity and not the data layer object itself (e.g. to expose a limited number of fields that user can edit).
var entity = context.Customers.SingleOrDefault(c => c.CustomerID == 1);
var updatedEntity = CustomExtensions.ShallowCopyEntity<Customer>(old);
updatedEntity.Name = "Modified";
updatedEntity.MobileNo = "9999999999";
entity.Name = updatedEntity.Name;
entity.MobileNo = updatedEntity.MobileNo;
context.SaveChanges();
If you add Automapper nuget, then you mappings (copying) will become much easier:
Mapper.CreateMap<Customer, Customer>();
Mapper.Map(updatedEntity, entity);
And your code will look like:
// Configuring mapping. Needs to be done only once.
Mapper.CreateMap<Customer, Customer>();
var entity = context.Customers.SingleOrDefault(c => c.CustomerID == 1);
// Check if entity is null
var updatedEntity = CustomExtensions.ShallowCopyEntity<Customer>(old);
updatedEntity.Name = "Modified";
updatedEntity.MobileNo = "9999999999";
// Copy the updated values back
Mapper.Map(updatedEntity, entity);
context.SaveChanges();
Options 2
Make changes in the originally loaded entity and discard them if user changed her mind and canceled. See this post and this post on how to do it.
Discarding the whole DbContext
might not be a good option in case you still need it (duh).
Upvotes: 2