Hi i am trying to attach multiple objects in ObjectContextManager and try to set their state in "Added" Mode. These objects have some navigational properties with them and when i try to attach any object after attaching the first object. It throws me the error
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
The reason seems to be very obvious but what will be its solution.
Kindly guide
By calling Attach or AddObject on the entity you are actually attaching or adding whole object graph (EF traverse navigation properties and executes the operation on every related property). When you try to add or attach entity which was already attached or added as part of object graph you will get this exception. The solution is to understand your data model and call AddObject or Attach only for disjointed object graphs.
You should initialize the Id of new entities you add/attach with a random Id (like Guid.NewGuid().GetHashCode() if you use Int32 as Id-type)
Otherwise have all entities the default Id of 0, and so will the ObjectStateManager throw an exception when you attach the entities.
Related
Scenario:
I use breeze for querying in our SPA and raw http methods for POST PUT DELETE methods.
A POST method on a resource returns the created resource including it's created childobjects.
I want to attach this created resource to the beeze entity manager.
I've tried adding the entity using
manager.createEntity('Driver', data, breeze.EntityState.Unchanged);
where the data object contains the driver resource and an array of related child entities.
But get an exception: "Collection navigation properties may NOT be set."
Do I have to create the local entity by hand and attach the child entities or does breeze support this scenario?
The reason for this exception is that the 'createEntity' method creates the entity and then assigns your 'data' to it, but for any collection navigation properties the collection already exists and Breeze won't allow you to replace it. This was a deliberate choice for existing entities where other parts of the application might hold a reference to the collection, but is overkill in this case where you are the 'first' to access the collection. For now, the workaround is to update any navigation collections instead of replacing them.
So the simplest way to do this is to call the createEntity method without any collection data properties, and then push data into your collections
var driver = manager.createEntity('Driver', dataWithoutCollections, EntityState.Unchanged)
// then update collection properties by pushing into them.
trafficFines.forEach(function(trafficFine) {
driver.trafficFines.push(trafficFine); // or use push.apply
};
Note that adding to an entity's collection properties will not cause an EntityState change so this should be sufficient.
Based on this issue, I will add a feature request to suppress this exception in the case where you are calling the 'createEntity' method, since there is no danger that some other part of the application has already had access to the new entity.
in EF1, i couldn't just update an object that was constructed (with the right id) outside the scope of the ObjectContext.
Is there a new way in EF4?
Can i just add it to the context (context.AddOrder(order)) (where context is an instance of my ObjectContext) and 'it' sees that it has an id and updates it?
It's non-poco so my objects derive from EntityObject
If it's a brand new object then you should use either ObjectContext.AddObject or ObjectSet.AddObject:
The AddObject method is for adding newly created objects that do not exist in the database. The entity will get an automatically generated temporary EntityKey and its
EntityState will be set to Added.
On the other hand ObjectContext.Attach and ObjectSet.Attach is used for entities that already exist in the database. Rather than setting the EntityState to Added, Attach results in an Unchanged EntityState, which means it has not changed since it was attached to the context. Objects that you are attaching are assumed to exist in the database.
For a more detailed discussion on this topic, please take a look at this post:
Entity Framework 4 - AddObject vs Attach
Use the Attach method instead. It is designed for disconnected objects.
Taken from Employee Info Starter Kit, you can consider the code snippet as below:
public void UpdateEmployee(Employee updatedEmployee)
{
//attaching and making ready for parsistance
if (updatedEmployee.EntityState == EntityState.Detached)
_DatabaseContext.Employees.Attach(updatedEmployee);
_DatabaseContext.ObjectStateManager.ChangeObjectState(updatedEmployee, System.Data.EntityState.Modified);
_DatabaseContext.SaveChanges();
}
In the past I used Sub Sonic which has the activerecord pattern baked into the framework. With Sub Sonic it was very easy to find the "dirty" fields on an update. I now have a need to create an audit table in my application that utilizes Entity Framework 4. Is there a comparable feature in EF 4 that will give me the dirty fields?
Thanks for your help!
You can get similar functionality with what is described in this page at MSDN:
Identity Resolution, State Management, and Change Tracking
Change Tracking -> Change tracking
information for the object graph is
stored in ObjectStateEntry objects,
which are created by the ObjectContext
for each attached object.
ObjectStateEntry objects store the
following information for the
entities:
...
The names of the entity's modified
properties.
Entity State -> The object context must know the state of an object to
save changes back to the data source.
ObjectStateEntry objects store
EntityState information. The
SaveChanges methods of the
ObjectContext process entities that
are attached to the context and update
the data source depending on the
EntityState of each object. For more
information, see Creating, Adding,
Modifying, and Deleting Objects. The
following table shows the possible
states of an object.
The state of objects inside an object context is managed by the ObjectStateManager. To find out the state of an object, call one of the following ObjectStateManager methods: TryGetObjectStateEntry, GetObjectStateEntry, or GetObjectStateEntries. The State property of the ObjectStateEntry defines the state of the object.
Take a look at this article for more info:
What's New and Cool in Entity Framework 4.0
I have a detached set of client objects that I'd like to update (I know they already exist in the db by primary key). Now I want to update them to the database. Knowing I need to query them first, I do so and now have to basically take the properties from the deattached objects and apply them to the attached objects. I finally call save changes. Is there a slick way to apply these properties from the detached collection to the attached one?
NOTE: The detached objects don't have the primary keys in them but I do have enough information to link with via a comparer class.
You don't need to do what you're doing. You can just call the Attach method on your ObjectContext to tell it that you want to work with your detatched objects. Then just call SaveChanges to update the database with your changed objects.
I am trying to attach an entity to the ObjectContext.
When I do so, the following InvalidOperationException is thrown:
An object with the same key already exists in the ObjectStateManager.
The ObjectStateManager cannot track multiple objects with the same key.
I checked in the object state manager and the item does not exist:
//Data context is actually the object context.
ObjectStateEntry contact;
while ( //Should only work once since it should be true if the item was attached
!DataContext.ObjectStateManager.
TryGetObjectStateEntry(Contact, out contact)
)
DataContext.Attach(Contact); //Here is the exception thrown.
Or look at this abstract example and tell me if it makes sense:
EntityState state = Contact.EntityState; //Detached
DataContext.Attach(Contact); //Throws the exception.
DataContext.AttachTo("Entities.Contacts", Contact); //Throws the Exception
var detached = DataContext.ObjectStateManager.
GetObjectStateEntries(EntityState.Detached);
//InvalidArgumentException - detached entities cannot be in the obj state mgr
Answers in VB are welcomed too.
Could your Contact entity have two child entities with the same EntityKey? For example, is it possible to get from the Contact entity to two Address entities with the same key?
If you specify MergeOptions.NoTracking a context will happily return a detached object graph that contains entities with the same key. However, when you attach the same object graph a System.InvalidOperationException will be thrown.
I would suggest that you look at the entire object graph that you are attaching to the context and check if there are objects with duplicate keys in it.
Answer is (and I didn't mention that this was the problem, since I didn't know it is), that if you set a navigation property to a tracked entity the new entity is automatically added:
Dim s = context.States.FirstOrDefault()
Dim a As New Address
a.State = s
Dim state = a.EntityState '= Added
Since I didn't know that I kept on wondering how come the entity is tracked.
I would delete the entire quesion but since there is effort of other answer that might be helpful I will leave it here, vote to close if you think it should be closed.
I had experienced the same problem within my application.
I have solved the problem by using ObjectStateManager TryGetObjectStateEntry Method
In fact the EntityState property is misleading developers. Although it is displaying Detached, interesting that causing error.
Check whether you are setting the EntityKey property of Entity object. If you are setting it, Make sure you are not copying from an existing entity object.