Сведения о вопросе

Faridun

07:35, 24th August, 2020

Теги

ado.net    

ADO.NET отображение из SQLDataReader в объект домена?

Просмотров: 437   Ответов: 8

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

То, что я действительно ищу, - это что-то вроде "IsValidColumn", поэтому я могу сохранить эту функцию 1 mapping в своем классе 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



  Сведения об ответе

darknet

21:06, 1st October, 2020

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

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


  Сведения об ответе

ЯЯ__4

18:38, 8th August, 2020

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


  Сведения об ответе

LAST

16:40, 13th August, 2020

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


  Сведения об ответе

KOMP

21:26, 3rd August, 2020

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

Например, если вы добавите какой-нибудь случайный специальный столбец, например *SELECT ProductName,'Testing' как 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

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

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


  Сведения об ответе

prince

21:36, 29th August, 2020

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


  Сведения об ответе

KOMP

20:07, 8th August, 2020

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

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


  Сведения об ответе

ASSembler

21:26, 6th August, 2020

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


  Сведения об ответе

$DOLLAR

20:00, 9th August, 2020

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


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться