An entity object cannot be referenced by multiple instances of IEntityChangeTracker error when trying to save changes to multiple types of entities - asp.net-mvc

I have a controller action where I am attempting to both create a new object in the database, of type FantasyTeam, and also modify an existing object, of type User. However, when the action is called I am receiving a System.InvalidOperationException exception, with the explanation of:
An entity object cannot be referenced by multiple instances of
IEntityChangeTracker.
My code is below.
public ActionResult Create([Bind(Include="ID,FantasyTeamName")] FantasyTeam fantasyteam)
{
if (ModelState.IsValid)
{
var CurrentUser = UserManager.FindById(User.Identity.GetUserId());
fantasyteam.OwnerID = CurrentUser.Id;
CurrentUser.HasTeam = true;
db.FantasyTeams.Add(fantasyteam);
db.Entry(CurrentUser).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Dashboard", "Application");
}
return View(fantasyteam);
}
The Controller Action takes the new FantasyTeam object as a parameter from the View where the team details are selected by user. I then find the currently logged in user and set the OwnerID of the team to match the UserID of the owner, as my Foreign Key. I then go to add the new FantasyTeam to the database and also modify the User record in the database, changing the Boolean HasTeam to true. The adding of the new team works fine on its own... I have been getting the exception once I tried to modify the User object as well.
I have searched on StackOverflow for this exception, and have found many related issues, but I couldn't find a way to apply the other resolutions to my problem. In some cases the issue was that the developers were using two separate data contexts when they should have just been using one, but I don't think that would apply to me here.
Could someone offer insight as to what might be going wrong here?
Thanks!

According to Linq to SQL DataContext Lifetime Management the main causality of the problem comes from the below reason.
Linq to SQL uses a DataContext to manage it's access to the database as well as tracking changes made to entities retrieved from the database. Linq to SQL has a persistent approach to managing its 'connection' to the database via this data context and it basically assumes that you use a single DataContext to make all of your data related access. This doesn't mean that it makes persistent connections to the database, but means that the DataContext instance maintains state about active result sets, which is especially important if change tracking is on which is the default.

The comment posted by haim770 was the answer - I didn't realize that the UserManager object was using a different context than the db object was using. Once I changed the UserManager object to use the same context as db, my code works as intended.

Related

Error when adding to many-to-many table in EF6

I have recently changed from ObjectContext to DbContext using EntityFramwework by upgrading to EF6
Most stuff works, but saving and updating won't. Here is an example:
public void AssignToAdmin(Product product, Admin admin)
{
var pcsps = from s in context.ProductCreationSections
join pcsp in context.ProductCreationSectionAndProducts on s.ProductCreationSecitionID equals pcsp.ProductCreationSectionID
where pcsp.ProductID == product.ProductID && s.IsManagerAssigned
select pcsp;
foreach (var pcsp in pcsps.Include("AssignedAdmins"))
{
pcsp.AssignedAdmins.Add(admin);
}
}
Trying to execute the line pcsp.AssignedAdmins.Add(admin), I get the error:
Error: The relationship between the two objects cannot be defined
because they are attached to different ObjectContext objects.
There is one context for the class and it comes from Dependency Injection (the class is a Service in an MVC app).
I've tried removing/attaching and so on, but this doesn't fix it - it just gives different error messages. It's not even obvious which entity is using another context.
Any ideas of where this other context the error message refers to is coming from?
See The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects
Where has admin come from?
Getting the admin object from the same context as the pcsp object should help.
Sorted it, but it was quite a major refactor.
The issue was that each service received it's own instance of 'context', so when two entities from two services were expected to work together, they wouldn't as each belonged to a different context.
One solution would have been to make the class that created the context a 'Singleton' so that it always returned the same instance, but that would have been very BAD as every page would then use the same context.
Each service got it's own instance of 'context' through Dependency Injection.
I changed the project so only the controllers got an instance of context through DI. Then, in the controller constructor, this context was passed to the services that the controller had received through dependency injection.
This way, each request only ever uses a single instance of context, but this instance is still short lived, as it is supposed to be as each request has its own context and doesn't share one.
Not sure this is the way it is supposed to work, but given the web app I was working with, this seemed to be the best solution.
I also had to go through and add a 'context.SaveChanges();' statement everywhere a change to the database was made.
Not sure why this should be when the old version of EF did this automatically, but it now works.
Thanks for the advice Derrick

