views:

48

answers:

1

Hi

I'm using self-tracking entities in a WCF client-server application. My WCF service returns various entities, and these can be updated using corresponding Update methods.

This worked well for a while, but now I'm having problems. To keep the focus, I'l limit this discussion to a specific case, simplified to the bare essentials.

One of my tables is called SystemDefinition. It has no foreign keys, but one other table (Route) has a foreign key to it. Consequently, it has a single navigation property in the entity model (called Routes). All the other columns are scalars. The table, and the corresponding entities, has a primary key column called Id, of type Guid. The database is SQL Server Compact v3.5.

To reproduce the problem, I can:

  1. Retrieve a single SystemDefinition entity using my WCF service's GetSystem() method
  2. In the client, call MarkAsDeleted() on the entity
  3. Call UpdateSystem(), passing the entity as the parameter

The code in UpdateSystem() is simply (non-essential code deleted for clarity):

_objectContext.SystemDefinitions.ApplyChanges(system);
_objectContext.SaveChanges();

The entity is retrieved with no Include() clause, which means the Routes collection is empty (and anyway, the error still occurs if there are no rows in Route with foreign keys to the SystemDefinition). So the SystemDefinition entity I pass to the Update method is the only entity in the graph. Yet I still get the following exception:

InvalidOperationException: AcceptChanges cannot continue because the object's key values conflict with another object in the ObjectStateManager. Make sure that the key values are unique before calling AcceptChanges.

The exception is thrown by the first method call (ApplyChanges). I am certain the ObjectContext is fresh, a new one created for each method call.

I have debugged the code all the way down to where it throws (in ObjectContext.FixupKey()), but the code makes little sense to me, and there are no comments in Microsoft's source code to indicate what the condition that causes it actually means.

Certainly, the message is misleading? There's just a single entity involved in the update. What might be going on?

PS. I found a forum post suggesting that overriding the GetHashCode() and Equals() methods on the entity classes might help. This would make some sense if the error was caused by the ObjectStateManager not being able to determine that the entity to update is in fact the same as some entity in the context. I tried it out (using partial classes), but ufortunately it didn't help. So now I'm lost. Any suggestions would be welcome.

A: 

I suspect that your _objectContext already contains the entity instances that you try to apply changes from. Since your entities are received from an external client, they will never be the same (in terms of instance reference) to those instances the context already knows about.

This makes sense with the exception thrown: the context ends up with two different instances containing the same key values.

To solve this you would simply make sure that you always work with a fresh context.

Peter Lillevold
That's entirely right. I injected a single object context into the WCF service constructor, thinking it was instantiated per-call. Turns out the service instance is reused, and so the object context was stale. I rewrote the service to take a factory instead, and that solved it. Thanks.
Tor Haugen