Estou usando EF Core (dentro do ASP.NET Core e minhas DbContext
vidas por solicitação / escopo).
Minha Employee
entidade possui esta propriedade:
public bool? IsBoss { get; set; }
e esta configuração:
entityBuilder.Property(b => b.IsBoss).IsRequired(false);
entityBuilder.HasIndex(b => b.IsBoss).IsUnique();
Isso cria um índice filtrado, portanto, pode haver apenas um verdadeiro, um falso, mas muitos nulos.
Meu aplicativo exige que eu sempre tenha exatamente um funcionário com IsBoss==true
.
Suponha que eu queira trocar dois funcionários.
employee1.IsBoss = null;
employee2.IsBoss = true;
context.SaveChanges();
Isso lança uma exceção de violação de restrição exclusiva.
Posso consertar isso envolvendo-o em uma transação:
using (var transaction = context.BeginTransaction())
{
try
{
employee1.IsBoss = null;
context.SaveChanges();
employee2.IsBoss = true;
context.SaveChanges();
transaction.Commit();
}
catch
{
transaction.Rollback();
}
}
Minha pergunta é: por que a primeira abordagem falha? Achei que o EF Core automaticamente envolve tudo em uma transação. Por que devo usar uma transação?
A primeira abordagem falha devido a um motivo diferente do das transações. Rastreamento de problema no repositório EF que cobre o mesmo cenário que o seu.
Quando SaveChanges
é chamado, o EF processa as alterações e calcula os comandos a serem enviados ao banco de dados. Este conjunto de comandos pode ter dependência. Como no seu caso, você precisa definir o valor null
para employee1
antes de definir o valor true
para employee2
. EF faz a classificação dos comandos para descobrir a ordem em que eles precisam ser executados. EF fez essa classificação com base nas restrições de chave estrangeira. Mas, como esse problema relatou, não contabilizamos o índice exclusivo, portanto os comandos estavam sendo enviados na ordem errada, causando violação de restrição exclusiva.
O problema já foi corrigido na base de código atual. Ele estará disponível no próximo lançamento público. Enquanto isso, como uma solução alternativa, você precisa chamar SaveChanges
duas vezes, como está fazendo no segundo código. Chamando SaveChanges
várias vezes, você pode controlar a ordem dos comandos enviados ao banco de dados. Você não precisa envolvê-lo em uma transação, a menos que queira que ambas as alterações sejam uma operação atômica. Cada um SaveChanges
tem sua própria transação, a menos que o usuário inicie uma.
Este artigo é coletado da Internet.
Se houver alguma infração, entre em [email protected] Delete.
deixe-me dizer algumas palavras