使用实体框架或实体框架核心删除父子关系

evb

我正在学习如何使用具有NHibernate背景的Entity Framework。网上有很多教程,但是我没有针对我的具体情况找到任何东西。我不想删除类别记录,我只想删除关系!

我有以下poco:

    public class TrainingCourse
    {
        [Key]
        public int CourseId { get; set; }
        public string CourseName { get; set; }
        public virtual ICollection<TrainingContent> Content { get; set; } = new List<TrainingContent>();
    }

    public class TrainingContent
    {
        [Key]
        public int ContentId { get; set; }
        public string ContentName { get; set; }
        public int? CategoryId { get; set; }
        [ForeignKey("CategoryId")]
        public Category Category { get; set; }
    }

    public class Category
    {
        public int CategoryId { get; set; }
        public string CategoryName { get; set; }
    }

在数据库中,我插入了以下“数据”

            var category = new Category { CategoryName = "Category 1" };
            var course = new TrainingCourse { CourseName = "Course 1" };
            context.TrainingCourses.Add(course);
            var content = new TrainingContent { ContentName = "Content 1", Category = category };
            context.TrainingContents.Add(content);
            course.Content.Add(content);

我现在想删除从TrainingContent到Category的关系:用数据库术语来说,我想将表TrainingContent中的外键CategoryId设置为null。

在一个上下文中执行此操作时,它起作用了,保存后我的外键为NULL:

        using (var context = new ClientContext())
        {
            _course = context.TrainingCourses.Include(c => c.Content.Select(cat => cat.Category)).FirstOrDefault(n => n.CourseName == "Course 1");

            _course.Content.ToList()[0].ContentName = "Content 1 changed";
            _course.Content.ToList()[0].Category = null;

            context.SaveChanges();
        }

但是在现实世界中,我们正在与不连贯的实体合作。我用下面的代码模拟

        using (var context = new ClientContext())
        {
            _course = context.TrainingCourses.Include(c => c.Content.Select(cat => cat.Category)).FirstOrDefault(n => n.CourseName == "Course 1");
        }

        _course.Content.ToList()[0].ContentName = "Content 1 changed";
        _course.Content.ToList()[0].Category = null;

        using (var context = new ClientContext())
        {
            context.Entry(_course.Content.ToList()[0]).State = EntityState.Modified;
            context.SaveChanges();
        }

这不起作用,内容名称已更改,但我的外键仍已定义。

如果我将导航属性设置为NULL,而FK设置为​​NULL,则它可以正常工作:

        using (var context = new ClientContext())
        {
            _course = context.TrainingCourses.Include(c => c.Content.Select(cat => cat.Category)).FirstOrDefault(n => n.CourseName == "Course 1");
        }

        _course.Content.ToList()[0].ContentName = "Course 1 changed";
        _course.Content.ToList()[0].Category = null;
        _course.Content.ToList()[0].CategoryId = null;

        using (var context = new ClientContext())
        {
            context.Entry(_course.Content.ToList()[0]).State = EntityState.Modified;
            context.SaveChanges();
        }

为什么这样的行为?我是EF和EF Core的新手,所以也许有一个简单的解释?我最初使用Entity Framework Core进行了此测试,但行为相同。

恶魔水一郎

您的问题是,导航属性为null时,EF将不会检查参照完整性(这将在SQL端发生)。

但是,大多数情况下这是必需的。考虑到您想将内容附加到另一个类别,您可能需要执行以下操作:

var content=context.Contents.FirstOrDefault();
content.CategoryId=2;
context.Entry(content).State=EntityState.Modified;
context.SaveChanges();

这看起来不错,不是吗?但是,请注意,您从未真正(延迟或显式)加载相应的Category对象-它仍然为null。

因此,在此示例中以及您的示例中,代码本身看起来都不错,但是FK和navigation属性不匹配。但是,由于导航属性不必正确(除非被上下文跟踪,否则它将被加载并且EF知道其正确的属性),因此EF将期望FK正确并将其保存到数据库中。

请注意,在某些情况下不会发生此问题:第一个显然是当EF能够在其ChangeTracker中跟踪类别时-然后它将知道您实际上是要考虑类别导航属性,而不必考虑FK。第二个是您的FK不属于对象的时候。从那时起,EF必须创建FK,但是您不能自己设置它。然后,EF必须设置与导航属性相对应的FK。(请注意,这不适用于null。null表示未加载该值该值为(以及其他含义),并且EF无法确定哪个是正确的)。

此外,请记住,在断开连接的情况下,EF将在附加对象树的根节点后检查整个对象树的参照完整性-如果任何FK与导航属性都不匹配,EF将抛出Exception(null例外,因为以上原因)。并且:在断开连接的情况下工作时,请注意,当任何父项处于“添加”状态时,必须附加所有子对象(atm,我不知道是否也必须对其进行修改/新建),因为否则EF无法修复子对象的FK并引发异常。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章