سلسلة net. للمحترفين الاتصال بمصادر البيانات عبر ADO.NET في dot NET


رضوى العربي

استخدام تقنية ADO.NET

تَستطيع تطبيقات إطار عمل ‎.NET الاتصال بمصادر البيانات (data sources) المُختلفة، مثل خادم SQL، وأوراكل Oracle، وXML، عن طريق تقنية ADO.NET -من مايكروسوفت-، وبالتالي يُمكِنها إدخال وجَلْب وتعديل البيانات الموجودة بمصدر البيانات (data source) بمجرد الاتصال به وِفقًا للصلاحيات المتناسبة.

تُوفِّر ADO.NET بِنْيَة معمارية بدون اتصال (connection-less)، وهو ما يُعدّ أسلوبًا آمنًا للتَعامُل مع قواعد البيانات؛ لأن -عن طريقه- لم يُعدّ من الضروري الإبقاء على الاتصال طوال الجلسة (session).

الممارسات المثلى عند التعامل مع ADO.NET

  • كقاعدة عامة، حَاوِل تَقصِير وقت الاتصال قدر المُسْتَطاع، واغلقه بمجرد انتهاء تَّنْفيذ الإجراء المطلوب إغلاقًا صريحًا، مما يَضمَن عودة الكائن المُستخدَم في الاتصال إلى مَجمع الاتصالات (connection pool)، ويُحسِن من أداء الاتصال الفعلّي بخادم قاعدة البيانات. لاحظ أن أكبر حجم لمَجمع الاتصالات (pool max size) هو 100 بشكل افتراضي. تجمُّع الاتصالات (connection pooling) بخادم SQL

  • أحِط كل الكائنات المُستخدَمة في الاتصال بقاعدة البيانات (database connections) بكتلة using، مما يَضمَن إغلاقها (dispose) والتخلص منها حتى في حالة التبلِّيغ عن اعتراض. اِطلع على عبارة using (مرجع c#) لمزيد من المعلومات.

  • اِسترجِع سَلاسِل اتصال قواعد البيانات (connection strings) بالاسم من ملف app.config أو web.config بناءً على نوع التطبيق:

  • يَتطلَّب إدراج مَرجِع لمكتبة System.configuration.

  • اِطلع على سلاسل الاتصال وملفات الإعداد لمزيد من المعلومات عن كيفية تنظيم ملف الإعداد.

  • ضَمِّن أي قيمة دَخْل بمُعامِل (parameter)؛ لأنه:

  • يُجنّبك هجمات الحقن (SQL Injection).

  • يُجنّبك الأخطاء في حالة استخدام نص مُتلاعَب به (malformed)، مثل تَضْمِين علامة اقتباس أحادية بداخل النص، والتي تَستخدِمها قاعدة البيانات SQL كمِحرِف تهريب (escaping) أو لبدء سِلسِلة نصية جديدة.

  • يَسمَح لمُوفِّر قاعدة البيانات (database provider) بإعادة اِستخدَام خطط تَّنْفيذ الاستعلام (query plans) -إن أمكن- مما يُعزز من الكفاءة. (غُير مُدَعَّم من جميع مُوفِّري قواعد البيانات، فقط بعضها).

  • عند التَعامُل مع مُعامِلات قاعدة البيانات:

  • يُعدّ عدم تَوافق نوع وحجم مُعامِلات قاعدة البيانات أحد أهم الأخطاء الشائعة والتي تؤدي إلى فَشَل عمليات الإضافة والتَحْديث والجَلْب.

  • قُم بتسمية مُعامِلات قاعدة البيانات بمُسمَّيات ذات مغزى، بنفس الطريقة التي تُسمِي بها أيّ مُتغيّرات بالشيفرة.

  • حدِّد نوع العمود (column) بقاعدة البيانات، مما يَضمَن عدم اِستخدَام أنواع المُعامِلات الخاطئة وتَجنُّب أيّ نتائج غيْر مُتوقَّعة.

  • تَأكَد من صلاحية (validate) قيم المُعامِلات قبل تمريرها إلى الأوامر command (فكما تَعلَم: مُدخلات خاطئة - مُخرجات خاطئة garbage in, garbage out).

  • اِستخدِم الأنواع الصحيحة عند إسناد القيم للمُعامِلات. مثلًا إذا كان لديك مُعامِل من النوع DateTime، لا تُسْنِد القيمة المطلوبة كسِلسِلة نصية من النوع string، ولكن اِسندها بحيث تَكون من النوع DateTime أي بعد تحليلها (parsing).

  • حدِّد خاصية size للمُعامِلات من النوع string؛ فقد يُعاد اِستخدَام نفس خطة تَّنْفيذ الاستعلام (execution plan) إذا كانت المُعامِلات مُتَوافِقة في النوع والحجم. يُستخدم -1 للإشارة إلى MAX.

  • لا تَستخدِم التابع AddWithValue؛ لأنه من السهل جدًا أن تَنسَى تَحديد نوع المُعامِل. اطلع على "هل يمكننا التوقف عن استخدام التابع AddWithValue؟" لمزيد من المعلومات.

  • عند التَعامُل مع كائنات الاتصال:

  • اِحرص على تأخير فتح الاتصال قدر المُسْتَطاع، واغلقه بأسرع ما يمكن، بحيث يقتصِر وقت الاتصال على تَّنْفيذ الإجراء المطلوب فقط. يُنصح بذلك عامةً عند التَعامُل مع أي مصدر خارجي.

  • لا تُشارِك الكائنات المُستخدَمة في الاتصال بأي شكل (مثلًا: لا تَستخدِم نمط المفرّدة (singleton pattern) بهدف مشاركة نُسخة وحيدة من النوع SqlConnection)، ولكن انشِئ كائن جديد إذا اقتضت الضرورة وتَخلَص (dispose) منه بمجرد انتهائه من تَّنْفيذ المطلوب. وذلك للأسباب التالية:

    • يَمتلك معظم مُوفِّري قواعد البيانات مَجمع اتصالات (connection pool)، مما يعني أنه ليس من المُكلِف تنشئة كائن اتصال جديد.
    • يَلْغي أي احتمالية مُستقبلية لحُدوث أخطاء إذا بدأت الشيفرة في التَعامُل مع أكثر من خيط (thread).

تنفيذ استعلامات SQL بصيغة أمر Command

public void SaveNewEmployee(Employee newEmployee)
{
    // (1)
    using(SqlConnection con = new SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings["MyConnectionName"].ConnectionString)) 
    {
        using(SqlCommand sc = new SqlCommand("INSERT INTO employee (FirstName, LastName,DateOfBirth /*etc*/) VALUES (@firstName, @lastName, @dateOfBirth /*etc*/)", con))
        {
             // (2)   
            sc.Parameters.Add(new SqlParameter("@firstName", SqlDbType.VarChar, 200){Value = newEmployee.FirstName ?? (object) System.DBNull.Value});

            sc.Parameters.Add(new SqlParameter("@lastName", SqlDbType.VarChar, 200){Value = newEmployee.LastName ?? (object) System.DBNull.Value});

            sc.Parameters.Add(new SqlParameter("@dateOfBirth", SqlDbType.Date){Value = newEmployee.DateOfBirth});

            // (3)
            con.Open();
            sc.ExecuteNonQuery();
        }
    }
}

