2008-08-22 2 views
3

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

Что я действительно ищу, это что-то вроде «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 

ответ

1

Хотя connection.GetSchema («Таблицы») делает возвращение мета данные о таблицах в базе данных, она не будет возвращать все в вашем sproc если определить пользовательские столбцы.

Например, если вы выбрали какой-то случайный ad-hoc-столбец, например * 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 

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

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

0

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

0

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

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

6

Также проверить эту extension method I wrote для использования данных команд:

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

1

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

1

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

0

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

Смежные вопросы