سؤال

لدي عملية تقوم باستيراد Excel Spreadhset، وتحليل البيانات في كائنات البيانات الخاصة بي.مصدر هذه البيانات هو جداً أمر مشكوك فيه، لأننا ننقل عملائنا من إدارة البيانات المستندة إلى جداول البيانات إلى نظام قاعدة بيانات مُدار مع التحقق من البيانات الصالحة.

أثناء عملية الاستيراد الخاصة بي، أقوم بإجراء بعض عمليات التحقق الأساسية من صحة البيانات لاستيعاب مدى سوء البيانات التي نستوردها، ولكن يتم إجراء التحقق الشامل من الصحة في DbContext.

جزء مما أحاول القيام به هو أنني أريد تقديم الصف # في جدول البيانات الذي يشير إلى أن البيانات سيئة حتى يتمكنوا بسهولة من تحديد ما يحتاجون إلى إصلاحه لاستيراد الملف.

بمجرد حصولي على البيانات من جدول البيانات (model)، والفرصة التي يعملون معها من قاعدة البيانات (opp)، هذا هو الكود الزائف للعملية الخاصة بي:

foreach (var model in Spreadsheet.Rows) { // Again, pseudocode
    if(opp != null && ValidateModel(model, opp, row)) {
        // Copy properties to the database object

        // This is in a Repository-layer method, not directly in my import process.
        // Just written here for clarity instead of several nested method calls.
        context.SaveChanges(); 
    }
}

يمكنني تقديم المزيد من التعليمات البرمجية هنا إذا لزم الأمر، ولكن المشكلة تكمن في ملف DbContext الخاص بي ValidateEntity() الطريقة (تجاوز DbContext).

مرة أخرى، لا يوجد أي خطأ في الكود الذي كتبته، على حد علمي، ولكن إذا فشلت الفرصة في هذا المستوى من التحقق من الصحة، فإنها تظل جزءًا من الكائنات غير المحفوظة في context, ، مما يعني أنه يحاول بشكل متكرر التحقق من صحته في كل مرة ValidateEntity() يسمى.يؤدي هذا إلى تكرار نفس رسالة خطأ التحقق من الصحة لكل صف بعد حدوث المشكلة الأولية.

هل هناك طريقة [عدل]احصل على السياق للتوقف عن محاولة التحقق من صحة الكائن بعد فشل التحقق من الصحة مرة واحدة[يحرر]؟أعلم أنه يمكنني الانتظار حتى النهاية والاتصال context.SaveChanges() مرة واحدة في النهاية للتغلب على هذا، ولكن أود أن أكون قادرًا على مطابقة هذا مع الصف الموجود في قاعدة البيانات.

كمرجع، أنا أستخدم Entity Framework 6.1 مع نهج Code First.

يحرر محاولة التوضيح بشكل أكبر لمارك إل.(بما في ذلك تحديث مجموعة التعليمات البرمجية أعلاه)

في الوقت الحالي، سيتم تكرار عمليتي عبر أكبر عدد من الصفوف الموجودة في جدول البيانات.السبب وراء استدعاء طبقة المستودع الخاصة بي مع كل كائن لحفظه، بدلاً من العمل بأسلوب يستدعي فقط context.SaveChanges() مرة واحدة هو السماح لنفسي بالقدرة على تحديد الصف الذي يسبب خطأ في التحقق من الصحة.

أنا سعيد لأن DbContext الخاص بي مخصص ValidateEntity() تكتشف الطرق أخطاء التحقق من الصحة، لكن المشكلة تكمن في حقيقة أنها لا تطرح ملف DbEntityValidationException لنفس الكيان عدة مرات.

أرغب في ذلك، إذا فشل التحقق من صحة الكائن مرة واحدة، فلن يحاول السياق حفظ الكائن، بغض النظر عن عدد المرات context.SaveChanges() يسمى.

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

المحلول

سؤالك ليس خدعة (هذا يتعلق بالحفظ وليس بالكيانات المحملة) ولكن يمكنك اتباع نصيحة جيمي أعلاه.أي أنه بمجرد إضافة كيان إلى السياق، يتم تعقبه في الحالة "المضافة" والطريقة الوحيدة لمنعه من إعادة التحقق من صحته هي فصله.إنه رابط SO داخلي، لكنني سأعيد إنتاج مقتطف الشفرة:

dbContext.Entry(entity).State = EntityState.Detached;

ومع ذلك، لا أعتقد أن هذه هي الطريقة التي تريد اتباعها، لأنك تستخدم الاستثناءات لإدارة الحالة دون داع (الاستثناءات باهظة الثمن).

من خلال العمل على المعلومات المقدمة، سأستخدم حلًا أكثر اعتمادًا على المجموعة:

  • قم بتعديل فئة النموذج الخاص بك بحيث يحتوي على RowID الذي يسجل صف جدول البيانات الأصلي (ربما تكون هناك أسباب وجيهة أخرى للحصول على هذا أيضًا)
  • قم بإيقاف تشغيل تتبع الكيان للسياق (يسمح دوران اكتشاف التغيير لكل منها Add() ليكون O(1))
  • إضافة كافة الكيانات
  • يتصل context.GetValidationErrors() واحصل على جميع أخطائك مرة واحدة، باستخدام RowID المذكور أعلاه لتحديد الصفوف غير الصالحة.

لم تحدد ما إذا كان يجب على عمليتك حفظ الصفوف الجيدة أو رفض الملف ككل، ولكن هذا سوف يلائم أيًا منهما - أي، إذا كنت بحاجة إلى حفظ الصفوف الجيدة، فافصل كافة الصفوف غير الصالحة باستخدام الكود أعلاه و ثم SaveChanges().


أخيرًا، إذا كنت تريد حفظ الصفوف الجيدة ولم تكن مرتاحًا للطريقة المستندة إلى المجموعة، فسيكون من الأفضل استخدام طريقة جديدة DbContext لكل صف واحد، أو على الأقل إنشاء جديد DbContext بعد كل خطأ.يصر فريق ADO.NET على أن إنشاء السياق "رخيص نسبيًا" (آسف ليس لدي أي اقتباس أو إحصائيات في متناول اليد لهذا الغرض) لذلك لا ينبغي أن يؤدي هذا إلى الإضرار بمعدل الإنتاجية لديك كثيرًا.ومع ذلك، فإنه سيبقى على الأقل O(n).لن ألومك، فإدارة سياق كبير يمكن أن يفتح أمامك مشكلات أخرى أيضًا.

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