3

リーダーデータをドメインオブジェクトにダンプするために必要な通常の退屈な「左/右」コーディングを行う「BuildEntity」と呼ばれる非常に単純なマッピング関数があります。(以下に表示)私の質問はこれです-このマッピングのすべての列をそのまま戻さないと、「System.IndexOutOfRangeException」例外が発生し、ado.netにこれを修正するものがあるかどうかを知りたいので、 SQLを呼び出すたびにすべての列を戻す必要があります...

私が本当に探しているのは「IsValidColumn」のようなものなので、DataAccessクラス全体でこの1つのマッピング関数を維持し、すべての左/右マッピングを定義できます。また、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
4

8 に答える 8

6

また、データコマンドで使用するために作成したこの拡張メソッドも確認してください。

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」にはデータリーダーからProductインスタンスを作成するロジックが含まれています。すべてのフィールドが存在しないというこの特定の問題には役立ちませんが、このような昔ながらのADO.NETをたくさん実行している場合は、非常に便利です。

于 2008-08-22T12:26:37.643 に答える
1

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

于 2008-08-22T12:28:59.757 に答える
1

データがない場合は、null、-1、または許容値を使用して、各sprocが完全な列セットを返すようにしないのはなぜですか。IndexOutOfRangeExceptionをキャッチしたり、LinqToSqlですべてを書き直したりする必要がなくなります。

于 2008-08-22T12:30:26.603 に答える
1

connection.GetSchema("Tables") はデータベース内のテーブルに関するメタ データを返しますが、カスタム列を定義すると、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

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

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

于 2008-08-25T14:25:40.497 に答える
0

LinqToSqlを使用してみませんか?必要なものはすべて自動的に実行されます。一般的にするために、.NET用の他のORMツールを使用できます。

于 2008-08-22T12:18:46.867 に答える
0

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

結果をに保存し、Dictionary<string, int>そのContainsKeyメソッドを使用して、フィールドが指定されているかどうかを判断できます。

于 2008-08-22T12:21:32.147 に答える
0

ORM を使用したくない場合は、次のようなものにリフレクションを使用することもできます (ただし、この場合、ProductID は両側で同じ名前ではないため、ここで示した単純な方法では実行できませんでした): リストC# のプロバイダー

于 2008-08-22T12:59:40.947 に答える