【发布时间】:2011-04-23 04:05:04
【问题描述】:
使用 LINQ-to-Entities 4.0,是否有正确的模式或构造来安全地实现“如果不存在则插入”?
例如,我目前有一个跟踪“用户收藏”的表格 - 用户可以在他们的收藏列表中添加或删除文章。
基础表不是真正的多对多关系,而是跟踪一些附加信息,例如添加收藏夹的日期。
CREATE TABLE UserFavorite
(
FavoriteId int not null identity(1,1) primary key,
UserId int not null,
ArticleId int not null
);
CREATE UNIQUE INDEX IX_UserFavorite_1 ON UserFavorite (UserId, ArticleId);
根据需要插入具有相同用户/文章对的两个收藏夹会导致重复键错误。
我目前已经使用 C# 在数据层实现了“如果不存在则插入”逻辑:
if (!entities.FavoriteArticles.Any(
f => f.UserId == userId &&
f.ArticleId == articleId))
{
FavoriteArticle favorite = new FavoriteArticle();
favorite.UserId = userId;
favorite.ArticleId = articleId;
favorite.DateAdded = DateTime.Now;
Entities.AddToFavoriteArticles(favorite);
Entities.SaveChanges();
}
这个实现的问题是它容易受到竞争条件的影响。例如,如果用户双击“添加到收藏夹”链接,则可以向服务器发送两个请求。第一个请求成功,而第二个请求(用户看到的那个)失败,并出现 UpdateException 包装了重复键错误的 SqlException。
通过 T-SQL 存储过程,我可以使用带有锁定提示的事务来确保永远不会发生竞争条件。是否有一种干净的方法可以避免实体框架中的竞争条件,而无需求助于存储过程或盲目地吞下异常?
【问题讨论】:
-
你看过
using (var tran = new TransactionScope())吗? -
^ 将代码包装在 TransactionScope 中不起作用。 @ShadowChaser 你有没有找到解决这个问题的方法?
标签: entity-framework linq-to-entities insert