EF Core + Oracle: كيفية جعل عمليات الترحيل عاطفية



عادة ، يتم استخدام إطار عمل EF Core مع MS SQL ، منتج Microsoft آخر. ومع ذلك ، هذه ليست عقيدة. على سبيل المثال ، في CUSTIS نكتب منطق الأعمال في C # ، ونستخدم Oracle لإدارة قواعد البيانات. تتميز EF Core بآلية ترحيل رائعة ، ولكن في حالتنا هذه ، فإنها ليست قوية. والحقيقة هي أن Oracle وعددًا من قواعد البيانات الأخرى ، مثل MySQL ، لا تدعم DDL للمعاملات . وهذا يعني أنه إذا وقعت الهجرة في مكان ما في الوسط ، فلا يمكن التراجع عنها أو التراجع عنها. كيفية تنفيذ عمليات الترحيل idempotent إلى EF Core بدون MS SQL؟

خلفية


تمتلك شركتنا أداة قوية إلى حد ما لتثبيت التصحيحات على قاعدة بيانات أوراكل ، والتي نستخدمها في عدد من المشاريع. تم كتابته عندما لم يكن هناك Liquibase ، وترحيل EF ، وغيرها من الأدوات المفتوحة. يتيح لك Patcher العمل مع مئات من قواعد البيانات وتتبع تاريخ التثبيت وعرض السجلات وتخزين الأسرار وغير ذلك الكثير. يتم كتابة البرامج النصية لتغيير قاعدة البيانات في شكل وحدات الماكرو SQL أو m4. بمساعدتهم ، يمكنك ، من بين أمور أخرى ، تعديل الهيكل: إنشاء الجداول والأعمدة والكائنات الأخرى. علاوة على ذلك ، فإن وحدات الماكرو m4 متشددة. هذا يعني أنه إذا حاولت إنشاء الجدول ، على سبيل المثال ، لا يقع البرنامج النصي ، ولكنه يرى أنه موجود بالفعل ويتخطى الإنشاء.

افترض أن البرنامج النصي لتثبيت التصحيح يتكون من عمليتين:

  1. إنشاء جدول A.
  2. إنشاء جدول ب.

إذا تعطل البرنامج النصي بعد العملية الأولى ، فسيظل الجدول أ في Oracle. ستعمل إعادة تطبيق التصحيح بشكل صحيح: سيتحقق البرنامج النصي من وجود A بالفعل ، لذلك سيتابع على الفور إلى العملية الثانية.

بالإضافة إلى المزايا ، لا تزال أداة الترقيع لها عيب - الأداة مغلقة ويتم استخدامها فقط في CUSTIS. يجب على المطورين أن يتعلموا العمل معه ، وخارج هذه الشركة ليست قيمة للغاية. بالإضافة إلى ذلك ، فإن أداة التصحيح لا تدعم وضع Code First للتشغيل ، لذلك يجب كتابة جميع البرامج النصية لتغيير بنية قاعدة البيانات يدويًا.

أردنا تجربة بعض الآليات الجاهزة لتثبيت التصحيحات واخترنا الترحيل. في نهاية عام 2019 ، تم إطلاق مشروع آخر للعملاء ، قررنا اختبار منهج جديد. كانت المشكلة الرئيسية لهذه الآلية هي عدم التهاون في الهجرة.

مشكلة


في MS SQL ، يتم تنفيذ سلسلة من عبارات DDL أو الترحيل كمعاملة مركبة واحدة. في حالة الانقطاع ، يتم إلغاء العملية تمامًا. Oracle DDL غير قابل للمعاملة ، لذا فإن انخفاض الترحيل سيؤدي إلى حالة غير متناسقة لقاعدة البيانات.

دعنا نعود إلى التصحيح ، الذي يتكون من عمليتين: إنشاء الجدولين A و B. إذا سقط الترحيل بعد الأول ، فستبقى Oracle في الجدول A. لن تعمل إعادة التشغيل - CREATE TABLEلن يعجب العامل أن A موجود بالفعل. ستفشل أيضًا في التراجع عن الترحيل: كتبت EF Core إلى جدول النظام أن الترحيل قد اكتمل ، فقط في نهاية العملية. من وجهة نظر EF Core ، إذا لم يكتمل الترحيل بعد ، فلا يوجد شيء للتراجع عنه.

القرار


لم يسفر البحث عن حل جاهز لـ Oracle على الإنترنت عن نتائج. كل ما وجدت هي مقالات عن كيفية إرسال و  تثبيت بقع عند العمل مع EF. بعد ذلك بقليل في StackOverflow ، توصلت إلى فكرة إنشاء IMigrationsSqlGenerator . هذه الواجهة مسؤولة عن إنشاء كود SQL الذي يعالج عمليات EF.

تتضمن الحزمة Oracle.EntityFrameworkCore OracleMigrationsSqlGenerator ، وتنفذ IMigrationsSqlGenerator. على سبيل المثال ، إذا كنت تريد إضافة عمود ، فسيتم إنشاء التعليمات البرمجية التالية:

ALTER TABLE MY_TABLE ADD (MY_COLUMN DATE)

ثم يتم تمرير التعليمات البرمجية إلى فئات أخرى لتشغيلها في قاعدة البيانات.

للبدء ، حاولت تجاوز زوج من عمليات OracleMigrationsSqlGenerator. تحولت المهمة إلى جدوى ، وبدأت في كتابة مهاجر عاطل عن العمل. هكذا نشأت CUSTIS.OracleIdempotentSqlGenerator .

قبل العملية EF ، يتحقق المهاجر لدينا لمعرفة ما إذا كان قد تم إجراؤه من قبل. على سبيل المثال ، تمت إضافة عمود مثل هذا:

DECLARE
    i NUMBER;
BEGIN
    SELECT COUNT(*) INTO i
    FROM user_tab_columns
    WHERE table_name = UPPER('MY_TABLE') AND column_name = UPPER('MY_COLUMN');
    IF I != 1 THEN
        EXECUTE IMMEDIATE 'ALTER TABLE MY_TABLE ADD (MY_COLUMN DATE)';  
    END IF;       
END;

باستخدام


استخدام الحزمة بسيط للغاية - ما عليك سوى استبدالها IMigrationsSqlGeneratorفي السياق الصحيح:

public class MyDbContext : DbContext
{
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.ReplaceService<IMigrationsSqlGenerator, IdempotentSqlGenerator>();
    }
}

يتم تشكيل عمليات الترحيل وتعيينها من خلال الأدوات القياسية لـ EF Core :

dotnet ef migrations add v1.0.1
dotnet ef database update

يمكن تنفيذ النهج العام المنصوص عليه في CUSTIS.OracleIdempotentSqlGenerator في مولدات مكتوبة لـ MySQL و MariaDB و Teradata و AmazonAurora وغيرها من قواعد البيانات التي لا يتم فيها استخدام DDL.

المراجع


الحزمة متاحة على مصادر NuGet
على GitHub

All Articles