16

データベースからデータをフェッチするために使用しているサンプルコードは次のとおりです。DAOレイヤー上:

public IEnumerable<IDataRecord> GetDATA(ICommonSearchCriteriaDto commonSearchCriteriaDto)
{
    using(DbContext)
    {
        DbDataReader reader = DbContext.GetReader("ABC_PACKAGE.GET_DATA", oracleParams.ToArray(), CommandType.StoredProcedure);
        while (reader.Read())
        {
            yield return reader;
        }
    }
}

BOレイヤーでは、上記のメソッドを次のように呼び出しています。

List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList();

マッパーレイヤーのMapMultipleメソッドは次のように定義されます。

public IGridDataDto MapSingle(IDataRecord dataRecord)
{
    return new GridDataDto
    {
        Code = Convert.ToString(dataRecord["Code"]),
        Name = Convert.ToString(dataRecord["Name"]),
        Type = Convert.ToString(dataRecord["Type"])     
    };
}
public IEnumerable<IGridDataDto> MapMultiple(IEnumerable<IDataRecord> dataRecords)
{
    return dataRecords.Select(MapSingle);
}

上記のコードはうまく機能していますが、上記のコードに関する2つの懸念について疑問に思っています。

  1. データリーダーの接続はどのくらいの期間開かれますか?
  2. コードのパフォーマンス要因のみを考慮する場合、レコードをリストに追加してリスト全体を返すのではなく、「yield return」を使用することをお勧めしますか?
4

3 に答える 3

18
  1. コードには、接続を開いたり閉じたりする場所が表示されません。ただし、ここのリーダーは、実際にはデータを反復処理している間のみ開いています。遅延実行など。これを実行するコードのビットは、だけ.ToList()なので、問題ありません。より一般的なケースでは、そうです。リーダーは、反復するのにかかる時間だけ開いています。あなたがそれをするなら、.ToList()それは最小限になります。を実行しforeach、(すべてのアイテムに対して)外部httpリクエストを作成し、20秒待つと、はい-それはより長く開かれます。
  2. どちらにも用途があります。バッファなしのアプローチは、単一のメモリ内リストにロードする必要なしに(または一度にすべてをメモリ内に保持することなく)、ストリームとして処理したい巨大な結果に最適です。リストを返すと、接続がすばやく閉じられ、リーダーが既に開いているときに誤って接続を使用することを簡単に回避できますが、大規模な結果には理想的ではありません。

イテレータブロックを返すと、呼び出し元は何が正常であるかを判断できます。常にリストを返す場合、それらには多くのオプションがありません。3番目の方法(dapperで行う)は、選択を彼らのものにすることです。boolデフォルトで「リストを返す」というオプションのパラメーターがありますが、呼び出し元は「イテレーター・ブロックを返す」ことを示すために変更できます。基本的に:

bool buffered = true

パラメータ内、および:

var data = QueryInternal<T>(...blah...);
return buffered ? data.ToList() : data;

実装で。ほとんどの場合、リストを返すことは完全に合理的であり、多くの問題を回避するため、これをデフォルトにします。

于 2013-03-13T09:54:29.180 に答える
4

データリーダーの接続はどのくらいの期間開かれますか?

接続は、が解除されるまで開いたままreaderになります。つまり、反復が終了するまで開いたままになります。

コードのパフォーマンス要因のみを考慮する場合、これは、yield returnレコードをリストに追加してリスト全体を返す代わりに使用することをお勧めしますか?

これはいくつかの要因に依存します:

  • 結果全体を取得する予定がない場合はyield return、ネットワーク上で転送されるデータの量を節約するのに役立ちます
  • 返されたデータをオブジェクトに変換する予定がない場合、または複数の行を使用して単一のオブジェクトを作成する場合 yield returnは、プログラムのピーク使用ポイントで使用されるメモリを節約するのに役立ちます
  • エンチャー結果セットを短期間で反復する場合は、を使用してもパフォーマンスが低下することはありませんyield return。複数の同時スレッドで反復がかなりの時間続く場合は、RDBMS側で開いているカーソルの数を超える可能性があります。
于 2013-03-13T09:56:04.767 に答える
0

この回答は、示されている実装の欠陥を無視し、一般的な考え方をカバーしています。

これはトレードオフです-システムの制約を知らずにそれが良い考えであるかどうかを判断することは不可能です-あなたが得ると期待するデータの量、あなたが受け入れることをいとわないメモリ消費、データベースの予想される負荷、等

于 2013-03-13T09:56:49.497 に答える