У меня есть очень простая функция сопоставления под названием «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





Почему бы вам не использовать LinqToSql - все, что вам нужно, делается автоматически. Для наглядности вы можете использовать любой другой Инструмент ORM для .NET.
Я бы назвал reader.GetOrdinal для каждого имени поля перед запуском цикла while. К сожалению, GetOrdinal выдает IndexOutOfRangeException, если поле не существует, поэтому оно не будет очень эффективным.
Вероятно, вы могли бы сохранить результаты в Dictionary<string, int> и использовать его метод ContainsKey, чтобы определить, было ли указано поле.
Также проверьте этот метод расширения, который я написал для использования в командах данных:
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
Используйте метод GetSchemaTable() для получения метаданных DataReader. Возвращаемый DataTable может использоваться для проверки наличия определенного столбца.
Почему бы просто не сделать так, чтобы каждый sproc возвращал полный набор столбцов с использованием null, -1 или допустимых значений, если у вас нет данных. Избегает необходимости перехватывать исключение IndexOutOfRangeException или переписывать все в LinqToSql.
Если вы не хотите использовать ORM, вы также можете использовать отражение для таких вещей (хотя в этом случае, поскольку ProductID не имеет одинакового названия с обеих сторон, вы не можете сделать это упрощенным способом, продемонстрированным здесь): Поставщик списков в C#
Хотя connection.GetSchema («Таблицы») действительно возвращает метаданные о таблицах в вашей базе данных, он не вернет все в вашем sproc, если вы определите какие-либо настраиваемые столбцы.
Например, если вы добавите какой-то случайный специальный столбец, например * SELECT ProductName, «Testing» As ProductTestName FROM dbo.Products », вы не увидите« ProductTestName »в качестве столбца, потому что его нет в схеме таблицы Products. Чтобы решить эту проблему и запросить каждый столбец, доступный в возвращаемых данных, используйте метод объекта 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
Честно говоря, это хитрость, поскольку вы должен возвращаете каждый столбец, чтобы правильно гидратировать ваш объект. Но я подумал включить этот метод чтения, поскольку он фактически захватит все столбцы, даже если они не определены в вашей схеме таблицы.
Такой подход к отображению ваших реляционных данных в модель предметной области может вызвать некоторые проблемы, когда вы попадаете в сценарий отложенной загрузки.
В итоге я написал свой, но этот картограф довольно хороший (и простой): https://code.google.com/p/dapper-dot-net/