【问题标题】:EF Core Postgres DbUpdateConcurrencyException when updating detached data更新分离数据时 EF Core Postgres DbUpdateConcurrencyException
【发布时间】:2020-07-03 05:06:58
【问题描述】:

我正在尝试在 MSTest 单元测试中更新我的 Postgres 数据库中的数据。在每次测试之前,我都会删除所有书籍并创建一些新书籍以确保测试数据正确:

        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);
            }
        }

我分三步完成。首先我得到一个实体。然后我改变它,而它与上下文分离。最后,我将这本书附加到一个新的上下文中,并将状态设置为已修改并尝试保存更改。但是我得到一个带有消息的 DbUpdateConcurrencyException:

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

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

我该如何解决这个问题?

【问题讨论】:

    标签: c# postgresql .net-core entity-framework-core npgsql


    【解决方案1】:

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

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

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

    【解决方案2】:

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

    您是否检查过您的 Provider / EF Core / .NET Core 版本? https://github.com/npgsql/efcore.pg/issues/1059

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

    或者,也许可以选择更改数据库供应商?

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-05-03
      • 2019-03-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多