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があります。ブログと投稿の間には、単純な1対多の関係があります。
ブログからすべての投稿を削除したいとします
もちろん、私は次のことを行うことができます:
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が発生します。
操作が失敗しました:1つ以上の外部キープロパティがnull不可であるため、関係を変更できませんでした。関係に変更が加えられると、関連する外部キープロパティがnull値に設定されます。外部キーがnull値をサポートしていない場合は、新しい関係を定義するか、外部キープロパティに別の非null値を割り当てるか、無関係のオブジェクトを削除する必要があります。
コレクションをクリアする適切な方法は何ですか?このための流暢なAPIステートメントはありますか?
2つのコードサンプルには違いがあります。
最初のコードサンプルdbContext.RemoveRange(postsToRemove)
は、Post
レコードを削除します。そのため、これらのレコードに関連する関係も削除されます。
2番目のコードサンプルmyBlog.Posts.Clear()
では、myBlog
とそれに対応するPost
レコードの間の関係を削除しています。 「実際の」基本的なアクションは、BlogId
レコードのPost
の値をnull
に設定することです。残念ながら、BlogId
がnull不可に設定されているため、これは不可能です。つまり、関係が削除され、実際にレコードが削除されることはありません。
Clear
は、エンティティの削除ではなく、リレーションシップで機能します。
あなたが書いた2つの解決策の間には、実用的な(私はもっと読みやすいと思う)中間の解決策があります。
dbContext.Posts.RemoveRange(myBlog.Posts);
// Now (also before SaveChanges) the myBlog.Posts is empty
dbContext.SaveChanges();
[〜#〜]編集[〜#〜]RemoveRange
は、Blog.Posts
コレクションから投稿も削除します