EF 4: إزالة كائن الطفل من المجموعة لا يحذفه - لماذا؟

StackOverflow https://stackoverflow.com/questions/2554696

سؤال

يمكنني استخدام Entity Framework 4 ولدي علاقة الوالدين - مع مجموعة "Cascade Delete". لذلك أتوقع عندما أقوم بإزالة طفل من الوالد ، يتم حذف الطفل عندما أدعو Savechanges ().

        cuRepository.Attach(_controlUnit);
        foreach (var recipe in recipes) {
            _controlUnit.Recipes.Remove(recipe);
            //repository.DeleteObject(recipe);
        }

بدلاً من ذلك ، أحصل على خطأ:

System.InvalidOperationException حدثت رسالة = فشل العملية: لا يمكن تغيير العلاقة لأن واحدة أو أكثر من خصائص المفتاح الأجنبي غير قابلة للفرق. عندما يتم إجراء تغيير على علاقة ، يتم تعيين خاصية مفتاح الأجنبي ذات الصلة على قيمة فارغة. إذا كان المفتاح الأجنبي لا يدعم القيم الخالية ، فيجب تحديد علاقة جديدة ، يجب تعيين خاصية مفتاح الأجنبية قيمة أخرى غير خالية ، أو يجب حذف الكائن غير المرتبط.

عندما أقوم بحذف الأطفال صراحة (انظر الخط المعلق) ، كل شيء على ما يرام. ماذا ينقصني؟

هل كانت مفيدة؟

المحلول

أنت لا تحذف الكائن ببيان إزالة. بدلاً من ذلك ، تحاول تغيير السجل وجعله يتيمًا (عن طريق ضبط المفتاح الخارجي على الفارغ). تحتوي قاعدة البيانات على قيود غير فائقة على هذا العمود وتمنعك من القيام بذلك.

نصائح أخرى

http://weblogs.asp.net/zeeshanhirani/archive/2010/07/23/removing-entity-from-a-rlex-collection.aspx يشرح بالضبط ما حدث لك.


على افتراض أن لديك تصميم الفصل شيء مثل هذا:

sample class design

سيقوم إطار الكيان بإنشاء أعمدة المفاتيح الخارجية المطلوبة ويضيف NOT NULL القيود عليهم لأن جميع الوصفات سوف ترتبط دائمًا مع وحدة التحكم الواحدة بالضبط.

لذا في وقت التشغيل ، سيكون لديك كائنات مشابهة للتخطيط التالي:

object diagram at runtime

الآن يتم تشغيل التعليمات البرمجية الخاصة بك وحذف العلاقة بين كائنات الوصفة ومكافحة التحكم:

objects with deleted relationships

محاولة حفظ في هذه اللحظة ، لا تحتوي قاعدة البيانات على معرف التحكم في المفتاح الخارجي NOT NULL عمود. تنتهك حالة الكائن الحالي مخطط الفصل أعلاه ولا يمكن حفظه في تخطيط قاعدة البيانات التي تم إنشاؤها بموجب افتراض أن كل وصفة ترتبط مع وحدة التحكم واحدة. هذا هو السبب في أن قاعدة البيانات ترفض حفظ التغييرات وترى الاستثناء.

وهذا ما يفسر أيضًا سبب عمله عندما تقوم بتفكيك الخط الذي يحذف الكيان: تتم إزالة الكيان من قاعدة البيانات إلى جانب علاقته ، لذلك لا يتم انتهاك أي قيود ، وبالتالي لا استثناء.

"لكنني وضعت ON DELETE CASCADE على العلاقة ... "

نعم ، ولكن هذا يتم تشغيله فقط على حذف الكائن ، وليس عند حذف العلاقة. مع ON DELETE CASCADE تعيين ، هذا يجب أن يعمل:

controlUnitRepository.DeleteObject(_controlUnit);
// deletes the ControlUnit and all associated Recipe entities

إذا كنت ترغب في تشغيل حذف كيانات الوصفة عند حذف علاقتها مع ControlNit ، يجب ألا تكون علاقتك ارتباطًا بسيطًا بل تكوين:

updated class diagram with composition

لا يدعم EF هذا أصليًا ، ولكن يمكنك محاكاة السلوك باستخدام تحديد العلاقات. بمجرد أن يكون الكيان في علاقة تحديد إلى كيان الوالدين ويتم إزالة هذه العلاقة ، تتم إزالة الكيان أيضًا. يبدو أن هذا كان نيتك منذ البداية. لمزيد من المعلومات حول تحديد العلاقة ، انظر تنفيذ تحديد العلاقات مع EF4 حيث قمت بتطبيق تحديد العلاقات مع EF4 وربطت بمزيد من مواد القراءة.

يضيف context.DeleteObject(recipe) داخل الحلقة

إذا قمت بعمل العلاقة بين الطفل والوالدين ، فيمكنك إزالة كيانات الأطفال من المجموعة. تحتاج إلى جعل مفتاح الطفل مفتاحًا مركبًا يحتوي على مفتاح المعرف الأساسي للوالد. بهذه الطريقة تعرف EF أنها تحتاج إلى إزالة الطفل.

يقول تحديد العلاقة بشكل أساسي إذا لم يكن الوالد موجودًا ، فليس لدى الطفل معنى. هذا يعني أن EF يعرف أنه من الآمن حذف الطفل عند إزالة العلاقة.

انظر هذا السؤال يؤدي تحديد العلاقة وإدخال كيانات الأطفال إلى "لا يمكن إدراج قيمة صريحة لعمود الهوية في الجدول" و هذه هل من الممكن إزالة الطفل من التجميع وحل المشكلات على Savechanges؟

أستخدم هذا الامتداد حتى لا أضيف طريقة في DAL فقط لحذف كيان (رمز مأخوذ من http://blogs.msdn.com/b/alexj/archive/2009/06/08/tip-24-how-to-get-the-objectcontext-from-an-entity.aspx):

public static void Delete<T>(this EntityCollection<T> collection, T entityToDelete) where T : EntityObject, IEntityWithRelationships
{
    RelationshipManager relationshipManager = entityToDelete.RelationshipManager;

    IRelatedEnd relatedEnd = relationshipManager.GetAllRelatedEnds().FirstOrDefault();
    if (relatedEnd == null)
    {
        throw new Exception("No relationships found for the entity to delete. Entity must have at least one relationship.");
    }

    var query = relatedEnd.CreateSourceQuery() as ObjectQuery;
    if (query == null)
    {
        throw new Exception("The entity to delete is detached. Entity must be attached to an ObjectContext.");
    }

    query.Context.DeleteObject(entityToDelete);
    collection.Remove(entityToDelete);
}

لذلك أحذف كيان مثل Order.Products.Delete(prod).

قيود استخدام التمديد هي:
- يجب أن يكون للكيان علاقات ؛
- يجب إرفاق الكيان بـ ObjectContext.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top