.NET EntityFramework无法重复添加同结构Exercise对象至数据库问题
问题描述
我有包含名称、描述和组数的训练模板,希望根据组数生成对应数量的Exercise对象并存入数据库。例如模板为[{"name":"Legs","sets":3},{"name":"Arms","sets":2}],期望数据库中保存[{legs},{legs},{legs},{arms},{arms}],但实际仅[{legs},{arms}]被保存。此外,保存后的Exercise对象ExerciseId并非连续的唯一值(如1024-1028),而是相同结构的对象被分配了相同ID(如1024或1025),尽管它们是不同的对象。
现有代码
生成Exercise并保存的代码
var exercises = planTemplate.Exercises .SelectMany(x => Enumerable.Repeat(new Exercise { Name = x.Name, Description = x.Description }, x.Sets)) .ToList() ?? new List<Exercise>(); var plan = new FitnessPlan { TemplateId = planTemplate.Id, Archived = false, User = user, Name = planTemplate.Name, Exercises = exercises, }; await _context.FitnessPlans.AddAsync(plan); await _context.SaveChangesAsync();
FitnessPlan类定义
public class FitnessPlan { public int Id { get; set; } public int TemplateId { get; set; } public bool Archived { get; set; } public int UserId { get; set; } public AppUser User { get; set; } public string Name { get; set; } public IEnumerable<Exercise> Exercises { get; set; } }
问题原因
- EF实体跟踪机制:
Enumerable.Repeat会生成同一个Exercise实例的多个引用,Entity Framework会将这些引用视为同一个对象,仅跟踪和保存一次。 - 集合类型限制:
FitnessPlan中使用IEnumerable<Exercise>作为集合类型,EF对抽象集合的处理支持有限,无法正确识别需要添加多个独立实体。
解决方案
1. 生成独立的Exercise实例
替换Enumerable.Repeat为Enumerable.Range+Select,确保每次迭代都创建全新的Exercise对象:
var exercises = planTemplate.Exercises .SelectMany(x => Enumerable.Range(1, x.Sets) .Select(_ => new Exercise { Name = x.Name, Description = x.Description })) .ToList() ?? new List<Exercise>();
2. 修改集合类型为具体实现
将FitnessPlan中的Exercises属性从IEnumerable<Exercise>改为List<Exercise>,EF对具体集合类型的处理更完善:
public class FitnessPlan { public int Id { get; set; } public int TemplateId { get; set; } public bool Archived { get; set; } public int UserId { get; set; } public AppUser User { get; set; } public string Name { get; set; } public List<Exercise> Exercises { get; set; } // 改用List<T> }
3. 显式添加每个Exercise到上下文(可选)
如果前两种方法无效,可以手动将每个Exercise添加到上下文,强制EF跟踪每个实体:
foreach (var exercise in exercises) { await _context.Exercises.AddAsync(exercise); } await _context.FitnessPlans.AddAsync(plan); await _context.SaveChangesAsync();
内容的提问来源于stack exchange,提问作者Zetka
相关产品推荐
相关产品推荐

