我正在调用具有多个结果集(总是2)的存储过程,并将结果写入单独的文件(以管道分隔格式)。我无法将结果集拆分为单独的存储过程。我正在使用IDataReader和IEnumerable在这个过程中保持尽可能少的内存。
是否有更简洁的方式来使用我的IEnumerable<IEnumerable<string>>
而不是使用GetEnumerator / MoveNext / Current来到内部IEnumerable<string>
传递给File.AppendAllLines?
public void Execute()
{
var reader = GetLines();
using (var enumerator = reader.GetEnumerator())
{
enumerator.MoveNext();
File.AppendAllLines("file1.dat", enumerator.Current);
enumerator.MoveNext();
File.AppendAllLines("file2.dat", enumerator.Current);
}
}
public IEnumerable<IEnumerable<string>> GetLines()
{
Database db = DatabaseFactory.CreateDatabase("connectionStringKey");
using (var command = db.GetStoredProcCommand("getdata_sp"))
{
var reader = db.ExecuteReader(command);
yield return GetInnerEnumerable(reader);
reader.NextResult();
yield return GetInnerEnumerable(reader);
}
}
private IEnumerable<string> GetInnerEnumerable(IDataReader reader)
{
while (reader.Read())
{
object[] rowValues = new object[reader.FieldCount];
reader.GetValues(rowValues);
yield return String.Join("|", rowValues);
}
}
答案 0 :(得分:5)
为什么不是foreach
循环?这是最基本的。
答案 1 :(得分:4)
就个人而言,我只会使用带有单独变量的foreach循环来跟踪要写入的文件,例如:
public void Execute()
{
var reader = GetLines();
int i = 0;
foreach (var inner in reader)
{
if (i % 2 == 0)
File.AppendAllLines("file1.dat", inner);
else
File.AppendAllLines("file2.dat", inner);
++i;
}
}
答案 2 :(得分:4)
您可以使用SelectMany()
来展平枚举,因为您只对值本身感兴趣。
修改:
根据评论SelectMany()
根据用例不适合,所以最好使用foreach
循环:
var reader = GetLines();
int index = 0;
foreach(var lines in reader)
File.AppendAllLines(string.Format("file{0}.dat", index++%2 + 1), lines);
答案 3 :(得分:2)
也许将GetLines()
的结果转换为数组并按索引访问它(因为你说总会有2个结果集)?
public void Execute()
{
IEnumerable<string>[] rows = GetLines().ToArray();
File.AppendAllLines("file1.dat", rows[0]);
File.AppendAllLines("file2.dat", rows[1]);
}
答案 4 :(得分:2)
我只想将GetLines
方法更改为以下
public IEnumerable<string> GetLines()
{
Database db = DatabaseFactory.CreateDatabase("connectionStringKey");
using (var command = db.GetStoredProcCommand("getdata_sp"))
{
var reader = db.ExecuteReader(command);
for (var i = 0; i < 2; i++)
{
foreach(var cur in GetInnerEnumerable(reader))
{
yield return cur;
}
reader.NextResult();
}
}
}
让它返回IEnumerable<IEnumerable<string>>
会给API的消费者带来不必要的负担。我的猜测是,他们都希望将此视为IEnumerable<string>
。
答案 5 :(得分:1)
foreach。所以:
public void Execute()
{
var reader = GetLines();
using (var enumerator = reader.GetEnumerator())
{
enumerator.MoveNext();
File.AppendAllLines("file1.dat", enumerator.Current);
enumerator.MoveNext();
File.AppendAllLines("file2.dat", enumerator.Current);
}
}
变为:
public void Execute()
{
var reader = GetLines();
int index = 0;
foreach (string line in reader)
{
if ((index % 2) == 0)
File.AppendAllLines("file1.dat", line);
else
File.AppendAllLines("file2.dat", line);
index++;
}
}
或者:
public void Execute()
{
var reader = GetLines();
var evenLines = reader.Where((str, i) => i % 2 == 0);
var oddLines = reader.Where((str, i) => i % 2 != 0);
foreach (string line in evenLines)
File.AppendAllLines("file1.dat", line);
foreach (string line in oddLines)
File.AppendAllLines("file2.dat", line);
}
答案 6 :(得分:0)
您可以将结果压缩为Tuple<>
,文件名如下:
using System.Linq;
using FileZip = System.Tuple<
System.String,
System.Collections.Generic.IEnumerable<
System.String>>;
public void Execute()
{
var files = new string[] { "file1.dat", "file2.dat" };
var results = GetLines();
foreach (var file in files.Zip(results, (f, r) => new FileZip(f, r)))
{
File.AppendAllLines(file.Item1, file.Item2);
}
}
当然,我很确定只要你返回不同数量的行就会抛出它,但它会做你正在寻找的东西。