تعيين ADO.NET من SQLDataReader إلى كائن المجال؟

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

  •  09-06-2019
  •  | 
  •  

سؤال

لدي وظيفة تعيين بسيطة جدًا تسمى "BuildEntity" والتي تقوم بالترميز الممل المعتاد "يسار/يمين" المطلوب لتفريغ بيانات القارئ الخاصة بي في كائن المجال الخاص بي.(كما هو موضح أدناه) سؤالي هو - إذا لم أقم بإعادة كل عمود في هذا التعيين كما هو، فسوف أحصل على الاستثناء "System.IndexOutOfRangeException" وأردت معرفة ما إذا كان لدى ado.net أي شيء لتصحيح هذا الأمر، لذلك لا أفعل ذلك. لا تحتاج إلى إعادة كل عمود مع كل استدعاء إلى SQL ...

ما أبحث عنه حقًا هو شيء مثل "IsValidColumn" حتى أتمكن من الاحتفاظ بوظيفة التعيين هذه خلال فصل DataAccess الخاص بي مع تحديد جميع التعيينات اليسرى/اليمين - وجعلها تعمل حتى عندما لا يُرجع sproc كل عمود مدرج. ..

Using reader As SqlDataReader = cmd.ExecuteReader()
  Dim product As Product
  While reader.Read()
    product = New Product()
    product.ID = Convert.ToInt32(reader("ProductID"))
    product.SupplierID = Convert.ToInt32(reader("SupplierID"))
    product.CategoryID = Convert.ToInt32(reader("CategoryID"))
    product.ProductName = Convert.ToString(reader("ProductName"))
    product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))
    product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))
    product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))
    product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))
    product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))
    productList.Add(product)
  End While
هل كانت مفيدة؟

المحلول

على الرغم من أن Connection.GetSchema("Tables") يقوم بإرجاع بيانات التعريف حول الجداول الموجودة في قاعدة البيانات الخاصة بك، إلا أنه لن يقوم بإرجاع كل شيء في sproc الخاص بك إذا قمت بتحديد أي أعمدة مخصصة.

على سبيل المثال، إذا قمت بإدخال بعض الأعمدة العشوائية المخصصة مثل *SELECT ProductName,'Testing' As ProductTestName FROM dbo.Products" فلن ترى "ProductTestName" كعمود لأنه غير موجود في مخطط جدول المنتجات.لحل هذه المشكلة، والسؤال عن كل عمود متوفر في البيانات التي تم إرجاعها، استخدم إحدى الطرق الموجودة على كائن SqlDataReader "GetSchemaTable()"

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

تحديث كود المصدر

Using reader As SqlDataReader = cmd.ExecuteReader() 
Dim table As DataTable = reader.GetSchemaTable()
Dim colNames As New DataTable()
For Each row As DataRow In table.Rows
 colNames.Columns.Add(row.ItemArray(0))
Next
Dim product As Product  While reader.Read()    
product = New Product()  
If Not colNames.Columns("ProductID") Is Nothing Then
  product.ID = Convert.ToInt32(reader("ProductID"))
End If    
product.SupplierID = Convert.ToInt32(reader("SupplierID"))    
product.CategoryID = Convert.ToInt32(reader("CategoryID"))    
product.ProductName = Convert.ToString(reader("ProductName"))    
product.QuantityPerUnit = Convert.ToString(reader("QuantityPerUnit"))    
product.UnitPrice = Convert.ToDouble(reader("UnitPrice"))    
product.UnitsInStock = Convert.ToInt32(reader("UnitsInStock"))    
product.UnitsOnOrder = Convert.ToInt32(reader("UnitsOnOrder"))    
product.ReorderLevel = Convert.ToInt32(reader("ReorderLevel"))    
productList.Add(product)  
End While

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

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

نصائح أخرى

تحقق من هذا أيضا طريقة التمديد كتبت للاستخدام في أوامر البيانات:

public static void Fill<T>(this IDbCommand cmd,
    IList<T> list, Func<IDataReader, T> rowConverter)
{
    using (var rdr = cmd.ExecuteReader())
    {
        while (rdr.Read())
        {
            list.Add(rowConverter(rdr));
        }
    }
}

يمكنك استخدامه مثل هذا:

cmd.Fill(products, r => r.GetProduct());

حيث "المنتجات" هي IList<Product> الذي تريد تعبئته، ويحتوي "GetProduct" على المنطق لإنشاء مثيل منتج من قارئ البيانات.لن يساعد ذلك في حل هذه المشكلة المحددة المتمثلة في عدم وجود جميع الحقول، ولكن إذا كنت تستخدم الكثير من ADO.NET القديم مثل هذا، فقد يكون ذلك مفيدًا جدًا.

لماذا لا تقوم فقط بإرجاع كل مجموعة أعمدة كاملة من sproc، باستخدام قيم خالية أو -1 أو مقبولة حيث لا تتوفر لديك البيانات.يتجنب الاضطرار إلى التقاط IndexOutOfRangeException أو إعادة كتابة كل شيء في LinqToSql.

استخدم ال GetSchemaTable() طريقة استرجاع البيانات الوصفية DataReader.ال DataTable يمكن استخدام ما تم إرجاعه للتحقق من وجود عمود معين أم لا.

لماذا لا تستخدم LinqToSql - كل ما تحتاجه يتم تنفيذه تلقائيًا.من أجل كونها عامة يمكنك استخدام أي شيء آخر أداة أورم ل.NET

إذا كنت لا ترغب في استخدام ORM، فيمكنك أيضًا استخدام الانعكاس لأشياء مثل هذه (على الرغم من أنه في هذه الحالة نظرًا لعدم تسمية ProductID بنفس الاسم على كلا الجانبين، فلن تتمكن من القيام بذلك بالطريقة المبسطة الموضحة هنا):قائمة الموفر في C#

يمكن أن أسميه reader.GetOrdinal لكل اسم حقل قبل بدء حلقة while.للأسف GetOrdinal يلقي IndexOutOfRangeException إذا لم يكن الحقل موجودًا، فلن يكون أداؤه جيدًا.

ربما يمكنك تخزين النتائج في ملف Dictionary<string, int> واستخدامها ContainsKey طريقة لتحديد ما إذا تم توفير الحقل.

انتهى بي الأمر بكتابة تصميمي الخاص، لكن مصمم الخرائط هذا جيد جدًا (وبسيط): https://code.google.com/p/dapper-dot-net/

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