私は、NHibernateの背景を持つEntity Frameworkの使い方を学んでいます。ネット上にはたくさんのチュートリアルがありますが、私の場合は何かを見つけることはできませんでした。私はカテゴリのレコードを削除したくない、私はその関係を削除したい!
私は次のポコを持っている:
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テーブルにあるForeignkey CategoryIdをnullに設定したいと思います。
1つのコンテキストでこれを行うとき、それは働いています、私の外部キーは、保存後に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とナビゲーションプロパティは一致しません。しかし、ナビゲーションプロパティは正確である必要はないので (コンテキストによって追跡されない限り、ロードされ、EFが正しいと認識しているので)、EFはFKが正しいと予想し、したがってこの値をデータベースに保存します。
この問題は、いくつかのケースでは発生しないことに注意してください。最初は、明らかに、EFがChangeTrackerでカテゴリを追跡できたときです。実際にFKでなくても、カテゴリナビゲーションプロパティを実際に検討したいことがわかります。 2番目はあなたのFKがあなたのオブジェクトの一部でないときです。それ以来、EFはFKを作成する必要がありますが、自分で設定することはできません。次に、EFはナビゲーションプロパティに対応するFKを設定する必要があります。 (これはヌルでは動作しないことに気づく。ヌル手段のいずれかの値がロードされていないか 、または値は、いくつかの他の意味と一緒に( 何もしない )とEFが適切であるかを決定することができません)。
また、切断されたシナリオでは、EFはそのツリーのルートをアタッチしたときにオブジェクトツリー全体の参照整合性をチェックします.FKがナビゲーションプロパティと一致しない場合、EFはExceptionをスローします上記の理由の)。そして:切断されたシナリオで作業するとき、親エントリが追加状態になると、すべての子オブジェクトが添付されなければならないことに注意してください(それ以外はEFで修正/新しくする必要があるかどうかわかりません)。子オブジェクトのFKと例外をスローします。