データベースからデータをフェッチするために使用しているサンプルコードは次のとおりです。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つの懸念について疑問に思っています。
.ToList()
だけなので、問題ありません。より一般的なケースでは、はい。リーダーは、反復するのにかかる時間だけ開いています。 .ToList()
を実行すると最小限になります。 foreach
を実行し、(すべてのアイテムに対して)外部httpリクエストを作成して20秒待つと、はい-それはより長く開かれます。イテレータブロックを返すと、呼び出し元は何が正常であるかを判断できます。常にリストを返す場合、それらには多くのオプションがありません。 3番目の方法(dapperで行う)は、選択を彼らのものにすることです。オプションのbool
パラメータがあり、デフォルトは「リストを返す」ですが、呼び出し元は「イテレータブロックを返す」ことを示すように変更できます。基本的に:
bool buffered = true
パラメータ内、および:
var data = QueryInternal<T>(...blah...);
return buffered ? data.ToList() : data;
実装で。ほとんどの場合、リストを返すことは完全に合理的であり、多くの問題を回避するため、これをデフォルトにします。
データリーダーの接続はどのくらいの期間開かれますか?
接続は、reader
が閉じられるまで開いたままになります。つまり、反復が終了するまで開いたままになります。
コードのパフォーマンス係数のみを考慮する場合、レコードをリストに追加してリスト全体を返す代わりに、
yield return
を使用することをお勧めしますか?
これはいくつかの要因に依存します:
yield return
を使用するとネットワーク上で転送されるデータの量を節約できます。yield return
は、プログラムのピーク使用ポイントで使用されるメモリを節約するのに役立ちますyield return
を使用してもパフォーマンスが低下することはありません。複数の同時スレッドで反復がかなりの時間続く場合、RDBMS側で開いているカーソルの数を超える可能性があります。この回答は、示されている実装の欠陥を無視し、一般的な考え方をカバーしています。
これはトレードオフです-システムの制約を知らずにそれが良い考えであるかどうかを判断することは不可能です-あなたが得ると期待するデータの量、あなたが受け入れることをいとわないメモリ消費、データベースの予想される負荷、等