当前位置: 首页 > 知识库问答 >
问题:

实体框架在两个不同的上下文中插入实体两次

巫马玉堂
2023-03-14

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

在对上下文的第二次调用中。保存更改(),我得到以下异常:

SqlException:

当identity\U insert设置为OFF时,无法在表“Namespace”中为identity列插入显式值。

当我查看正在执行的SQL时,它试图再次插入名称空间实体,可能是因为myType正在保存到DB中,并且它有一个对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识别(在第二个上下文中,SaveChanges())应该将myType插入数据库,但不应该将myType插入数据库吗。命名空间不应该,因为它已经存在?这两个实体都有一个由DB自动生成的int id,并且名称空间的id设置为第一次调用SaveChanges后的数据库值。我认为EF Core会识别出id不是0,并且不会尝试保存它。欢迎提供任何帮助/建议。

共有1个答案

谢弘阔
2023-03-14

我以为EFC会识别id不是0并且不会尝试保存它。

问题是,您使用的是添加方法,该方法将所有可访问和未跟踪的实体标记为新实体,而不考虑键值(这是为了允许标识插入场景)。这在“断开连接的实体-使用图形-所有新实体/所有现有实体”中进行了解释。而您的screnario则是新实体和现有实体的混合体。

您知道如何让EFC(在第二个上下文中.SaveChanges)识别出应该将myType插入数据库,而不是myType吗。命名空间不应该,因为它已经存在?这两个实体都有一个由DB自动生成的int id,并且名称空间的id设置为第一次调用SaveChanges后的数据库值。

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

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

其中“再次”指保存单个实体:

Update方法通常将实体标记为更新,而不是插入。但是,如果实体具有自动生成的键,并且未设置键值,则该实体将自动标记为插入。

幸运的是,您的实体使用自动生成的密钥,因此只需使用更新而不是添加:

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

 类似资料:
  • 我有以下方法将播放器添加到数据库或更新它,如果它已经存在: 这个方法有时由两个不同的线程调用,因此几乎同时执行两次。有时我会得到以下异常: org . H2 . JDBC . jdbcsqlintegrityconstraintviolationexception:唯一索引或主键冲突:" PUBLIC。PUBLIC上的PRIMARY_KEY_B42。玩家(ID)值3”; 这对我来说是有意义的,因为

  • JPQl是jpa中的新成员,我想查询两个实体中的所有字段,然后使用实体类getter访问数据。 错误 异常[EclipseLink-0](Eclipse持久性服务-2.5.0.v20130507-3faac2b): org.Eclipse.Persistence.exceptions。JPQLException<br>异常描述:语法错误解析[SELECT u(),f()FROM User u jo

  • 在实体框架中,我想使用两个外键作为另一个实体类型的主键。 但是,这会给我一个缺少键的错误。 我知道我可以定义另外两个属性来保存引用实体类型的主键。Visual Studio是否不够聪明,无法自行使用它们的主键?

  • 问题内容: 我有一个简单的问题,即与“ not in” SQL等效项有关的实体框架语法。本质上,我想将以下SQL语法转换为Entity Framework语法: 这是我用于查找单个记录的方法: 这是我要用于此的伪方法: 谁能给我指点一下条款区域的内容吗?我阅读了一些有关此的论坛,并提到了使用或的情况,但是没有一个例子非常合适。 问题答案: 快去… 这些将大致变成以下数据库查询: 或者 分别。

  • 本文向大家介绍实现两个文本框同时输入的实例,包括了实现两个文本框同时输入的实例的使用技巧和注意事项,需要的朋友参考一下 实例如下所示: 以上这篇实现两个文本框同时输入的实例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持呐喊教程。

  • 实体框架5.0首先使用现有数据库编写代码。使用电动工具对类进行逆向工程。一切都很好。数据库有两个表。一个父母和一个孩子的外键返回到父母ID。ID都是带有自动增量的int。我添加了许多父母记录,现在想将孩子记录添加到特定的父母。我能看到的唯一方法是通过在父母表中搜索名称或其他属性并返回ID来找到适当的父母ID。然后在添加孩子时在外键属性中使用该ID。我不想设置新父母,所以这是将孩子添加到现有父母的唯