【问题标题】:"Adding a relationship with an entity which is in the Deleted state is not allowed" occurs when trying to delete "many" set in optional relationship“不允许与处于已删除状态的实体添加关系”在尝试删除可选关系中设置的“许多”时发生
【发布时间】:2015-11-13 12:45:37
【问题描述】:

我有一个一对多的关系,我试图删除“多”端的一组实例,但不断收到异常“不允许添加与处于已删除状态的实体的关系”。这是实体框架 6.1.1。

从教师到课程的关系是一对多的。这两个类定义为:

[Table("Course")]
public partial class Course {
    public int Id { get; set; }

    public int? TeacherId { get; set; }

    public virtual Teacher Teacher { get; set; }
}


[Table("Teacher")]
public partial class Teacher
{
    public Teacher()
    {
        Course = new HashSet<Course>();
    }

    public int Id { get; set; }

    [Required]
    [StringLength(50)]
    public string TeacherName { get; set; }

    public virtual ICollection<Course> Course { get; set; }
}

尝试删除课程的代码是导入的一部分:一组课程即将进入,数据库中但不属于传入课程的课程应从数据库中删除。 (此外,应该创建属于传入集但不在数据库中的课程,但这似乎可行)。

var existingCourses = ctx.Courses.ToList();
var toCreate = incomingCourses.Where(x => !existingCourses.Contains(x)).ToList();
var coursesToDelete = existingCourses.Where(x => !incomingCourses.Contains(x)).ToList();
ctx.Courses.RemoveRange(coursesToDelete);
ctx.SaveChanges(); // The exception occurs here

传入的课程集从 XML 文件解析为 DTO。在将它们与现有课程进行比较之前,它们被放置在一个列表中:

var incomingCourses = incomingDtos.Select(x => new Course
{
    Teacher = new Teacher { TeacherName = x.TeacherNameFromXml }
}.ToList();

Course 实体上还有其他用于标识课程的属性,但我没有在此处显示它们,因为我认为它们无关紧要。

调试时,我注意到正在删除的 Courses 的 Teacher 属性在调用 RemoveRange() 之前为非空,但之后为空。所以似乎发生了某种级联删除。

我试图通过我的 DbContext 删除所有级联删除,并在那里指定关系。这没有任何改变。

public class MyDbContext : DbContext {
    public MyDbContext() {}

    public MyDbContext(string connectionString) {
        Database.Connection.ConnectionString = connectionString;
    }

    public virtual DbSet<Teacher> Teacher { get; set; }
    public virtual DbSet<Course> Courses { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
        modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

        modelBuilder.Entity<Teacher>()
            .HasMany(x => x.Course)
            .WithOptional(x => x.Teacher)
            .HasForeignKey(x => x.TeacherId)
            .WillCascadeOnDelete(false);
    }
}

【问题讨论】:

  • 如何获得incomingCourses 收藏?
  • @LukasKabrt 我编辑了一些关于incomingCourses的信息
  • 我的猜测...... EF 对您的 incomingCourses 集合中的对象一无所知,它无法将其包裹起来。我会尝试在您的 Where 语句中按 ID 比较实体
  • 猜得好!我已经发布了一个答案,我比较了 DTO 而不是实际的 Course 对象。不过,我不确定为什么existingCourses.Where(x =&gt; !incomingCourses.Contains(x)).ToList(); 会返回existingCourses 集合中的实际对象以外的任何东西。也许有人可以详细说明答案?
  • 刚刚遇到同样的问题。根本原因是您尝试删除的实体被加载到teacher.Course 属性中。尝试直接从上下文中删除课程会导致 EF 认为您正在尝试添加实体,因为这些实体仍在 teacher.Course 集合中。解决方案是在从上下文中删除实体并保存更改之前清除 teacher.Course

标签: c# entity-framework


【解决方案1】:

@LukasKabrt 的评论为我指明了正确的方向。我没有直接比较 Course 对象,而是在 LINQ 内“临时”将现有课程转换为 DTO 并比较 DTO。现在我可以从coursesToDelete中删除所有内容了

var coursesToDelete = (
      from e in existing
      let dto = new CourseDto(e)
      where !incomingDtos.Contains(dto)
      select e).ToList();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-12
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    相关资源
    最近更新 更多