لن يتم حفظ الكيان الفرعي الجديد عند حفظ الكيان الأصلي
-
02-01-2020 - |
سؤال
لدي كيان الوالدين
foo
الموجود في قاعدة البيانات، لدي خاصية bar
على هذا الكيان (علاقة واحد إلى متعدد).
Foo
تم فصله لأنه تم إلغاء تسلسله باستخدام WebApi، لذلك أفعل ذلك foo
context.Foos.AddOrUpdate(foo);
حتى لو كان هناك جديد bar
المرجع المرفق به، لن يتم حفظه، ومع ذلك فهو يعمل بهذه الطريقة بالنسبة لعلاقة أخرى لدينا وهي علاقة كثير إلى كثير.إذا أضفت كيانًا جديدًا إلى تلك المجموعة، فسيتم حفظه في جدوله، كما تتم إضافة صف إلى جدول العلاقة.
إذا فعلت context.Bars.AddOrUpdate(foo.Bar);
قبل الاتصال context.Foos.AddOrUpdate(foo);
سيحفظ الشريط الجديد بشكل صحيح في جدول الشريط، لكنه لن يضيف معرف الشريط الصحيح إلى جدول foo
@ يوليام شاندرا
إذا فهمت إجابتك بشكل صحيح (أعتقد أنك تخلط بين الأشرطة والفوس في إجابتك) فهل يجب أن ينجح هذا؟
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
ولكن لا
المحلول
يحتاج العمل مع الكائنات المنفصلة إلى تعليمات برمجية إضافية.
إذا كنت تعمل مع الكائنات غير المتصل ، فيجب عليك إدارة التزامن يدويًا.
لو Bar
هو كيان موجود تحتاج إلى إرفاقه أولاً، لذلك Foo
سيتم إضافتها كما Bar's
أطفال.
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
مثال الكود أعلاه مشابه لـ Course
(Foo
) و Department
(Bar
) مثال في هذا المقال.
لكن اذا Bar
هو كيان جديد تحتاج فقط إلى إضافته Foo
, ، ثم Bar
سيتم إضافتها أيضًا.
else
{
context.Foos.Add(foo);
}
يمكن التحقق من بعض الأنواع الأخرى إجابتي.
تحديث
قبل أن أشرح أكثر، أود أن أعرض رمزًا متطابقًا.
db.Set<T>().Add(instance)
يساويdb.Entry(instance).State = EntityState.Added;
db.Set<T>().Attach(instance)
يساويdb.Entry(instance).State = EntityState.Unchanged;
الجواب السابق أوضح شرطين.
New Foo والشريط الحالي
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
نيو فو وبار جديد
context.Foos.Add(foo);
تمت الإضافة الخاصة
Added
له حالة خاصة، بمجرد وضع علامة على الكيان Added
.سيتم وضع علامة على جميع الكيانات في الرسم البياني على أنها Added
أيضًا، حتى لو كان أي كيان مرجعي عبارة عن كائن موجود في قاعدة البيانات.إذا كان لدينا هذا الرمز، ستتم إضافة Foo وBar.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Foo>().Add(foo);
db.SaveChanges();
لمنع حدوث ذلك، يجب إرفاق الشريط أولاً.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Bar>().Attach(bar);
db.Set<Foo>().Add(foo);
db.SaveChanges();
يفحص مقالة جولي ليرمان للحصول على شرح أكثر اكتمالا.
والسبب في حدوث ذلك هو أنه عند استخدام طريقة dbset.add (أي ، screencasts.add) ، ليس فقط حالة الكيان الجذري الذي تم وضع علامة عليه "إضافة" ، ولكن كل شيء في الرسم البياني لم يكن السياق على دراية به من قبل تمت إضافة علامة كذلك.على الرغم من أن المطور قد يدرك أن الموضوع له قيمة معرف موجودة ، فإن إطار عمل الكيان يكرم EntityState (إضافة) ويقوم بإنشاء أمر قاعدة بيانات إدراج للموضوع ، بغض النظر عن المعرف الحالي.
اضبط الشرح بناءً على التحديث الخاص بك
وسؤالك المحدث يتعلق بـ Foo الحالي والشريط الجديد.باستخدام الكود الخاص بك، لن تضيف النتيجة شريطًا جديدًا ولن يقوم Foo الحالي بإنشاء علاقة مع Bar الجديد.
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
إذا أضفنا الشريط يدويًا مع AddOrUpdate(foo)
, ، والنتيجة لا تزال ليست كما هو متوقع.ستتم إضافة الشريط الجديد، لكن لن يكون لـ Foo علاقة بالشريط الجديد.
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
سلوك AddOrUpdate
غير متناسق.
حل
إذا كنت تعمل مع الكائنات غير المتصل ، فيجب عليك إدارة التزامن يدويًا.
يجب أن يعمل هذا الرمز في جميع الظروف.
- نيو فو و نيو بار
- Foo الجديد والشريط الموجود
- Foo الحالي والشريط الجديد
- Foo الموجود والشريط الموجود
يعتمد هذا الرمز على المعرف (المعرف = 0 كيان جديد).
db.Entry(foo).State =
foo.FooId == 0 ? EntityState.Added : EntityState.Modified;
if (foo.Bar != null)
{
db.Entry(foo.Bar).State =
foo.Bar.BarId == 0 ? EntityState.Added : EntityState.Modified;
^^^
// If you don't want to change the Bar while creating a relationship between
// Foo and with existing Bar, you can change
// `EntityState.Modified` with `EntityState.Unchanged`
}
db.SaveChanges();
متعلق ب AddOrUpdate
, أعتقد أن هناك قضية مفتوحة يمكن العثور عليها هنا.