5

データベースから「asset」行を返すメソッドを書いています。文字列、int、バイト配列が含まれています(これは画像/映画/ドキュメントの場合があります)。

現在、ほとんどの行アクセスでは、次のメソッドを使用しています。これは、軽量オブジェクトであり、使いやすく、intと文字列をキャストできるためNameValueCollectionを返します。

        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を作成してから、最初のデータ行を返すのは、ちょっと無駄に思えます。

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

おそらくオブジェクトの辞書を考えており、それを手動で各メンバーにキャストします。

他の人がこれにどのように取り組んでいるかを見るのは興味深いでしょう。私はこれがマイクロ最適化の分野に該当することを知っています。各行クエリのデータセットを返さない限り(コード行でそれを見るたびにポンドがあればいいのですが)、問題ないはずです。

とはいえ、このメソッドは、1つのボックス上のサイトの割り当てに対するデータアクセスクエリの割り当てに対して呼び出される可能性があります。

乾杯

スティーブ

4

5 に答える 5

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

リーダーのGetxを介して値を取得していることに注意してください。ここで、xは列から取得するタイプです。これは、 http://msdn.microsoft.com/en-us/library/haa3afyz.aspx (2番目の段落)に従って列のデータを取得するためのMicrosoftの推奨方法です。これは、取得した値をSystem.Objectにボックス化する必要がないためです。箱から出してプリミティブ型にします。

このメソッドはASP.NETアプリケーションで何度も呼び出されるとおっしゃっていたので、このような一般的なアプローチを再検討することをお勧めします。NameValueCollectionを返すために使用するメソッドは、このシナリオ(およびおそらく他の多くのシナリオ)では非常にパフォーマンスが低くなります。言うまでもなく、現在のユーザーのカルチャを考慮せずに各データベース列を文字列に変換します。カルチャはASP.NETアプリケーションの重要な考慮事項です。このNameValueCollectionは、他の開発作業でも使用しないでください。私はこれについて何度も続けることができました、しかし私はあなたに私の暴言を救います。

もちろん、テーブルに直接マップするオブジェクトを作成する場合は、LINQtoSQLまたはADO.NETEntityFrameworkを調べることをお勧めます。あなたはあなたがしたことを幸せにするでしょう。

于 2009-04-16T18:16:58.490 に答える
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)
            };
        }
    }
}

同様に、同様の方法でデータをKVPのコレクションにダンプすることもできます...

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

コードの臭いに関する別の投稿で言及されているように、私はおそらくコマンドをパラメーターとして渡さないでしょう。データベース接続とのIDのみを渡して、このメソッド内にコマンドをカプセル化する可​​能性が高いと思います。私が欲しかったアセット-もちろんキャッシングを使用しなかったと仮定して、MyAssetインスタンスを渡します。これにより、メソッドは、任意のデータベースタイプで使用できるように十分に汎用的に保たれます。もちろん、ストアドプロシージャが存在することを前提としています。このようにして、コードの残りの部分は、データベースのタイプ以外のデータベースについて何も知る必要がなくなります...そして、アプリの残りの部分全体で、MyAssetInstance.ID、MyAssetInstance.Name、を使用してアセット情報を参照できます。 MyAssetInstance.Descriptionなど..

于 2009-04-16T17:56:58.850 に答える
2

あなたが示しているのは、PrimitiveObsessionと呼ばれるコードの臭いです。カスタムタイプを作成し、リポジトリメソッドから返します。過度に一般的であろうとしないでください...純粋に手続き型のコードを使用してエンティティと対話するため、ビジネスコードにその複雑さを押し込むことになります。ビジネスをモデル化するオブジェクトを作成することをお勧めします。

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

于 2009-04-16T17:55:57.730 に答える
0

単一行を返すことを最適化しようとするよりも、データをキャッシュすることではるかに多くのメリットが得られます。主キーで選択している場合は、DataTable、DataRow、またはカスタムオブジェクトを返すことに違いが見られる可能性はほとんどありません。これは時期尚早の最適化として私を襲います。私はもっ​​と明確になりますが、ミックスにバイト配列があると状況が変わるかどうかはわかりません。

于 2009-04-16T18:01:36.627 に答える
0

すべての入力者に感謝します。私はORMがおそらく進むべき道であることを知っています、そしてそれとMVCフレームワークは私のリストの次です。

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

mnero0429とbalabasterのコード例は私に正しい方向性を与えてくれると思います。データリーダーを使用して、中間オブジェクトをいじることなく、そのように手動でデータを取得します。詳細なMSリンクmnero0429をありがとう。原始的な執着について公正に-私は実際にビジネスレイヤーでそれから適切な資産クラスを作成します;)

ADOエンティティフレームワークについても調べます。

繰り返しになりますが、アドバイスに感謝します-DataSet.Tables [0] .Rows [0] ["bob"]などを使用したとしても、世界は変わり続けるでしょうが、そのかゆみを感じると、最高のワットは何ですかそれをしてください、それを引っかいてもらうのはいいことです!

于 2009-04-16T23:00:00.403 に答える