实体框架两次插入相同的实体[重复]

Posted

技术标签:

【中文标题】实体框架两次插入相同的实体[重复]【英文标题】:Entity Framework inserts the same entity twice [duplicate] 【发布时间】:2017-12-23 09:53:19 【问题描述】:

我有以下结构,使用Database First principle 映射到Entity Framework 6

这里是源数据库:

CREATE TABLE `Foo` (
  `Guid` VARCHAR(36),
  `Name` VARCHAR(500) NOT NULL,
  `Author` VARCHAR(100) NOT NULL,
  PRIMARY KEY (`Guid`),
  UNIQUE KEY `unique_fooname` (`Name`,`Author`));

CREATE TABLE `FooVersion` (
  `Guid` VARCHAR(36),
  `Version` INT,
  `RefFooGuid` VARCHAR(36) NOT NULL,
  PRIMARY KEY (`Guid`),
  UNIQUE KEY `unique_fooversion` (`Version`,`RefFooGuid`),
  CONSTRAINT `fk_foo_version`
    FOREIGN KEY (`RefFooGuid`)  
    REFERENCES `Foo` (`Guid`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

CREATE TABLE `FooVersionPart` (
  `Name` VARCHAR(250) NOT NULL,
  `RefFooVersionGuid` VARCHAR(36) NOT NULL,
  PRIMARY KEY (`Name`, `RefFooVersionGuid`),
  INDEX `fk_fooversion_fooversionpart_idx` (`RefFooVersionGuid` ASC),
  CONSTRAINT `fk_fooversion_fooversionpart`
    FOREIGN KEY (`RefFooVersionGuid`)
    REFERENCES `FooVersion` (`Guid`)
    ON DELETE NO ACTION
    ON UPDATE NO ACTION);

在我的代码中,我正在创建一个新的 foo,如下所示:

var dbContext = new DbContext();
var newVersion = new FooVersion();

newVersion.Guid = Guid.NewGuid().ToString()
newVersion.Parts = sourceParts.Select(s => new FooVersionPart

    Name = s.Name,
    RefFooVersionGuid = newVersion.Guid
.ToList(); 

var foo = new Foo

    Author = "Me"
    Guid = Guid.NewGuid().ToString(),
    Name = "Foo"
;

dbContext.Foos.Add(foo);

foo.Versions.Add(newVersion);

dbContext.SaveChanges();

我在SaveChanges 期间收到以下错误:

键“PRIMARY”的重复条目“dim.proran.db.tmp.dataCallistHDay -9e6620f4-227d-44de-b781-5fd67”

当 EF 尝试插入其中一个 FooVersionPart 时,错误会更具体地发生(dim.proran.db.tmp.dataCallistHDay 是该部分的 Name9e6620f4-227d-44de-b781-5fd67 是该部分的 -truncated- RefFooVersionGuid )。

我绝对确定sourceParts 没有重复,也没有在数据库中。

这是生成的 SQL:

插入Foo [..];

插入FooVersion [..];

插入FooVersionPart [..];

插入FooVersionPart [..];

插入FooVersionPart [..];

插入FooVersionPart [..];

等等

异常总是发生在同一个FooVersionPart (dim.proran.db.tmp.dataCallistHDay) 上。它是 2435 的第 1910 个元素。因此 EF 不会尝试将所有部分插入两次,而只是在中间插入一个。

最奇怪的是,它在不久前就可以工作了,但它不再工作了,所有相关的东西都没有变化(架构没有变化,库没有更新,代码没有变化)。它在我的一个环境中运行良好,但在我的开发环境中无法使用相同的代码。

最后一件事,它不是特定于那个 Guid。每次尝试时,Guid 都是不同的(不是其他输入,因此在 dim.proran.db.tmp.dataCallistHDay 上仍然失败),并且每次尝试时我都会遇到相同的错误。

您知道是什么原因造成的吗?

【问题讨论】:

看不到您的代码或源数据,我们如何才能真正提供帮助? 如何向您展示我正在插入的 2435 个元素?我向您展示了与我的代码相关的内容。如果您想要更具体的元素,请询问。 你需要自己调试。看看报错,dim.proran.db.tmp.dataCallistHDay是什么?问题中没有提到该对象。 @DavidG 我没有清楚地解释错误发生在哪里。我试图在上次编辑中更清晰。 也许下一次当你有多个人建议你有重复时,不要这么快就假设你没有重复! :) 【参考方案1】:

异常消息 (Duplicate entry 'dim.proran.db.tmp.dataCallistHDay -9e6620f4-227d-44de-b781-5fd67' for key 'PRIMARY') 结合它所引用的表的主键 (PRIMARY KEY ('Name', 'RefFooVersionGuid')) 告诉我们您正在尝试向表中插入重复数据,特别是多个 FooVersionParts 具有相同的姓名。

现在您说您已经对源数据进行了重复检查,但您可能不知道有很多(全部?)SQL 数据库不将尾随空格计为记录的一部分。例如这个查询实际上会返回一条记录:

SELECT 1 
WHERE 'abc' = 'abc        '

因此,正如您所确认的,您的数据确实有重复项,C#GroupBy 不会发现这些重复项,但会被数据库引擎捕获。一个简单的解决方案是在分组之前修剪数据,这是一个很好的习惯,尤其是手动输入的数据。

【讨论】:

如你所说,被忽略尾随空格的 mysql 抓住了......

以上是关于实体框架两次插入相同的实体[重复]的主要内容,如果未能解决你的问题,请参考以下文章

实体框架:多对多插入重复

实体框架无法在对象中插入重复键

具有实体框架 6 的 ObjectContext 在现有相关实体上插入重复项

实体框架在播种数据库上插入重复项[重复]

具有过滤索引的实体框架 - “无法在对象中插入重复的键行”

EF Core 过滤掉多对多关系中的重复实体