You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

EF6迁移EF Core添加含子实体对象时报重复键错误求助

EF Core 2.2 迁移:Add() 时复合主键重复异常的解决方案

我明白你在从EF6迁移到EF Core时遇到的这个痛点——EF6的自动关系修复确实帮我们掩盖了不少外键设置的小失误,但EF Core的状态跟踪机制更严格,这既是优势也是需要适应的地方。

问题根源

EF6会在调用Add()后自动修复父子实体的外键关系,哪怕你给子实体设置了错误的外键值;但EF Core在执行Add()时,会立即检查上下文已跟踪的所有实体主键。你的场景中,itemDetail的复合主键是(ItemGID, LineId),之前添加的item1detail1已经被上下文跟踪(主键为OneCrud_UnitTest, 1),当你给item2的子实体设置同样的ItemGID时,EF Core会认为你要添加一个已存在的实体,直接抛出重复主键异常。

解决方案

1. 手动提前修复外键值(推荐)

既然我们知道EF Core不会自动帮我们修正外键,最直接的方式就是在添加item2前,确保子实体的外键和父实体主键一致:

var item2 = new item { ItemGID = defaultPk2 };
item2.ItemID = item2.ItemGID;
item2.TS = DateTime.Now;
item2.itemDetail = new List<itemDetail>();

// 直接设置正确的外键值,和item2的ItemGID保持一致
var newDetail = new itemDetail 
{ 
    ItemGID = defaultPk2, 
    LineId = 1, 
    GUID = Guid.NewGuid().ToString() 
};
item2.itemDetail.Add(newDetail);

unitOfWork.DataContext.Set<item>().Add(item2);
unitOfWork.Commit();

这是最符合EF Core设计理念的做法,避免依赖自动修复,让代码逻辑更清晰。

2. 解除对旧实体的跟踪(特殊场景适用)

如果因为某些原因无法提前设置正确的外键,且你不再需要上下文跟踪之前的detail1,可以在添加item2前将旧实体从跟踪状态中移除:

// 找到已跟踪的旧detail实体
var trackedDetail = unitOfWork.DataContext.Set<itemDetail>().Find(defaultPk, 1);
if (trackedDetail != null)
{
    // 将其设置为无跟踪状态
    unitOfWork.DataContext.Entry(trackedDetail).State = EntityState.Detached;
}

// 现在添加item2就不会触发重复键异常,EF Core会在SaveChanges时修复外键
unitOfWork.DataContext.Set<item>().Add(item2);
unitOfWork.Commit();

注意:这种方式只适合你确定旧实体不会再被上下文操作的场景,否则可能导致状态不一致。

3. 配置关系增强自动修复能力

确保你的EF Core模型配置正确,让EF Core能更好地识别父子关系,提升自动修复的概率:
DbContextOnModelCreating方法中添加关系配置:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);

    // 配置item和itemDetail的父子关系
    modelBuilder.Entity<item>()
        .HasMany(i => i.itemDetail)
        .WithOne() // 如果itemDetail有指向item的导航属性,这里填写属性名,比如d => d.Item
        .HasForeignKey(d => d.ItemGID)
        .OnDelete(DeleteBehavior.Cascade);

    // 显式配置itemDetail的复合主键
    modelBuilder.Entity<itemDetail>()
        .HasKey(d => new { d.ItemGID, d.LineId });
}

正确的关系配置能让EF Core更准确地处理实体间的关联,减少异常发生。

总结

EF Core放弃了EF6中一些“隐式”的自动修复行为,转而强调显式的状态管理和数据正确性。优先选择手动设置正确的外键值,既能避免异常,也能让代码逻辑更易维护。

内容的提问来源于stack exchange,提问作者Gavin

火山引擎 最新活动