使用DbContext和Entity Framework避免并发问题

时间:2013-06-20 19:54:43

标签: .net entity-framework thread-safety

我正在构建一个ASP Web API项目,使用SQL Server进行存储,并使用Entity Framework连接到它。

存储中的多个表包含唯一约束,以强制其中值的唯一性。在向这些表添加值之前,我的应用程序会检查以确保这些值不存在。

构建应用程序,以便每个请求都存在一个DbContext。但是,我发现两个请求可能会尝试将相同的值插入表中。请求A将检查表中是否存在值,请求B也是如此。两者都确定该值需要添加,并将其添加到DbSet。调用SaveChanges时,一个请求将成功,一个请求将因为唯一约束失败而失败。

如何使用Entity Framework解决这些问题?我打算创建存储过程来检索或创建值,我认为应该解决它(保证原子性的存储过程),但我更愿意只用Entity Framework本身来解决这个问题。我想我喜欢排队一些只在调用DbContext.SaveChanges()时执行的操作,但显然存储过程解决方案意味着数据库交互将在SaveChanges()之前发生。

1 个答案:

答案 0 :(得分:2)

此问题并非特定于Entity Framework(尽管EF当然也有围绕UNIQUE约束的其他限制)。这在任何类似的服务器 - 客户端模型中都很常见。由于数据库服务器在请求时将强制执行唯一性,因此在您尝试插入之前,没有任何万无一失的方法可以提前知道是否违反约束。

也就是说,提前检查唯一性应该是一个非常便宜的操作(在SQL Server上,UNIQUE约束也会为你提供该列的索引),所以取决于你期望应用程序尝试重复插入的频率,这应该涵盖你的绝大部分案件。但是,如果重复的插入尝试开始时很少,则可以避免为每个插入进行额外的往返,并在发生时处理异常。

处理异常不需要非常复杂,特别是如果最终用户有办法修改数据并尝试重试。如上所述,您在单个事务中排队几个插入,您可能需要检查特定约束名称的异常(或内部异常),以便您知道哪个实体对象是重复的。 (同样,EF并不真正支持直接处理UNIQUE约束异常,所以这可能是你现在最痛苦的部分。)

注意:我不建议将插件重新用作存储过程,以避免同时尝试重复条目的罕见机会。你最好确保你的应用程序尽可能优雅地处理这个(和其他SQL异常,其中可能有很多)。但是,如果您发现在您的情况下实际上没有其他方法,那么现在最简单的方法是使用sproc。请记住,为了解决一个非常罕见的边缘情况,它可能会提供更易于维护的代码。