更新自我跟踪实体时遇到问题
我在 WCF 客户端-服务器应用程序中使用自我跟踪实体。我的 WCF 服务返回各种实体,并且可以使用相应的 Update 方法来更新这些实体。
这在一段时间内运作良好,但现在我遇到了问题。为了保持重点,我将把讨论限制在一个特定的案例中,并简化为最基本的要点。
我的一张表称为 SystemDefinition。它没有外键,但另一个表(路由)有一个外键。因此,它在实体模型中具有单个导航属性(称为“路由”)。所有其他列都是标量。该表和相应的实体有一个名为 Id、类型为 Guid 的主键列。数据库是SQL Server Compact v3.5。
要重现该问题,我可以:
- 使用 WCF 服务的 GetSystem() 方法检索单个 SystemDefinition 实体
- 在客户端中,对实体调用 MarkAsDeleted()
- 调用 UpdateSystem(),将该实体作为参数传递
UpdateSystem() 中的代码是简单地(为了清楚起见,删除了非必要代码):
_objectContext.SystemDefinitions.ApplyChanges(system);
_objectContext.SaveChanges();
检索实体时不使用 Include() 子句,这意味着 Routes 集合为空(无论如何,如果 Route 中没有包含 SystemDefinition 外键的行,错误仍然会发生) )。因此,我传递给 Update 方法的 SystemDefinition 实体是图中唯一的实体。但我仍然遇到以下异常:
无效操作异常: AcceptChanges 无法继续,因为 对象的键值冲突 中的另一个对象 对象状态管理器。确保 调用前键值是唯一的 接受更改。
异常是由第一个方法调用 (ApplyChanges) 引发的。我确信 ObjectContext 是新鲜的,是为每个方法调用创建的一个新的。
我已经将代码一直调试到它抛出的位置(在 ObjectContext.FixupKey() 中),但是代码对我来说没有什么意义,并且 Microsoft 的源代码中没有注释来指示导致它的条件的实际含义。 。
当然,该消息具有误导性?更新只涉及一个实体。可能发生了什么?
附言。我发现一个论坛帖子建议重写实体类上的 GetHashCode() 和 Equals() 方法可能会有所帮助。如果错误是由于 ObjectStateManager 无法确定要更新的实体实际上与上下文中的某些实体相同而引起的,那么这将有意义。我尝试了一下(使用部分类),但不幸的是它没有帮助。所以现在我迷路了。任何建议都将受到欢迎。
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:
- Retrieve a single SystemDefinition entity using my WCF service's GetSystem() method
- In the client, call MarkAsDeleted() on the entity
- 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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我怀疑您的
_objectContext
已包含您尝试应用更改的实体实例。由于您的实体是从外部客户端接收的,因此它们永远不会与上下文已经知道的那些实例相同(就实例引用而言)。这对于抛出的异常是有意义的:上下文最终有两个包含相同键值的不同实例。
要解决这个问题,您只需确保始终在新的环境中工作即可。
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.