Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Entity framework 在不存在竞争条件的情况下使用实体框架实现if-not-exists insert_Entity Framework_Linq To Entities_Insert - Fatal编程技术网

Entity framework 在不存在竞争条件的情况下使用实体框架实现if-not-exists insert

Entity framework 在不存在竞争条件的情况下使用实体框架实现if-not-exists insert,entity-framework,linq-to-entities,insert,Entity Framework,Linq To Entities,Insert,使用LINQ to Entities 4.0,是否有正确的模式或结构来安全地实现“如果不存在,则插入” 例如,我目前有一个跟踪“用户收藏夹”的表,用户可以从收藏夹列表中添加或删除文章 基础表不是真正的多对多关系,而是跟踪一些附加信息,例如添加收藏夹的日期 CREATE TABLE UserFavorite ( FavoriteId int not null identity(1,1) primary key, UserId int not null, ArticleId

使用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 not exists then insert”逻辑:

这个实现的问题是它容易受到竞争条件的影响。例如,如果用户双击“添加到收藏夹”链接,则可以向服务器发送两个请求。第一个请求成功,而第二个请求(用户看到的请求)失败,UpdateException为重复密钥错误包装了SqlException


对于T-SQL存储过程,我可以使用带有锁提示的事务来确保竞争条件永远不会发生。是否有一种干净的方法可以避免实体框架中的竞争条件,而不必求助于存储过程或盲目地接受异常

您可以尝试将其包装在与“著名”的try/catch模式相结合的事务中:

using (var scope = new TransactionScope())
try
{
//...do your thing...
scope.Complete();
}
catch (UpdateException ex)
{
// here the second request ends up...
}

您还可以编写一个使用sql 2005中的一些新技巧的存储过程+

在update语句中使用您组合的唯一ID(userID+articleID),然后使用@RowCount函数查看行数是否大于0如果是1(或更多),则更新已找到与您的userID和articleID匹配的行,如果是0,则可以插入

e、 g

更新tablex set userID=@userID,ArticleID=@ArticleID(这里可以有更多属性,只要where包含一个组合的唯一ID),其中userID=@userID和ArticleID=@ArticleID

如果(@@RowCount=0) 开始 插入到表格中。。。 结束


最棒的是,这一切都是在一次调用中完成的,因此您不必首先比较数据,然后确定是否应该插入。当然,它会停止任何重复的插入,不会抛出任何错误(优雅地?

您是否看过使用(var tran=new TransactionScope())的
?^在TransactionScope中包装代码不起作用@ShadowChaser你能找到解决方案吗?我不知道使用显式事务能让你得到什么。据我所知,无论是否有事务,行为都将完全相同。您能给我解释一下吗?这显然比在存储过程中使用合并效率要低,但如果事务类型设置正确,这似乎是EF中的最佳选择。我们最近刚刚为一个比我原来的问题更复杂的项目使用了一个类似的解决方案——一个必须处理合并冲突的完整保存命令。我也看不到封闭的TransactionScope添加了什么。如果存在竞态条件,您将得到一个UpdateException,不是吗?这仍然会导致竞态条件。假设您尝试更新,但没有任何更新。当您选中
@@RowCount
并实际执行插入时,可能已经插入了另一行。如果您有唯一的约束,这将抛出一个错误,否则您有重复的数据。@@RowCount将只从上一条语句中获取受影响的行。它对当前上下文中的最后一条语句有效,其他用户会话对此没有影响。
using (var scope = new TransactionScope())
try
{
//...do your thing...
scope.Complete();
}
catch (UpdateException ex)
{
// here the second request ends up...
}