实体框架 - 更新异常

3
我刚刚注意到,当使用Entity Framework更新数据时发生SqlException,由于引起异常的实体仍在“队列”中等待保存,因此所有后续调用SaveChanges都将失败。
这在我们的现场系统上给许多用户带来了很大的困扰,因为一些更新操作失败并显示错误信息“string or binary data would be truncated”,导致他们无法保存数据。我们不得不采取重新启动应用程序池的措施。
我该如何删除/重置有问题的对象并让其他更新操作继续进行?
更好的方法是,在插入/更新期间发生Sql异常时,最佳处理方法是什么?
2个回答

4
EF的第一个基本规则是ObjectContext是工作单元,因此您必须以这种方式处理它。如果您在用户之间共享上下文,则犯了如此大的错误,应立即关闭应用程序,并且不要让用户使用它,除非您进行修复。我曾经写过一个答案,其中描述了上下文实现的两种模式——工作单元和标识映射。如果您在并发用户之间共享上下文,则使每个操作的结果不确定。您不能确定用户是否拥有新鲜/提交的数据,也不能确定您是否在单个事务中保存了用户修改的所有内容。

现在上下文在内部使用事务。每个SaveChanges都会将所有修改的记录(来自所有并发用户,如果您共享上下文)保存在事务中。单个错误导致整个事务回滚。一旦您开始使用逻辑操作(请求或Web应用程序中的操作)的上下文,您就可以向用户显示数据并让他进行修改,或者您可以简单地重试(如果出现锁定问题)。当然,这并不能解决没有验证用户输入的问题,因为那是应该修复的应用程序漏洞。如果您没有验证,则无法向用户显示数据的错误之处。


所以基本上,每个CRUD操作都需要创建一个新的ObjectContext吗? - Alfero Chingono
如果您使用Web应用程序,可以为每个请求创建单个上下文,并且如果它们是单个逻辑事务的一部分,则可以在该请求中进行多个CRUD操作 - 您还可以多次调用SaveChanges,因此您可以在单个逻辑事务中使用多个数据库事务。 - Ladislav Mrnka
哇!我真的错了...我读了你的答案,一切都变得更清晰了。谢谢! - Alfero Chingono

1

您可以通过使用工作单元模式来保护自己免受这种情况的影响。

在这种情况下,每个来自不同用户的更新都将使用自己的上下文...因此,如果其中一个存在错误,则不会影响其他用户。

请参考:

在Entity Framework 4.0中使用存储库和工作单元模式

工作单元还将帮助您了解如何从错误中恢复。

由于单个工作单元本质上是单个事务,因此您可以简单地回滚事务并通知用户(并允许他们修改数据并重试)。


谢谢Justin...我想问题变成了,“我该如何回滚?” - Alfero Chingono
@deverop - 如果您正在使用单个上下文,则SaveChanges()将自动为您回滚事务。如果您在单个工作单元中使用多个上下文,则需要查看TransactionScope。 - Justin Niessner
感谢您的耐心等待...我正在使用单个上下文(因为我认为/读到这可以提高性能),但不幸的是它确实会回滚事务(在数据库中),但实体仍处于“挂起”状态,因此对SaveChanges的任何其他调用都将被阻塞。 - Alfero Chingono

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接