使用事务更改 EF Core 中的唯一约束列
Changing unique constrained column in EF Core using a transaction
我正在使用 EF Core(在 ASP.NET Core 中,我的 DbContext
寿命为 request/scope)。
我的 Employee
实体有这个 属性:
public bool? IsBoss { get; set; }
和这个配置:
entityBuilder.Property(b => b.IsBoss).IsRequired(false);
entityBuilder.HasIndex(b => b.IsBoss).IsUnique();
这会创建一个过滤索引,因此只能有一个为真,一个为假,但有很多空值。
我的应用程序要求我总是只有一名员工 IsBoss==true
。
假设我想调换两个员工。
employee1.IsBoss = null;
employee2.IsBoss = true;
context.SaveChanges();
这会抛出一个违反唯一约束的异常。
我可以通过将其包装在交易中来解决这个问题:
using (var transaction = context.BeginTransaction())
{
try
{
employee1.IsBoss = null;
context.SaveChanges();
employee2.IsBoss = true;
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
我的问题是:为什么第一种方法会失败?我认为 EF Core automatically wraps 一切都在一个事务中。为什么我必须使用交易?
第一种方法由于与事务不同的原因而失败。
Tracking issue 在 EF 存储库上,它涵盖了与您相同的场景。
当调用 SaveChanges
时,EF 处理更改并计算要发送到数据库的命令。这组命令可以具有依赖性。与您的情况一样,您需要先将 employee1
的值设置为 null
,然后才能将 employee2
的值设置为 true
。 EF 对命令进行排序以找出它们需要执行的顺序。 EF 根据外键约束进行了这种排序。但正如该问题所报告的那样,我们没有考虑唯一索引,因此命令以错误的顺序发送,导致违反唯一约束。
该问题已在当前代码库中修复。它将在下一个 public 版本中提供。同时,作为一种变通方法,您需要像在第二个代码中那样调用 SaveChanges
两次。多次调用 SaveChanges
可以控制发送到数据库的命令的顺序。您不需要将其包装在一个事务中,除非您希望这两个更改都是一个原子操作。每个 SaveChanges
都有自己的事务,除非用户启动一个。
我正在使用 EF Core(在 ASP.NET Core 中,我的 DbContext
寿命为 request/scope)。
我的 Employee
实体有这个 属性:
public bool? IsBoss { get; set; }
和这个配置:
entityBuilder.Property(b => b.IsBoss).IsRequired(false);
entityBuilder.HasIndex(b => b.IsBoss).IsUnique();
这会创建一个过滤索引,因此只能有一个为真,一个为假,但有很多空值。
我的应用程序要求我总是只有一名员工 IsBoss==true
。
假设我想调换两个员工。
employee1.IsBoss = null;
employee2.IsBoss = true;
context.SaveChanges();
这会抛出一个违反唯一约束的异常。
我可以通过将其包装在交易中来解决这个问题:
using (var transaction = context.BeginTransaction())
{
try
{
employee1.IsBoss = null;
context.SaveChanges();
employee2.IsBoss = true;
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
我的问题是:为什么第一种方法会失败?我认为 EF Core automatically wraps 一切都在一个事务中。为什么我必须使用交易?
第一种方法由于与事务不同的原因而失败。 Tracking issue 在 EF 存储库上,它涵盖了与您相同的场景。
当调用 SaveChanges
时,EF 处理更改并计算要发送到数据库的命令。这组命令可以具有依赖性。与您的情况一样,您需要先将 employee1
的值设置为 null
,然后才能将 employee2
的值设置为 true
。 EF 对命令进行排序以找出它们需要执行的顺序。 EF 根据外键约束进行了这种排序。但正如该问题所报告的那样,我们没有考虑唯一索引,因此命令以错误的顺序发送,导致违反唯一约束。
该问题已在当前代码库中修复。它将在下一个 public 版本中提供。同时,作为一种变通方法,您需要像在第二个代码中那样调用 SaveChanges
两次。多次调用 SaveChanges
可以控制发送到数据库的命令的顺序。您不需要将其包装在一个事务中,除非您希望这两个更改都是一个原子操作。每个 SaveChanges
都有自己的事务,除非用户启动一个。