(1): تنشئة كائن الاتصال بقاعدة البيانات ضِمْن كتلة using

(2): تم تَحديد النوع SqlDbType.VarChar والحجم 200 للمُعامِل firstName

(3): إِرجاء الفَتح الفعلّي للاتصال قَدْرِ الإمكان

ملحوظة 1: اطلع على التعداد SqlDbType

ملحوظة 2: اطلع على التعداد MySqlDbType

استخدام واجهات مشتركة لتجريد الأنواع الخاصة بالمورد

نظرًا لوجود العديد من مصادر البيانات (data sources)، وبالتالي العديد من مُوفِّري قواعد البيانات (database providers)، يُفضَّل الاعتماد على واجهات مُشتَرَكة (common interfaces) لتجريد (abstract) العمليات المُشتَرَكة.

var providerName = "System.Data.SqlClient"; 
var connectionString = "{your-connection-string}";

var factory = DbProviderFactories.GetFactory(providerName);

using(var connection = factory.CreateConnection()) { //IDbConnection
    connection.ConnectionString = connectionString;
    connection.Open();

    using(var command = connection.CreateCommand()) { //IDbCommand
        command.CommandText = "{query}";

        using(var reader = command.ExecuteReader()) { //IDataReader
            while(reader.Read()) {
                ...
            }
        }
    }
}

ترجمة -وبتصرف- للفصل ADO.NET من كتاب ‎.NET Framework Notes for Professionals





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن