EF Core Postgres DbUpdateConcurrentException当更新分离的数据时



我正试图在MSTest单元测试中更新Postgresdatabase上的数据。在每次测试之前,我删除所有的书,并创建一些新的书,以确保测试的正确数据:

private static Book CreateDefaultBook(int i)
{
return new Book
{
Title = TitlePrefix + i,
Description = DescriptionPrefix + i
};
}
[TestInitialize]
public void InitializeContext()
{
using (var context = new MampfContext(DbContextOptions))
{
foreach (var contextBook in context.Books)
{
context.Entry(contextBook).State = EntityState.Deleted;
}
context.SaveChanges();
for (int i = 1; i <= NumberOfBooks; i++)
{
context.Books.Add(CreateDefaultBook(i));
}
context.SaveChanges();
}
}

这很好用。然后我尝试在测试中更新数据:

[TestMethod]
public void UpdateBookTest()
{
Book book = null;
using (var context = new MampfContext(DbContextOptions))
{
book = context.Books.FirstOrDefault(r => r.Title == TitlePrefix + 1);
Assert.IsNotNull(book);
}
book.Description = "Changed";
using (var context = new MampfContext(DbContextOptions))
{
var entry = context.Entry(book);
entry.State = EntityState.Modified;
context.SaveChanges(); //Exception!
}
using (var context = new MampfContext(DbContextOptions))
{
var updatedBook = context.Books.FirstOrDefault(r => r.Title == TitlePrefix + 1);
Assert.IsNotNull(updatedBook);
Assert.AreEqual("Changed", updatedBook.Description);
}
}

我分三步来做。首先我得到一个实体。然后我改变它,同时它脱离上下文。最后,我将这本书附加到一个新的上下文中,并将状态设置为已修改,并尝试保存更改。但在那里我得到了一个DbUpdateConcurrentException,消息是:

"数据库操作预计会影响1行,但实际影响了0行。自加载实体以来,数据可能已被修改或删除。请参阅http://go.microsoft.com/fwlink/?LinkId=527962有关理解和处理乐观并发异常的信息。">

我在我的Book实体上使用postgres在OnModelCreating中调用UseXminAsConcurrentToken((提供的乐观并发,如他们网站上所述https://www.npgsql.org/efcore/modeling/concurrency.html

如何解决此问题?

当你调用UseXminAsConcurrencyToken时,这会在你的实体上设置一个xmin属性,它将保存PostgreSQL中xmin列的值(这是自动生成的等(。由于你实际的Book CLR类型没有xmin成员,所以会配置一个shadow属性;这意味着列的值存储在上下文中,而不是CLR实例上。

因此,当您将加载的CLR实例从一个上下文移动到另一个上下文时,该值将丢失,因为它存储在上下文中。因此,当您尝试在新上下文中更新它时,值默认为0(这是不正确的(,您就会得到异常。

要解决此问题,您可以:1.只需在Book类上定义一个uint类型的xmin属性。这将导致使用它而不是影子属性,因此它将在实例之间持久存在。2.在新上下文中重新加载实体,以便重新加载值。

这可能是Npgsql提供程序中的实现问题。

您是否检查了您的提供商/EF核心/。NET核心版本?https://github.com/npgsql/efcore.pg/issues/1059

如果你没有用krisztiankocsis和roji的提示运行它,你需要开始跟踪数据库中的所有查询,并比较SQL语句和EF Core模型状态。

或者,更改数据库供应商可能是一种选择?

顺便说一句,这篇旧帖子可能会给你更多提示:https://github.com/npgsql/efcore.pg/issues/19

最新更新