entity-framework – 使用Entity Framework实现if-not-exists-insert,而不会有竞争条件

前端之家收集整理的这篇文章主要介绍了entity-framework – 使用Entity Framework实现if-not-exists-insert,而不会有竞争条件前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
使用LINQ-to-Entities 4.0,是否有正确的模式或构造来安全地实现“如果不存在然后插入”?

例如,我目前有一个跟踪“用户收藏夹”的表格 – 用户可以从他们的收藏夹列表中添加删除文章.

基础表不是真正的多对多关系,而是跟踪一些其他信息,如添加日期.

  1. CREATE TABLE UserFavorite
  2. (
  3. FavoriteId int not null identity(1,1) primary key,UserId int not null,ArticleId int not null
  4. );
  5.  
  6. CREATE UNIQUE INDEX IX_UserFavorite_1 ON UserFavorite (UserId,ArticleId);

根据需要,使用相同的用户/文章对插入两个收藏夹会导致重复的键错误.

我现在使用C#在数据层中实现了“if not exists then insert”逻辑,

  1. if (!entities.FavoriteArticles.Any(
  2. f => f.UserId == userId &&
  3. f.ArticleId == articleId))
  4. {
  5. FavoriteArticle favorite = new FavoriteArticle();
  6. favorite.UserId = userId;
  7. favorite.ArticleId = articleId;
  8. favorite.DateAdded = DateTime.Now;
  9.  
  10. Entities.AddToFavoriteArticles(favorite);
  11. Entities.SaveChanges();
  12. }

这种实现的问题是它容易受到种族条件的影响.例如,如果用户双击“添加到收藏夹”链接,则可以将两个请求发送到服务器.第一个请求成功,而第二个请求(用户看到的那个)失败,并且UpdateException将包含重复键错误sqlException.

使用T-sql存储过程,我可以使用具有锁提示的事务来确保不会发生竞争条件.有没有干净的方法来避免实体框架中的竞争状况,而不诉诸于存储过程或盲目吞咽异常?

解决方法

您可以尝试将其与“着名”try / catch模式结合在一起的事务中:
  1. using (var scope = new TransactionScope())
  2. try
  3. {
  4. //...do your thing...
  5. scope.Complete();
  6. }
  7. catch (UpdateException ex)
  8. {
  9. // here the second request ends up...
  10. }

猜你在找的MsSQL相关文章