简体   繁体   English

在Entity Framework中使用唯一约束交换值

[英]Swapping values with unique constraint in Entity Framework

I have a unique constraint on a Navigations table's column called Index . 我对Navigations表的名为Index的列有一个唯一约束。 I have two Navigation entities and I want to swap their Index values. 我有两个Navigation实体,我想交换他们的Index值。

When I call db.SaveChanges it throws an exception indicating that a unique constraint was violated. 当我调用db.SaveChanges它会抛出一个异常,指示违反了唯一约束。 It seems EF is updating one value and then the other, thus violating the constraint. 似乎EF正在更新一个值然后另一个值,从而违反了约束。

Shouldn't it be updating them both in a transaction and then trying to commit once the values are sorted out and not in violation of the constraint? 它不应该在事务中更新它们,然后在值被整理并且不违反约束时尝试提交吗?

Is there a way around this without using temporary values? 有没有办法解决这个问题而不使用临时值?

It is not problem of EF but the problem of SQL database because update commands are executed sequentially. 这不是EF的问题,而是SQL数据库的问题,因为更新命令是按顺序执行的。 Transaction has nothing to do with this - all constrains are validated per command not per transaction. 事务与此无关 - 所有约束都是针对每个事务而不是每个事务验证的。 If you want to swap unique values you need more steps where you will use additional dummy values to avoid this situation. 如果要交换唯一值,则需要更多步骤,以便使用其他虚拟值来避免这种情况。

There are a few approaches. 有几种方法。 Some of them are covered in other answers and comments but for completeness, I will list them out here (note that this is just a list that I brainstormed and it might not be all that 'complete'). 其中一些内容包含在其他答案和评论中,但为了完整起见,我会在此列出它们(请注意,这只是我头脑风暴的列表,可能不是那么'完整')。

  1. Perform all of the updates in a single command. 在单个命令中执行所有更新。 See W0lf's answer for an example of this. 有关此示例,请参阅W0lf的答案
  2. Do two sets of updates - one to swap all of the values to the negative of the intended value and then a second to swap them from negative to positive. 做两组更新 - 一组用于将所有值交换为预期值的负数,然后用一秒钟将它们从负数转换为正数。 This is working on the assumptions that negative values are not prevented by other constraints and that they are not values that records other than those in a transient state will have. 这是假设其他约束不会阻止负值,并且它们不是除瞬态状态之外的记录所具有的值。
  3. Add an extra column - IsUpdating for example - set it to true in the first set of updates where the values are changed and then set it back to false in a second set of updates. 添加一个额外的列 - 例如IsUpdating - 在更改值的第一组更新中将其设置为true,然后在第二组更新中将其设置为false。 Swap the unique constraint for a filtered, unique index which ignores records where IsUpdating is true. 为过滤的唯一索引交换唯一约束,该索引忽略IsUpdating为true的记录。
  4. Remove the constraint and deal with duplicate values. 删除约束并处理重复值。

You could run a custom SQL Query to swap the values, like this: 您可以运行自定义SQL查询来交换值,如下所示:

update Navigation
set valuecolumn = 
        case 
            when id=1 then 'value2' 
            when id=2 then 'value1'
        end
where id in (1,2)

However, Entity Framework cannot do that, because it's outside the scope of an ORM. 但是,实体框架不能这样做,因为它超出了ORM的范围。 It just executes sequential update statements for each altered entity, like Ladislav described in his answer. 它只是为每个被更改的实体执行顺序update语句,就像Ladislav在他的回答中所描述的那样。

Another possibility would be to drop the UNIQUE constraint in your database and rely on the application to properly enforce this constraint. 另一种可能性是在数据库中删除UNIQUE约束并依赖应用程序来正确实施此约束。 In this case, the EF could save the changes just fine, but depending on your scenario, it may not be possible. 在这种情况下,EF可以很好地保存更改,但根据您的方案,可能无法实现。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM