【发布时间】:2014-07-16 05:48:23
【问题描述】:
我正在尝试处理对我的实体框架应用程序的近乎同时的输入。成员(用户)可以对事物进行评分,所以我有一个他们的评分表,其中一列是成员的 ID,一列是他们正在评分的事物的 ID,一是评分,另一列是他们评分的时间.最近的评级应该覆盖早期的评级。当我收到输入时,我会检查成员是否已经对某事物进行了评分,如果有,我只需使用现有行更新评分,如果没有,我添加一个新行。我注意到,当同一用户几乎同时对同一项目进行输入时,我最终会为该用户对同一事物的两个评分。
之前我问过这个问题:How can I avoid duplicate rows from near-simultaneous SQL adds?,然后我按照建议添加了一个需要 MemberID 和 ThingID 的唯一组合的 SQL 约束,这是有道理的,但我无法让这种技术发挥作用,可能是因为我没有不知道发生异常时执行我想做的事情的语法。出现异常说违反了约束,然后我想做的是忘记尝试非法添加具有相同 MemberID 和 ThingID 的行,而是获取现有的并简单地将值设置为这个稍微更新数据。但是我还没有想出一个可以做到这一点的语法。我已经尝试了一些事情,但当我在收到异常后尝试 SaveChanges 时总是遇到异常 - 唯一约束仍在出现,或者我遇到死锁异常。
我试过的最新版本是这样的:
// Get the member's rating for the thing, or create it.
Member_Thing_Rating memPref = (from mip in _myEntities.Member_Thing_Rating
where mip.thingID == thingId
where mip.MemberID == memberId
select mip).FirstOrDefault();
bool RetryGet = false;
if (memPref == null)
{
using (TransactionScope txScope = new TransactionScope())
{
try
{
memPref = new Member_Thing_Rating();
memPref.MemberID = memberId;
memPref.thingID = thingId;
memPref.EffectiveDate = DateTime.Now;
_myEntities.Member_Thing_Rating.AddObject(memPref);
_myEntities.SaveChanges();
}
catch (Exception ex)
{
Thread.Sleep(750);
RetryGet = true;
}
}
if (RetryGet == true)
{
Member_Thing_Rating memPref = (from mip in _myEntities.Member_Thing_Rating
where mip.thingID == thingId
where mip.MemberID == memberId
select mip).FirstOrDefault();
}
}
写完以上内容后,我还尝试将逻辑包装在函数调用中,因为似乎 Entity Framework 在离开提交更改的范围时会清理数据库事务。因此,我没有使用 TransactionScope 并在与上述相同的级别管理异常,而是将整个事情包装在一个管理函数中,如下所示:
bool Succeeded = false;
while (Succeeded == false)
{
Thread.Sleep(750);
Exception Problem = AttemptToSaveMemberIngredientPreference(memberId, ingredientId, rating);
if (Problem == null)
Succeeded = true;
else
{
Exception BaseEx = Problem.GetBaseException();
}
}
但这只会导致唯一约束上的无休止的异常字符串,在更高级别的函数中永久处理。我在尝试之间有 3/4 秒的延迟,所以我很惊讶可能会报告冲突,但当我查询一行时仍然没有找到任何东西。我想这表明所有线程都失败了,因为它们同时运行并且实体框架注意到它们并且在任何成功之前都使它们失败。所以我想应该有办法通过查看所有提交并调整它们来响应异常?我不知道或看到它的语法。那么再次,有什么办法来处理呢?
更新: Paddy 在下面提出了三个很好的建议。我希望他的存储过程技术可以解决这个问题,但我仍然对这个问题的答案感兴趣。也就是说,当然应该能够通过操纵提交来响应这个异常,但是我还没有找到让它插入一行并使用最新值的语法。
【问题讨论】:
标签: sql-server entity-framework exception-handling unique-constraint