How do I determine the ID of an aggregate root added to a repository?

Say I have a generic repository interface as follows:
public interface IRepository<T>
{
Add(T item);
Delete(int itemId);
Update(T item);
}
Typically the new ID of an item added through IRepository.Add() would be determined by some back-end database, but only once the overall transaction/unit of work has been submitted. So I'm fairly certain that it would be wrong for IRepository.Add() to return the new ID of the added item. The repository really shouldn't know anything about how ID are created. Is this correct?
If this is a case how else can one determine the new ID of an item added to a repository, or should I even be doing this? I know an ORM like NHibernate is able to automagically replace objects in memory with new objects with the correct ID, but I'm trying to design my repository with out any specific ORM implementation in mind.
For example say I have a website where customers can make orders. A new customer chooses to check out and is sent to a form to fill out their details. This information is used to create a Customer object which is stored in a CustomerRepository. Now their order information needs to be created but an Order needs to reference a Customer by their ID?
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
customerRepository.Add(newCustomer);
//How would I determine customerId??
Order newOrder = new Order(customerId, shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");
In the example you give, I would create the Customer and Order in one step, and pass domain objects to domain objects, instead of passing Ids:
Customer newCustomer = new Customer(first, last, address, phone dateOfBirth);
// Pass the customer rather than the CustomerId:
Order newOrder = new Order(newCustomer , shippingAddress, billingAddress);
newOrder.AddOrderItem("widget");
newOrder.AddOrderItem("doohicky");
newOrder.AddOrderItem("stuff");
customerRepository.Add(newCustomer);
orderRepository.Add(newOrder);
// SaveChanges()
...when the changes are saved, the framework automatically populates the Ids of both Customer and Order, and fills in Customer.Id, Order.customerId, (etc.) by virtue of the Customer object having been assigned to the Order.
Eric,
In the scenario you mention, I don't see any CommitChanges() going on. I would wrap everything in a transactionscope and then hit customerRepository.CommitChanges() before you add the orderlines. you should then be able to grab the id from the newly created customer object and use it as follows:
Order newOrder = new Order(newCustomer.Id, shippingAddress, billingAddress);
then, if the order(s) fails, you can roll everything back and keep it atomic by not hitting scope.Complete().
hope this helps..
I generate id on a client (a la CombGuid.NewGuid()) and then pass it to constructor. Approach when you are using database identity has serious disadvantages
Whether or not you use NHibernate, I feel that the approach it takes is the right one. Your goal with any domain objects is to only ever have one instance of that object in memory at any one time, i.e. you should never have two objects that represent the same database record. It follows that if the database has updated the record with a new id, the domain object in memory should also be updated with that ID since that is the "one" true representation of that record.
After calling Add, the object's ID is set and you could then make further changes to that object and call Update without having to know too much about your implementation.
Your interface is more DAO than Repository according to DDD:
http://codebetter.com/iancooper/2011/04/12/repository-saveupdate-is-a-smell/
Like Steve Wilkes mentioned, you should keep reference of Customer in Order and not Customer Id so when Unit of Work is processed, it will create correct link those Entities in Persistence Storage (SQL DB, Web Service etc)
For more on DAO here: http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
Domain entities should have their own ID strategy regardless database IDs, so preferably generate your id in the domain layer, or if you really need to generate id in database, then add another domain identifier generated at domain layer beside the database auto generated id.
In domain driven design where you apply repository pattern you should not tie your domain with database so relying on database for id creation is not a good idea.
Another point is that you may want to make customer associated in order not just putting the customer id, this makes the domain layer rich and solid.

Update relationships when saving changes of EF4 POCO objects

Entity Framework 4, POCO objects and ASP.Net MVC2. I have a many to many relationship, lets say between BlogPost and Tag entities. This means that in my T4 generated POCO BlogPost class I have:
public virtual ICollection<Tag> Tags {
// getter and setter with the magic FixupCollection
}
private ICollection<Tag> _tags;
I ask for a BlogPost and the related Tags from an instance of the ObjectContext and send it to another layer (View in the MVC application). Later I get back the updated BlogPost with changed properties and changed relationships. For example it had tags "A" "B" and "C", and the new tags are "C" and "D". In my particular example there are no new Tags and the properties of the Tags never change, so the only thing which should be saved is the changed relationships. Now I need to save this in another ObjectContext. (Update: Now I tried to do in the same context instance and also failed.)
The problem: I can't make it save the relationships properly. I tried everything I found:
Controller.UpdateModel and Controller.TryUpdateModel don't work.
Getting the old BlogPost from the context then modifying the collection doesn't work. (with different methods from the next point)
This probably would work, but I hope this is just a workaround, not the solution :(.
Tried Attach/Add/ChangeObjectState functions for BlogPost and/or Tags in every possible combinations. Failed.
This looks like what I need, but it doesn't work (I tried to fix it, but can't for my problem).
Tried ChangeState/Add/Attach/... the relationship objects of the context. Failed.
"Doesn't work" means in most cases that I worked on the given "solution" until it produces no errors and saves at least the properties of BlogPost. What happens with the relationships varies: usually Tags are added again to the Tag table with new PKs and the saved BlogPost references those and not the original ones. Of course the returned Tags have PKs, and before the save/update methods I check the PKs and they are equal to the ones in the database so probably EF thinks that they are new objects and those PKs are the temp ones.
A problem I know about and might make it impossible to find an automated simple solution: When a POCO object's collection is changed, that should happen by the above mentioned virtual collection property, because then the FixupCollection trick will update the reverse references on the other end of the many-to-many relationship. However when a View "returns" an updated BlogPost object, that didn't happen. This means that maybe there is no simple solution to my problem, but that would make me very sad and I would hate the EF4-POCO-MVC triumph :(. Also that would mean that EF can't do this in the MVC environment whichever EF4 object types are used :(. I think the snapshot based change tracking should find out that the changed BlogPost has relationships to Tags with existing PKs.
Btw: I think the same problem happens with one-to-many relations (google and my colleague say so). I will give it a try at home, but even if that works that doesn't help me in my six many-to-many relationships in my app :(.
Let's try it this way:
Attach BlogPost to context. After attaching object to context the state of the object, all related objects and all relations is set to Unchanged.
Use context.ObjectStateManager.ChangeObjectState to set your BlogPost to Modified
Iterate through Tag collection
Use context.ObjectStateManager.ChangeRelationshipState to set state for relation between current Tag and BlogPost.
SaveChanges
Edit:
I guess one of my comments gave you false hope that EF will do the merge for you. I played a lot with this problem and my conclusion says EF will not do this for you. I think you have also found my question on MSDN. In reality there is plenty of such questions on the Internet. The problem is that it is not clearly stated how to deal with this scenario. So lets have a look on the problem:
Problem background
EF needs to track changes on entities so that persistance knows which records have to be updated, inserted or deleted. The problem is that it is ObjectContext responsibility to track changes. ObjectContext is able to track changes only for attached entities. Entities which are created outside the ObjectContext are not tracked at all.
Problem description
Based on above description we can clearly state that EF is more suitable for connected scenarios where entity is always attached to context - typical for WinForm application. Web applications requires disconnected scenario where context is closed after request processing and entity content is passed as HTTP response to the client. Next HTTP request provides modified content of the entity which has to be recreated, attached to new context and persisted. Recreation usually happends outside of the context scope (layered architecture with persistance ignorace).
Solution
So how to deal with such disconnected scenario? When using POCO classes we have 3 ways to deal with change tracking:
Snapshot - requires same context = useless for disconnected scenario
Dynamic tracking proxies - requires same context = useless for disconnected scenario
Manual synchronization.
Manual synchronization on single entity is easy task. You just need to attach entity and call AddObject for inserting, DeleteObject for deleting or set state in ObjectStateManager to Modified for updating. The real pain comes when you have to deal with object graph instead of single entity. This pain is even worse when you have to deal with independent associations (those that don't use Foreign Key property) and many to many relations. In that case you have to manually synchronize each entity in object graph but also each relation in object graph.
Manual synchronization is proposed as solution by MSDN documentation: Attaching and Detaching objects says:
Objects are attached to the object
context in an Unchanged state. If you
need to change the state of an object
or the relationship because you know
that your object was modified in
detached state, use one of the
following methods.
Mentioned methods are ChangeObjectState and ChangeRelationshipState of ObjectStateManager = manual change tracking. Similar proposal is in other MSDN documentation article: Defining and Managing Relationships says:
If you are working with disconnected
objects you must manually manage the
synchronization.
Moreover there is blog post related to EF v1 which criticise exactly this behavior of EF.
Reason for solution
EF has many "helpful" operations and settings like Refresh, Load, ApplyCurrentValues, ApplyOriginalValues, MergeOption etc. But by my investigation all these features work only for single entity and affects only scalar preperties (= not navigation properties and relations). I rather not test this methods with complex types nested in entity.
Other proposed solution
Instead of real Merge functionality EF team provides something called Self Tracking Entities (STE) which don't solve the problem. First of all STE works only if same instance is used for whole processing. In web application it is not the case unless you store instance in view state or session. Due to that I'm very unhappy from using EF and I'm going to check features of NHibernate. First observation says that NHibernate perhaps has such functionality.
Conclusion
I will end up this assumptions with single link to another related question on MSDN forum. Check Zeeshan Hirani's answer. He is author of Entity Framework 4.0 Recipes. If he says that automatic merge of object graphs is not supported, I believe him.
But still there is possibility that I'm completely wrong and some automatic merge functionality exists in EF.
Edit 2:
As you can see this was already added to MS Connect as suggestion in 2007. MS has closed it as something to be done in next version but actually nothing had been done to improve this gap except STE.
I have a solution to the problem that was described above by Ladislav. I have created an extension method for the DbContext which will automatically perform the add/update/delete's based on a diff of the provided graph and persisted graph.
At present using the Entity Framework you will need to perform the updates of the contacts manually, check if each contact is new and add, check if updated and edit, check if removed then delete it from the database. Once you have to do this for a few different aggregates in a large system you start to realize there must be a better, more generic way.
Please take a look and see if it can help http://refactorthis.wordpress.com/2012/12/11/introducing-graphdiff-for-entity-framework-code-first-allowing-automated-updates-of-a-graph-of-detached-entities/
You can go straight to the code here https://github.com/refactorthis/GraphDiff
I know it's late for the OP but since this is a very common issue I posted this in case it serves someone else.
I've been toying around with this issue and I think I got a fairly simple solution,
what I do is:
Save main object (Blogs for example) by setting its state to Modified.
Query the database for the updated object including the collections I need to update.
Query and convert .ToList() the entities I want my collection to include.
Update the main object's collection(s) to the List I got from step 3.
SaveChanges();
In the following example "dataobj" and "_categories" are the parameters received by my controller "dataobj" is my main object, and "_categories" is an IEnumerable containing the IDs of the categories the user selected in the view.
db.Entry(dataobj).State = EntityState.Modified;
db.SaveChanges();
dataobj = db.ServiceTypes.Include(x => x.Categories).Single(x => x.Id == dataobj.Id);
var it = _categories != null ? db.Categories.Where(x => _categories.Contains(x.Id)).ToList() : null;
dataobj.Categories = it;
db.SaveChanges();
It even works for multiple relations
The Entity Framework team is aware that this is a usability issue and plans to address it post-EF6.
From the Entity Framework team:
This is a usability issue that we are aware of and is something we have been thinking about and plan to do more work on post-EF6. I have created this work item to track the issue: http://entityframework.codeplex.com/workitem/864 The work item also contains a link to the user voice item for this--I encourage you to vote for it if you have not done so already.
If this impacts you, vote for the feature at
http://entityframework.codeplex.com/workitem/864
All of the answers were great to explain the problem, but none of them really solved the problem for me.
I found that if I didn't use the relationship in the parent entity but just added and removed the child entities everything worked just fine.
Sorry for the VB but that is what the project I am working in is written in.
The parent entity "Report" has a one to many relationship to "ReportRole" and has the property "ReportRoles". The new roles are passed in by a comma separated string from an Ajax call.
The first line will remove all the child entities, and if I used "report.ReportRoles.Remove(f)" instead of the "db.ReportRoles.Remove(f)" I would get the error.
report.ReportRoles.ToList.ForEach(Function(f) db.ReportRoles.Remove(f))
Dim newRoles = If(String.IsNullOrEmpty(model.RolesString), New String() {}, model.RolesString.Split(","))
newRoles.ToList.ForEach(Function(f) db.ReportRoles.Add(New ReportRole With {.ReportId = report.Id, .AspNetRoleId = f}))

Entity Framework creating new record instead of modifying existing one

I'm using Entity Framework with an AS.NET MVC application. I need to allow the user to create new records and modify existing ones. I am able to fetch existing records no problem, but when I pass back in the edited entity and try to save it it creates a new one and saves it and leaves the original unmodified.
I am getting the object from EF using the primary key (e.g. ID number for an employee record). I successfully retrieve it, and set the MergeOption like so:
Context.Sector.MergeOption = MergeOption.NoTracking;
I am able to trace that the object has the correct data (using the key of the original record) all the way down to the point where I call:
Context.SaveChanges();
However, after that, the new record is created instead of modifying the existing one.
Is there something obvious I am missing here? I would have thought that retrieving the object and changing some of its values (not the ID) and saving it would just work, but obviously not.
Thanks,
Chris
"NoTracking means that the ObjectStateManager is bypassed and therefore every access to the Entity Objects results in a fetch from the database and the creation of new objects."
-- http://blog.dynatrace.com/2009/03/11/adonet-entity-framework-unexpected-behaviour-with-mergeoptions/
I don't think NoTracking is what you want.
From your comment: "distributed across various tiers and some proprietary libraries"
Are you new()ing up a ObjectContext, closing it or losing the reference to it, and then trying to save your object to a new() or different ObjectContext?
If so your losing all of your change tracking information. If this is the case then you want to call the Attach() method to reattach the entity to the context, ApplyPropertyChanges() and then finally SaveChanges().
Julie Lerman has a pretty good blog post that outlines all the different change tracking options and techniques that are available. You should also check out this MSDN article on the same subject.

Updating a disconnected LINQ object with MVC Framework RC1

This is a little out there but I have a customer object coming back to my controller. I want to just reconnect this object back to the database, is it even possible? I know there is a datacontext.customers.insertonsubmit(customer), but is there the equivalent datacontext.customers.updateonsubmit(customer)???
This is what I don't like about LINQ-to-SQL.
It generally works fine if you're querying and updating in the same scope, but if you get an object, cache it, and then try to update it later, you can't.
Here's what the documentation says:
Use the Attach methods with entities that have been created in one DataContext, and serialized to a client, and then deserialized back with the intention to perform an update or delete operation. Because the new DataContext has no way of tracking what the original values were for a disconnected entity, the client is responsible for supplying those values. In this version of Attach, the entity is assumed to be in its original value state. After calling this method, you can then update its fields, for example with additional data sent from the client.
Do not try to Attach an entity that has not been detached through serialization. Entities that have not been serialized still maintain associations with deferred loaders that can cause unexpected results if the entity becomes tracked by a second data context.
A little ambiguous IMHO, specifically about exactly what it means by "serialized" and "deserialized".
Also, interestingly enough, here's what it says about the DataContext object:
In general, a DataContext instance is
designed to last for one "unit of
work" however your application defines
that term. A DataContext is
lightweight and is not expensive to
create. A typical LINQ to SQL
application creates DataContext
instances at method scope or as a
member of short-lived classes that
represent a logical set of related
database operations.
So, DataContexts are intended to be tightly scoped - and yet to use Attach(), you have to use the same DataContext that queried the object. I'm assuming/hoping we're all completely misunderstanding what Attach() is really intended to be used for.
What I've had to do in situations like this is re-query the object I needed to update to get a fresh copy, and then do the update.
The customer that you post from the form will not have entity keys so may not attach well, also you may not have every field of the customer available on the form so all of it's fields may not be set.
I would recommend using the TryUpdateModel method, in your action you'll have to get the customer from the database again and update it with the form's post variables.
public ActionResult MySaveAction(int id, FormCollection form)
{
Customer updateCustomer = _Repository.GetCustomer(id);
TryUpdateModel(updateCustomer, "Customer", form);
_Repository.Save(updateCustomer);
}
You will have to add in all your own exception handling and validation of course, but that's the general idea.
You want to use the attach method on the customers table on the data context.
datacontext.customers.Attach(customer);
to reconnect it to the data context. Then you can use SubmitChanges() to update the values in the database.
EDIT: This only works with entities that have been detached from the original data context through serialization. If you don't mind the extra call to the database, you can use the idiomatic method in ASP.NET MVC of retrieving the object again and applying your changes via UpdateModel or TryUpdateModel as #Odd suggests.

Resources