2008-08-22 17 views
3

私は "BuildEntity"と呼ばれる非常に単純なマッピング関数を持っています。これは、読者データを自分のドメインオブジェクトにダンプするのに必要な通常の退屈な "左/右"コーディングを行います。私はこのマッピングのすべての列を元に戻すことができない場合、 "System.IndexOutOfRangeException"例外を取得し、ado.netにこれを修正する何かがあるかどうかを知りたいと思ったので、すべての列をSQLに呼び出すたびにすべての列を返す必要があります...ADO.NET SQLDataReaderからドメインオブジェクトへのマッピング?

私が実際に探しているのは「IsValidColumn」のようなものなので、DataAccessクラス全体でこの1のマッピング機能をすべての左/右定義されたマッピング - とのSPROCが記載されているすべての列が返されない場合でも、それが機能している...あなたがLinqToSqlを使用していないのはなぜ

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

データベースのテーブルに関するメタデータを返しますが、カスタム列を定義すると、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 

これは、あなたが正しくオブジェクトを水和するすべての列を返さなければならないとして、正直に言うとハックです。しかし、私はテーブルスキーマで定義されていなくても、実際にすべての列を取得するので、このリーダーメソッドを含めることを考えました。

リレーショナルデータをドメインモデルにマッピングするこのアプローチは、遅延読み込みシナリオに入るといくつかの問題を引き起こす可能性があります。

0

- あなたが必要なすべてのものが自動的に行われます。一般的な目的のために、ORM tool for .NETを使用することができます。

0

whileループを開始する前に、フィールド名ごとにreader.GetOrdinalを呼び出します。フィールドが存在しない場合、残念ながらGetOrdinalIndexOutOfRangeExceptionをスローします。そのため、パフォーマンスはあまり高くありません。

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

あなたはこのようにそれを使用することができます:あなたが移入したい「製品は、」IListの<製品>ある

cmd.Fill(products, r => r.GetProduct()); 

「GetProduct」には、データ・リーダーからProductインスタンスを作成するロジックが含まれています。すべてのフィールドが存在しないというこの特定の問題には役立ちませんが、このような昔ながらのADO.NETを多用している場合は、非常に便利です。

1

DataReaderのメタデータを取得するためにGetSchemaTable()メソッドを使用します。返されるDataTableは、特定の列が存在するかどうかを確認するために使用できます。

1

はなぜ、それぞれが完全な列セットは、nullを使用して、-1、またはあなたがデータを持っていない許容値を返すSPROC持っていません。 IndexOutOfRangeExceptionを捕まえたり、LinqToSqlのすべてを書き直す必要はありません。

0

あなたは商品コードが両側で同じ名前が付いていないので、あなたがこの場合にもかかわらず、このようなもの(のためにリフレクションを使用することができますORMを使用したくない場合は、示された単純なやり方でそれを行うことができませんでしたここでは: List Provider in C#

関連する問題