Сопоставление ADO.NET от SQLDataReader к объекту домена?

У меня есть очень простая функция отображения, называемая «BuildEntity», которая выполняет обычное скучное кодирование «влево / вправо», необходимое для выгрузки данных читателя в мой объект домена. (показано ниже). Мой вопрос таков: если я не возвращаю каждый столбец в этом отображении как есть, я получаю исключение «System.IndexOutOfRangeException» и хочу знать, есть ли в ado.net что-нибудь, чтобы исправить это, поэтому я не нужно возвращать каждый столбец с каждым вызовом в SQL ...

Что я действительно ищу, так это что-то вроде «IsValidColumn», так что я могу сохранить эту функцию отображения 1 в своем классе 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
22.08.2008 12:14:37
8 ОТВЕТОВ
РЕШЕНИЕ

Хотя connection.GetSchema («Таблицы») возвращает метаданные о таблицах в вашей базе данных, она не вернет все в вашем 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

Честно говоря, это хак, поскольку вы должны возвращать каждый столбец, чтобы правильно увлажнять ваш объект. Но я подумал включить этот метод чтения, так как он будет фактически захватывать все столбцы, даже если они не определены в вашей схеме таблицы.

Такой подход к отображению ваших реляционных данных в модель вашего домена может вызвать некоторые проблемы, когда вы попадаете в сценарий отложенной загрузки.

1
28.08.2008 17:34:19

Почему бы вам не использовать LinqToSql - все, что вам нужно, делается автоматически. Ради общего понимания вы можете использовать любой другой инструмент ORM для .NET

0
22.08.2008 12:18:46

Я бы назвал reader.GetOrdinalкаждое имя поля перед началом цикла while. К сожалению, GetOrdinalвыбрасывает, IndexOutOfRangeExceptionесли поле не существует, поэтому оно не будет очень производительным.

Вы могли бы, вероятно, сохранить результаты в a Dictionary<string, int>и использовать его ContainsKeyметод, чтобы определить, было ли предоставлено поле.

0
18.05.2013 01:47:15

Также проверьте этот метод расширения, который я написал для использования в командах данных:

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());

Где «products» - это IList <Product>, который вы хотите заполнить, а «GetProduct» содержит логику для создания экземпляра Product из устройства чтения данных. Это не поможет с этой конкретной проблемой отсутствия всех полей, но если вы делаете много старомодного ADO.NET, как это, это может быть очень удобно.

6
22.08.2008 12:26:37

Используйте GetSchemaTable()метод для получения метаданных DataReader. DataTable, Возвращаемые может быть использована для проверки , если определенный столбец присутствует или нет.

1
18.05.2013 01:47:56

Почему бы не сделать так, чтобы каждый sproc возвращал полный набор столбцов, используя ноль, -1 или допустимые значения, если у вас нет данных. Избегает необходимости перехватывать IndexOutOfRangeException или переписывать все в LinqToSql.

1
22.08.2008 12:30:26

Если вы не хотите использовать ORM, вы также можете использовать отражение для подобных вещей (хотя в этом случае, поскольку ProductID не назван одинаково с обеих сторон, вы не можете сделать это в упрощенном виде, продемонстрированном здесь): Список Провайдер в C #

0
22.08.2008 12:59:40

В итоге я написал свой собственный, но этот картограф довольно хорош (и прост): https://code.google.com/p/dapper-dot-net/

0
9.12.2013 16:56:58