断开连接的方案中的实体框架因多个类型的实体而导致保存或接受更改失败

时间:2016-04-14 14:39:55

标签: c# angularjs entity-framework asp.net-web-api dbcontext

我正在使用Web API和实体框架的小项目中工作。我在发布我的实体时面临一些问题。

我的实体看起来像这样:

 public class DayExercises
    {
        public DayExercises()
        {
            Exercises = new List<Exercise>();
        }
        [Key]
        public int Id { get; set; }

        public string Day { get; set; }

        public virtual ICollection<Exercise> Exercises { get; set; }

    }

和我的Exercise实体看起来像这样。

 public class Exercise 
    {    
       public Exercise()
        {
            DayExercises = new List<DayExercises>();
        }
            public int Id { get; set; }
            public string Name { get; set; }
            public virtual List<DayExercises> DayExercises { get; set; }
    }

我发布dayExercises的web api方法看起来像这样

 [ResponseType(typeof(WorkoutTemplate))]
    public IHttpActionResult PostWorkoutTemplate(DayExercises dayExercises)
    {            
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        foreach (var dayExercise in dayExercises)
        {
            fitnessDbContext.Entry(dayExercise).State = EntityState.Added;

            foreach (var exercise in dayExercise.Exercises.ToList())
            {
                fitnessDbContext.Entry(exercise).State = EntityState.Unchanged;

            }
        }

        db.SaveChanges();

        return CreatedAtRoute("DefaultApi", new { id = dayExercises.Id }, dayExercises);
    }

这种关系是多对多的。

问题: 我正在向我的方法发送一个dayExercise,其中包含现有Exercise(已存在于数据库中)。但是当我发布dayExercise和SAME两个练习时。它抛出了这个例外:

其他信息:保存或接受更改失败,因为多个类型为&#39; FitnessFirst.WebApi.Exercise&#39;的实体具有相同的主键值。  确保显式设置的主键值是唯一的。确保在数据库和Entity Framework模型中正确配置了数据库生成的主键。  使用实体设计器进行数据库优先/模型优先配置。使用&#39; HasDatabaseGeneratedOption&#34;流利的API或“DatabaseGeneratedAttribute”#39;代码优先配置。

我还尝试了Deattach个实体,然后再次使用他们的IDAttach从数据库中获取练习并将其添加到dayExercise,但它没有&# 39;保存到数据库。

注意:当我添加两个不同的练习时,它不会抛出异常。

我也阅读了以下答案,但它没有解决它:Ensure that explicitly set primary key values are unique

任何建议或解释。

1 个答案:

答案 0 :(得分:1)

我知道这是一个老帖子,但昨天我遇到了同样的问题。这是我提出的解决方案。基本上,实体框架更改跟踪器仅允许实体的唯一值。因此,为了解决错误,您需要检查实体是否已存在于更改跟踪器中并使用该实例。

var excercises = dayExercise.Exercises.ToList();
for (int i = 0; i < excercises.Count; i++)
{
    var unchangedEntity = _dbContext.ChangeTracker.Entries<Exercise>()
         .Where(xy => xy.State == EntityState.Unchanged &&
         xy.Entity.Id == excercises [i].Id).FirstOrDefault();

    if (unchangedEntity == null)
    {
        fitnessDbContext.Entry(excercises[i]).State = EntityState.Unchanged;
    }
    else
    {
        excercises[i] = unchangedEntity.Entity;
    }

}