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

.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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 12:23:29