2009-04-16 11 views
5

私はデータベースから「資産」行を返すメソッドを作成しています。文字列、整数、バイト配列(これはイメージ/ムービー/ドキュメントのこともあります)を含みます。ASP.NETで最も効率的なデータをデータベースから取得する

ほとんどの行アクセスでは、LightValueCollectionを軽量オブジェクトとして使用し、intとstringを使いやすくキャストするため、次のメソッドを使用します。

 public static NameValueCollection ReturnNameValueCollection(Database db, DbCommand dbCommand) 
    { 

     var nvc = new NameValueCollection(); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
     { 
      if (dr != null) 
      { 
       while (dr.Read()) 
       { 
        for (int count = 0; count < dr.FieldCount; count++) 
        { 
         nvc[dr.GetName(count)] = dr.GetValue(count).ToString(); 
        } 
       } 
      } 
     } 

     dbCommand.Dispose(); 
     return nvc.Count != 0 ? nvc : null; 
    } 

このようなデータアクセスのための私のアプローチは、通常、データローを返すメソッドを取得することです。

 public static DataRow ReturnDataRow(Database db, DbCommand dbCommand) 
    { 
     var dt = new DataTable(); 

     using (IDataReader dr = db.ExecuteReader(dbCommand)) 
      if (dr != null) dt.Load(dr); 

     dbCommand.Dispose(); 
     return dt.Rows.Count != 0 ? dt.Rows[0] : null; 
    } 

DataTableを作成して最初のデータローを返すのは無駄です。

これを行うより良い方法はありますか?

私は多分、各メンバーを手動でキャストするオブジェクトの辞書を考えています。

他の人たちがこれにどのように取り組んできたのか興味深いでしょう。私はこのようなものがマイクロ最適化の分野に入ることを知っています。そして、各行のクエリに対してDataSetsを返さない限り(コード行でそれを確認するたびにポンドがあることを祈ってください)、それは問題ありません。

これは、この方法は、1つのボックス内のサイトに割り当てられたデータアクセスクエリに割り当てられていると言われています。

あなたはdemonstartingているもの乾杯

スティーブ

+1

ちょっとした問題ですが、呼び出し元はデータの読み取り方法ではなく、DbCommand.Disposeメソッドを呼び出す必要があります。あなたの呼び出し元がdbCommandオブジェクトを提供して以来、それはそれを処理する必要があります。 –

答えて

7

どうなっていますか?

データベースに行を表すオブジェクトコンテナがない理由はありますか?カスタムオブジェクトの作成は、ソリューションの他の層で処理するほうが簡単です。このアプローチでは、問題に対して2つの非常に実行可能な解決策があります。

データベース内の製品を表すカスタムオブジェクトがあるとします。あなたは、このようなオブジェクトを定義したい:

public class Product { 
    public int ProductID { get; set; } 
    public string Name { get; set; } 
    public byte[] Image { get; set; } 
} 

をそして、あなたは、このような製品(コレクション)のコレクションを埋めるだろう:私は読者のを経由して値を取得しています

var collection = new Collection<Product>(); 

