我正在尝试将文件导入数据库,并在此过程中学习更有效的方法。 This article建议链接枚举产生低内存使用率和良好性能。 这是我第一次链接几个枚举,我不太确定如何正确处理重置......
短篇小说:
我有一个枚举,它从文本文件中读取并映射到DTO(参见Map函数),Where枚举器,然后是一个带枚举的Import ...除了当过滤器返回0记录时,它都完美地工作...在这种情况下,SQL错误说System.ArgumentException: There are no records in the SqlDataRecord enumeration.
...
所以我在我的Import方法的顶部放了一个if(!list.Any()) return;
,它似乎没有错误。除了它将始终跳过文本文件中第一个有效行的所有行(包括)...
在Any()调用之后,我是否需要以某种方式重置()枚举器?当在Linq和其他Enumerable实现中使用相同的结构时,为什么这不是必需的?
代码:
public IEnumerable<DTO> Map(TextReader sr)
{
while (null != (line = sr.ReadLine()))
{
var dto = new DTO();
var row = line.Split('\t');
// ... mapping logic goes here ...
yield return (T)obj;
}
}
//Filter, called elsewhere
list.Where(x => Valid(x)).Select(x => LoadSqlRecord(x))
public void Import(IEnumerable<SqlDataRecord> list)
{
using (var conn = new SqlConnection(...))
{
if (conn.State != ConnectionState.Open)
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandText = "Import_Data";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
var parm = new SqlParameter();
cmd.Parameters.Add(parm);
parm.ParameterName = "Data"
parm.TypeName = "udt_DTO";
parm.SqlDbType = SqlDbType.Structured;
parm.Value = list;
cmd.ExecuteNonQuery();
conn.Close();
}
}
很抱歉这个长长的例子。谢谢你的阅读...
答案 0 :(得分:1)
您看到的问题可能不是因为IEnumerable
/ IEnumerator
接口,而是因为您使用的基础资源来生成值。
对于大多数枚举,添加list.Any()
不会导致将来list
的枚举跳过项,因为每次调用list.GetEnumerator
都会返回独立的对象。您可能有其他原因不想创建多个枚举器,例如通过LINQ to SQL多次调用数据库,但每个枚举器都会获取所有项目。
但是,在这种情况下,由于底层资源,使多个枚举器无法工作。根据您发布的代码,我假设传递给Import
的参数基于您发布的Map
方法的调用。每次通过Map返回的可枚举时,您将在方法的顶部“开始”,但TextReader及其当前位置在所有枚举器之间共享。即使您尝试在IEnumerators上调用Reset,也不会重置TextReader。要解决您的问题,您需要缓冲可枚举(例如ToList)或找到重置TextReader的方法。