You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 6实现多对多关系时主键重复录入问题解决

EF Core 6多对多关联创建餐品时重复主键错误解决

我是一名初级.NET开发者。

TLDR
内部异常:MySqlException: 键'Tags.PRIMARY'存在重复条目'vegan'
问题:CreateMealAsync方法尝试从meal.Tags创建新标签,但这些标签已存在于数据库中导致错误,需修改行为,仅更新MealTag关联表并正确创建带标签的餐品。

场景说明

我遇到了餐品与标签的多对多关联场景:一个Meal可关联多个Tag,一个Tag可关联多个Meal。使用EF Core 6通过以下两个简化类生成数据库:

public class Meal
{
   [Key]
   public Guid Id { get; set; }
   public ICollection<Tag>? Tags { get; set; }
}

public class Tag
{
    [Key]
    public string? TagName { get; set; }
    public ICollection<Meal>? Meals { get; set; }
}

EF Core 6自动处理了多对多关系的所有细节,比如关联表MealTag等。上下文配置如下:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Meal>()
        .HasMany(m => m.Tags)
        .WithMany(t => t.Meals);

    modelBuilder
        .Entity<Tag>()
        .HasMany(t => t.Meals)
        .WithMany(m => m.Tags);
}

错误发生场景

在MealService中调用SaveChangesAsync创建新餐品时,收到“重复条目”错误:

public async Task<bool> CreateMealAsync(Meal meal)
{
    try
    {
        await _context.Meals.AddAsync(meal);
        await _context.SaveChangesAsync();    // 错误发生在这里

        return true;
    }
    catch (Exception ex)
    {
        // 这里做日志记录
        return false;
    }
}

我在创建餐品的Razor组件中按如下方式添加所需标签:

// 当前版本
var tagList = new List<Tag>();

foreach (var item in selected)
{
      var tag = await data.GetTagByNameAsync(item.Text);
      tagList.Add(tag);
}

meal.Tags = tagList;

var result = await data.CreateMealAsync(meal);

// 旧版本
meal.Tags = new List<Tag>();

foreach (var item in selected)
{         
     meal.Tags.Add(new Tag() { TagName = item.Text } );
}

var result = await data.CreateMealAsync(meal);

旧版本中我以为错误源于创建ID重复的新标签,因此改为从数据库获取现有标签添加到集合,但仍报错。若删除数据库中对应标签则可正常创建,但该行为不可接受。我需要修改CreateMealAsync的行为,避免重复创建标签,仅更新关联表。


解决方法

以下两种方法均可生效,修改后的CreateMealAsync如下(Attach方法更简洁):

public async Task<bool> CreateMealAsync(Meal meal)
{
    try
    {
        // 从上下文查询的方法
        /*
        var tempListOfTags = meal.Tags;
        meal.Tags = new List<Tag>();

        foreach (var mealTag in tempListOfTags)
        {
            var tag = await _context.Tags
                .AsTracking()
                .FirstOrDefaultAsync(x => x == mealTag);

            meal.Tags.Add(tag);
        }
        */
        
        // Attach方法
        foreach (var tag in meal.Tags)
            _context.Attach(tag);

        await _context.Meals.AddAsync(meal);
        await _context.SaveChangesAsync();

        return true;
    }
    catch (Exception ex)
    {
        return false;
    }
}

注意:此问题可能仅在DbContext全局启用AsNoTracking时出现。


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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.23 15:06:29