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
相关产品推荐
相关产品推荐