using (var reader = command.ExecuteReader()) { 
    while (reader.Read()) { 
     var product = new Product(); 

     int ordinal = reader.GetOrdinal("ProductID"); 
     if (!reader.IsDBNull(ordinal) { 
      product.ProductID = reader.GetInt32(ordinal); 
     } 

     ordinal = reader.GetOrdinal("Name"); 
     if (!reader.IsDBNull(ordinal)) { 
      product.Name = reader.GetString(ordinal); 
     } 

     ordinal = reader.GetOrdinal("Image"); 
     if (!reader.IsDBNull(ordinal)) { 
      var sqlBytes = reader.GetSqlBytes(ordinal); 
      product.Image = sqlBytes.Value; 
     } 

     collection.Add(product); 
    } 
} 

お知らせ xを取得します。 xは、列から取得するタイプです。 http://msdn.microsoft.com/en-us/library/haa3afyz.aspx(2番目の段落)の列のデータを取得する方法はMicrosoftが推奨しています。これは、取得した値をSystem.Objectにボックス化してプリミティブ型にボックス化しないためです。

この方法は、ASP.NETアプリケーションで何度も何度も呼び出されると述べているので、このような一般的なアプローチを再検討することをお勧めします。 NameValueCollectionを返すために使用するメソッドは、このシナリオでは(そして恐らく他の多くのシナリオでは)非常に機能しません。現在のユーザーのCultureを考慮せずに各データベース列を文字列に変換することはもちろん、CultureはASP.NETアプリケーションで重要な考慮事項です。私はこの NameValueCollectionを他の開発努力にも使用すべきではないと主張します。私はこれについて続けていくことができますが、私はあなたの暴言を救います。

もちろん、テーブルに直接マップするオブジェクトを作成する場合は、LINQ to SQLまたはADO.NET Entity Frameworkも参照してください。あなたはあなたが幸せになるでしょう。

+0

+1私は読者に気付かなかったので、+1してください。 – BenAlabaster

2

Primitive Obsessionと呼ばれるコードのにおいです。カスタム型を作成し、それをリポジトリメソッドから返します。あまりにも一般的なことをしようとしないでください...純粋に手続き型コードを使用してあなたのエンティティと対話するので、あなたは複雑さをあなたのビジネスコードにプッシュするだけです。ビジネスをモデル化するオブジェクトを作成する方がよいでしょう。

データアクセスコードが多すぎる場合は、ORMフレームワークを使用してこれを生成してください。この懸念がアプリケーション層での悪い設計を指示するようにしてはいけません。

3

コード効率の面では、少なくともキーストロークでやったことがありますが、無駄に思えるかもしれませんが、おそらく最も単純なものです。同様に、あなたがデータをダンプすることができ

public class MyAsset 
{ 
    public int ID; 
    public string Name; 
    public string Description; 
} 

public MyAsset GetAsset(IDBConnection con, Int AssetId) 
{ 
    using (var cmd = con.CreateCommand("sp_GetAsset")) 
    { 
     cmd.CommandType = CommandType.StoredProcedure; 
     cmd.Parameters.Add(cmd.CreateParameter("AssetID")); 
     using(IDataReader dr = cmd.ExecuteReader()) 
     { 
      if (!dr.Read()) return null; 

      return new MyAsset() { 
       ID = dr.GetInt32(0), 
       Name = dr.GetString(1), 
       Description = dr.GetString(2) 
      }; 
     } 
    } 
} 

:あなたはすべての唯一の厳密に必要である何をしての効率についてならしかし、あなたはデータを取り込むと同様のものを使用した軽量構造体/クラスを作成することができます持っているように、右KVPsのあなたのコレクションに同様の方法...

は、それはあなたの元のコードのように見ているほどきれいではないですが、それだけで単一の行を取得するために全体のテーブルを作成しません...

しかし、コードの匂いに関する別の記事で言及されている、私はおそらくパラメータとしてコマンドを渡すことはない、私はこのメソッドの中にコマンドをカプセル化し、私が望んだアセットのIDとデータベース接続だけを渡す可能性が高くなりました。私はもちろんキャッシングを使わず、MyAssetインスタンスを返すと仮定します。これにより、ストアドプロシージャが存在していると仮定して、どのデータベースタイプでも使用できるようにメソッドを汎用的に保ちます。この方法で、私のコードの残りの部分は、それがどんなタイプのデータベースであるか以外にデータベースについて何かを知る必要がなくなります...私のアプリケーションの残りの部分では、MyAssetInstance.ID、MyAssetInstance.Name、MyAssetInstance.Descriptionなどを使用してアセット情報を参照できます。

0

単一の行を返すように最適化しようとするよりも、 。プライマリキーで選択している場合は、DataTableまたはDataRowまたはカスタムオブジェクトを返すことに違いはありません。これは早すぎる最適化として私を襲う。私はより明確なはずですが、ミックスの中にバイト配列を持つことで変更があるかどうかはわかりません。

0

すべての入力ユーザーに感謝します。私はORMがおそらく行く方法であることを知っています。そしてMVCフレームワークは私のリストの次にあります。

もう少し詳しく説明すると、データアクセスレイヤーのヘルパーセクションからコードが表示され、行または名前の値コレクションをビジネスレイヤーに渡してオブジェクトに変換します。

私はmnero0429とバラバスターのコード例が私に正しい方向を与えると思います。 datareaderを使用して、手作業でオブジェクトを混乱させることなく、手動でデータを取得します。詳細なMSリンクmnero0429をありがとう。私は実際にビジネス層で適切な資産クラスを作っています;)

私はADOエンティティフレームワークについても検討しています。

もう一度、アドバイスをいただきありがとうございます。私はDataSet.Tables [0]を使用しても世界が変わっていくことはわかっています。行[0] ["ボブ"]またはそのようなものが、あなたがそのかゆみを得るとき - それを行うには最高のワットは何ですか、それを傷つけていいです!

関連する問題