我想知道在迭代数据读取器对象时,'yield'的连接状态和对代码性能的影响

San*_*Rai 16 c# linq using datareader yield-return

这是我用来从数据库中获取数据的示例代码:在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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

在BO层我调用上面的方法,如:

List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList();
Run Code Online (Sandbox Code Playgroud)

在mapper层上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);
}
Run Code Online (Sandbox Code Playgroud)

上面的代码运行良好,但我想知道上述代码的两个问题.

  1. 数据阅读器的连接将打开多长时间?
  2. 当我只考虑代码性能因素时,使用'yield return'而不​​是将记录添加到列表并返回整个列表是一个好主意吗?

Mar*_*ell 15

  1. 您的代码不会显示您打开/关闭连接的位置; 但是这里的读者实际上只有在你迭代数据时才会打开.延迟执行等等.执行此操作的代码的唯一位是.ToList(),所以它会没事的.在更一般的情况下,是的:读者将花费你花费的时间来迭代它; 如果你这样做.ToList()会很少; 如果你做了一个foreach和(对于每个项目)发出外部http请求并等待20秒,那么是 - 它将打开更长时间.
  2. 两者都有它们的用途; 非缓冲的办法是伟大的,你要处理的数据流庞大的结果,而不必加载到一个在内存中的列表(或者甚至所有的人都在内存中一次); 返回列表可以快速关闭连接,并且在已经有一个打开的阅读器时可以很容易地避免意外使用连接,但对于大结果却不太理想

如果你返回一个迭代器块,调用者可以决定什么是理智的; 如果你总是返回一个列表,他们没有太多选择.第三种方式(我们在短小精悍的做法)是做出他们的选择; 我们有一个可选bool参数,默认为"返回一个列表",但调用者可以更改它以指示"返回迭代器块"; 基本上:

bool buffered = true
Run Code Online (Sandbox Code Playgroud)

在参数中,和:

var data = QueryInternal<T>(...blah...);
return buffered ? data.ToList() : data;
Run Code Online (Sandbox Code Playgroud)

在实施中.在大多数情况下,返回列表是完全合理的,并避免了很多问题,因此我们将其作为默认值.