我在使用Clear()
从实体框架中删除集合中的所有元素时遇到问题考虑一下常用的博客和帖子示例。
public class Blog
{
public int Id {get; set;}
public string Name {get; set;}
public virtual ICollection<Post> Posts { get; set; }
}
public class Post
{
public int Id { get; set; }
// foreign key to Blog:
public int BlogId { get; set; }
public virtual Blog Blog { get; set; }
public string Title { get; set; }
public string Text { get; set; }
}
public class BlogContext : DbContext
{
public DbSet<Blog> Blogs {get; set;}
public DbSet<Post> Posts {get; set;}
}
博客有很多帖子。博客有一个ICollection的帖子。博客和帖子之间存在直接的一对多关系。
假设我要删除博客中的所有帖子
当然,我可以做到以下几点:
Blog myBlog = ...
var postsToRemove = dbContext.Posts.Where(post => post.BlogId == myBlog.Id);
dbContext.RemoveRange(postsToRemove);
dbContext.SaveChanges();
然而,以下似乎更容易:
Blog myBlog = ...
myBlog.Posts.Clear();
dbContext.SaveChanges();
但是这会导致InvalidOperationException:
操作失败:无法更改关系,因为一个或多个外键属性不可为空。当对关系进行更改时,相关的外键属性将设置为空值。如果外键不支持空值,则必须定义新关系,必须为foreign-key属性分配另一个非空值,或者必须删除不相关的对象。
清除收藏品的正确方法是什么?是否有一个流畅的API声明?
答案 0 :(得分:6)
两个代码示例之间存在差异。
您的第一个代码示例dbContext.RemoveRange(postsToRemove)
会删除Post
条记录。因此,任何涉及这些记录的关系也将被删除。
在您的第二个代码示例myBlog.Posts.Clear()
中,您将删除myBlog
与其对应的Post
记录之间的关系。真实的&#39;基本操作是将BlogId
记录的Post
值设置为null
。不幸的是,这是不可能的,因为BlogId
设置为不可为空。因此,简而言之,关系将被删除,并且实际上不会删除任何记录。
答案 1 :(得分:2)
Clear
处理关系,而不是删除实体。
你写的两个解决方案之间有一个工作(我认为更具可读性)的中途解决方案。
dbContext.Posts.RemoveRange(myBlog.Posts);
// Now (also before SaveChanges) the myBlog.Posts is empty
dbContext.SaveChanges();
修改强>
RemoveRange
还会从Blog.Posts
集合