Сопоставление 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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
0
7 067
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

Используйте метод 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/

Другие вопросы по теме