المسارات
/
C#
C#
/
التمارين
/
ORM في خطوة واحدة
ORM في خطوة واحدة

ORM في خطوة واحدة

تمرين تعلّمي

مقدمة

عمر المورد

يستخدم resource-cleanup الواجهة IDispose للإشارة إلى أن موارد كائن ما أو غيره من حالات البرنامج كان لا بد من تحريرها أو إعادة ضبطها عندما لا يعود الكائن مطلوبًا (وأن الاعتماد على جامع القمامة لن يحقق ذلك أو يوفر مستوى التحكم المطلوب)، وأن طريقة IDisposable.Dispose() كانت المكان الطبيعي لمثل هذه العمليات.

وهناك تركيب آخر، وهو كتلة using، يتيح من منظور المستدعي جمع إدارة عمر الموارد كلها في عبارة واحدة.

using (var file = new File("my_secrets"))
{
    file.WriteSecret("xxxxxxx");
}

في المثال أعلاه، ستُحرَّر موارد نظام الملفات المرتبطة بـ file وتُعاد إلى نظام التشغيل عند الخروج من كتلة using.

ولكي يعمل هذا النمط، يجب أن يكون المتغير في عبارة using من نوع مرجعي يُنفّذ الواجهة IDisposable، وأن يُحرّر الموارد أو يُعيد ضبط حالة البرنامج في طريقة Dispose().

يقدّم C# 8 تحسينًا على هذا النمط، إذ يمكن وضع عبارة using في بداية الكتلة.

using var drawingResource = some_provided_or_new_object;
try
{
    drawingResource.DrawSomething();
}
catch (Exception)
{
    throw;
}

قد يتعرف مطورو Java على هذا بوصفه نظيرًا لآلية إدارة الموارد التلقائية التي قُدّمت في Java 7.

التعليمات

لقد عدتَ للعمل على نظام ORM (تخطيط العلاقات بين الكائنات) الذي قدمناه في object-relational-mapping.

يُظهر تحليلنا لاستخدام ORM أن 95% من المعاملات تُنفَّذ من داخل طريقة استدعاء واحدة، وقد تقرر أنه من الأنسب أن تكون لدينا طريقة ORM واحدة تفتح المعاملة وتكتبها وتُثبّتها.

تحتوي قاعدة البيانات على طرق النسخة التالية:

  • تبدأ Database.BeginTransaction() معاملة على قاعدة البيانات.
  • تكتب Database.Write(string data) البيانات إلى قاعدة البيانات داخل المعاملة. وإذا استقبلت بيانات غير صالحة، فسيُطرح استثناء. ومحاولة استدعاء هذه الطريقة دون استدعاء BeginTransaction() ستؤدي إلى طرح استثناء. وإذا نجحت، ستتغير الحالة الداخلية لقاعدة البيانات إلى DataWritten.
  • تُثبّت Database.EndTransaction() المعاملة في قاعدة البيانات. وقد تطرح استثناءً إذا لم تتمكن من إغلاق المعاملة أو إذا لم يكن Database.BeginTransaction() قد استُدعي.
  • يؤدي استدعاء Database.Dispose() إلى تنظيف قاعدة البيانات إذا طُرح استثناء أثناء معاملة. وسيغيّر هذا حالة قاعدة البيانات إلى Closed.

1. الكتابة إلى قاعدة البيانات

نفّذ الطريقة Orm.Write() لبدء معاملة على قاعدة البيانات، وكتابة البيانات الممرَّرة، وتثبيت المعاملة. ينبغي السماح لجميع الاستثناءات، بما فيها InvalidOperationException، بالمرور إلى المستدعي دون تسجيلها أو أي تدخل آخر.

Database db = new Database();
Orm orm = new Orm(db);
orm.Write("good write");
// => database has an internal state of State.Closed
orm.Write("bad write");
// => an exception is thrown but database is left with an internal state of State.Closed
orm.Write("bad commit");
// => an exception is thrown but database is left with an internal state of State.Closed

2. الكتابة إلى قاعدة البيانات وإرجاع مؤشر إلى المستدعي يوضح ما إذا كانت الكتابة ناجحة

مضت بضعة أشهر منذ أن أُدخلت Orm.Write()، وهناك انقسام في الفريق. يودّ العديد من المطورين أن يتعامل ORM مع الأخطاء عند طرح الاستثناءات، وأن يُرجع ببساطة مؤشرًا على النجاح إلى المستدعي.

يرجى تنفيذ الطريقة Orm.WriteSafely() لبدء معاملة على قاعدة البيانات، وكتابة البيانات الممرَّرة، وتثبيت المعاملة (كما سبق). وينبغي أن تُرجع true إذا كانت الكتابة ناجحة، وfalse خلاف ذلك. لا تحاول تسجيل الاستثناء.

Database db = new Database();
Orm orm = new Orm(db);
orm.WriteSafely("good write");
// => true
orm.WriteSafely("bad write");
// => false
orm.WriteSafely("bad commit");
// => false
تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
C# Exercism

مستعد لبدء ORM في خطوة واحدة؟

سجّل في Exercism لتتعلّم وتتقن C# عبر 62 مفهومًا178 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.