【问题标题】:Entity Framework inserting entity twice in two different contexts实体框架在两个不同的上下文中插入实体两次
【发布时间】:2018-12-13 04:48:55
【问题描述】:

我正在使用 Entity Framework Core 将对象图存储在数据库中。在构建图形的不同时间,我创建一个实体,将其存储到数据库中,然后释放上下文。但是,我遇到了一个问题,即 EFC 试图插入一个在连接到新实体时已经插入的实体。这最好用代码来解释。这是一段简短的重现代码(这是直线代码,但上下文的两种使用发生在代码中的不同时间和位置)。

在第二次调用context.SaveChanges() 时,我得到以下异常:

SqlException:

当 IDENTITY_INSERT 设置为 OFF 时,无法为表“命名空间”中的标识列插入显式值。

当我查看正在执行的 SQL 时,它正在尝试再次插入命名空间实体,可能是因为 myType 正在保存到数据库中并且它引用了 dbNamespace 实体。

// see if namespace is in the db and add it if not
string someNamespaceString = "foobar";
CodeDatabase.Models.Namespace dbNamespace;
using (var context = new CodeFactsContext())
{
    dbNamespace = context.Namespace.FirstOrDefault(ns => ns.Namespace1 == someNamespaceString);
    if (dbNamespace == null)
    {
        dbNamespace = new Namespace() { Namespace1 = someNamespaceString };
        context.Namespace.Add(dbNamespace);
    }
    context.SaveChanges();
}

// Type entity created somewhere from the code
var myType = new CodeDatabase.Models.Type()
{
    FullName = "foobar.mytype",
    ShortName = "mytype",
    Namespace = dbNamespace // this is already in the DB
};

// check if myType is in the db and add it if not
using (var context = new CodeFactsContext())
{
    var dbType = context.Type.FirstOrDefault(t => t.FullName == myType.FullName);
    if (dbType == null)
    {
        dbType = myType;
        context.Add(dbType);
    }
    context.SaveChanges(); // throws exception
}

知道如何让 EF Core 识别(在第二个 context.SaveChanges() 中)myType 应该插入到数据库中,但 myType.Namespace 不应该因为它已经存在?这两个实体都有一个由 DB 自动生成的 int id,并且 Namespace 的 id 在第一次调用 SaveChanges 后设置为数据库值。我认为 EF Core 会识别出 id 不是 0 并且不会尝试保存它。非常欢迎任何帮助/建议。

【问题讨论】:

  • 这只是意味着你的命名空间表有一个标识列。像PRIMARY KEY IDENTITY (1, 1) 这样的东西,你的保存正在尝试写入 SQL 服务器不喜欢的列。
  • 我明白这就是它的意思。我在问如何让 EFC 理解它不应该再次编写它,因为实体已经添加到数据库中。
  • 不。我认为您仍然误解了它的含义。这意味着您永远不应该写入该列(除非您尝试使用身份复制数据),而不是您不应该再次写入。
  • 好的。我想我是误会了。我并没有明确地尝试写入该专栏。我正在创建命名空间实体,并且在第一次调用 context.SaveChanges() 时,它成功保存了命名空间实体。然后第二个 SaveChanges()(它正在尝试写入 Type 实体)是发生故障的地方。我不是想写那个专栏,我不确定我在做什么让 EFC 尝试写那个专栏。
  • 我觉得你应该看看stackoverflow.com/questions/25441027/…

标签: c# entity-framework entity-framework-core


【解决方案1】:

我以为 EFC 会识别出 id 不为 0 而不会尝试保存它。

问题是您正在使用Add 方法,该方法将所有可访问且未跟踪的实体标记为新实体,而不管键值如何(这是为了允许身份插入场景)。这在Disconnected Entities - Working with graphs - All new/all existing entities 中有解释。而您的脚本属于Mix of new and existing entities

知道如何让 EFC 识别(在第二个 context.SaveChanges 中)myType 应该插入数据库,但 myType.Namespace 不应该因为它已经存在?这两个实体都有一个由 DB 自动生成的 int id,并且 Namespace 的 id 在第一次调用 SaveChanges 后设置为数据库值。

实际上在第二个文档链接中解释了一个简单的解决方案:

使用自动生成的键,Update 可以再次用于插入和更新,即使图表包含需要插入和需要更新的实体的混合

“再次”指的是Saving single entities

Update 方法通常将实体标记为更新,而不是插入。但是,如果实体有一个自动生成的键,并且没有设置键值,那么该实体会被自动标记为插入。

幸运的是,您的实体使用自动生成的密钥,因此只需使用 Update 而不是 Add

if (dbType == null)
{
    dbType = myType;
    context.Update(dbType); // <--
}

【讨论】:

    猜你喜欢
    • 2017-12-23
    • 1970-01-01
    • 2022-01-20
    • 2012-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多