I am wondering about the state of connection and impact on code performance by 'yield' while iterating over data reader object
下面是我用来从数据库中获取数据的示例代码:论刀层:
1 2 3 4 5 6 7 8 9 10 11 | 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层,我调用上面的方法,比如:
1 | List<IGridDataDto> GridDataDtos = MapMultiple(_costDriversGraphDao.GetGraphData(commonSearchCriteriaDto)).ToList(); |
在映射器层上,mapmultiple方法的定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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); } |
上面的代码运行良好,但是我想知道上面代码的两个问题。
如果您返回一个迭代器块,调用方可以决定什么是正常的;如果您总是返回一个列表,那么它们没有太多的选项。第三种方法(我们在dapper中做的)是选择它们的;我们有一个可选的
1 | bool buffered = true |
在参数中,和:
1 2 | var data = QueryInternal<T>(...blah...); return buffered ? data.ToList() : data; |
在实施中。在大多数情况下,返回一个列表是完全合理的,可以避免很多问题,因此我们将其设置为默认值。
How long data reader’s connection will be opened?
连接将保持打开,直到取消
When I consider code performance factor only, Is this a good idea to use
yield return instead of adding record into a list and returning the whole list?
这取决于几个因素:
- 如果您不打算获取整个结果,
yield return 将帮助您节省在网络上传输的数据量。 - 如果您不打算将返回的数据转换为对象,或者如果多行用于创建单个对象,
yield return 将帮助您节省在程序的峰值使用点使用的内存。 - 如果您计划在短时间内迭代Enture结果集,那么使用
yield return 不会受到性能惩罚。如果迭代将在多个并发线程上持续相当长的时间,那么RDBMS端打开的游标数可能会超过。
这个答案忽略了所示实现中的缺陷,并涵盖了一般的思想。
这是一种权衡——不知道系统的约束条件就无法判断这是否是一个好主意——您期望获得的数据量、您愿意接受的内存消耗、数据库的预期负载等等。