我需要允许Intranet .NET Web门户用户将自由文本SQL查询发送到后端(SQL Server 2014上的只读数据库)并在Excel中获取结果,但是在大多数情况下,这种方法都可以正常工作但是当结果太大(大约350mb,250k记录)而无法处理时,代码将失败。
我的第一个尝试是直接将结果作为JSON序列化到前端的数据表中。
之所以失败,是因为遍历结果集会抛出System.OutOfMemoryException
:
private JavaScriptSerializer _serializer;
return _serializer.Serialize(results));
因此决定直接在界面上显示此结果数量不是一件好事,因为IE会遇到困难。因此选择了提示用户通过将结果保存到JSON文件中来下载输出的Excel副本的选项,然后读取该文件并将其转换为Excel:
using (StreamReader sr = new StreamReader(filePath))
String json;
// Read and display lines from the file until the end of
// the file is reached.
while ((json = sr.ReadLine()) != null)
{
Console.WriteLine(json);}
}
但是,ReadLine()方法会引发相同的异常,请注意,由于文件仅包含一行,因此ReadLine失败,否则我将尝试逐行进行迭代。 / p>
最后我尝试直接访问IEnumerable并将其写入Excel
var results = new ReportProcess().ExecuteSql(sqlQuery, out string eventMessage);
List<object> queryObjects = new List<object>();
foreach (var result in results)
{
queryObjects.Add(result);
}
var row = queryObjects.FirstOrDefault();
if (row != null)
{
var recordType = row.GetType();
using (var excelFile = new ExcelPackage())
{
MemberInfo[] membersToInclude = recordType
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.ToArray();
var worksheet = excelFile.Workbook.Worksheets.Add("Sheet1");
worksheet.Cells.LoadFromCollection(queryObjects, true,
OfficeOpenXml.Table.TableStyles.None,
BindingFlags.Instance | BindingFlags.Public,
membersToInclude);
fileName = Guid.NewGuid() + ".xlsx";
excelFile.SaveAs(new FileInfo(HttpContext.Current.Server.MapPath("~/temp/") + fileName));
}
}
代码再次失败
foreach (var result in results)
{
queryObjects.Add(result);
}
有同样的例外
因此,现在我陷入了一个事实,即无论我尝试执行什么操作来遍历IEnumerable
结果,我总是会遇到OutOfMemory异常。
我还尝试通过将gcAllowVeryLargeObjects
中的web.config
设置为true来增加分配给对象的内存,但无济于事:
<runtime>
<gcAllowVeryLargeObjects enabled="true"/>
</runtime>
其他尝试:
Google搜索没有带来任何解决问题的方法,没有任何建议/想法吗?
答案 0 :(得分:0)
最终,我不得不重写代码以实现外部库,以使用CsvHelper
库
using (StreamReader sr = new StreamReader(filePath))
{
var csvReader = new CsvReader(sr);
var records = csvReader.GetRecords<object>();
var result = string.Empty;
try
{
return JsonConvert.SerializeObject(new ServerData(records, _eventMessage));
}
catch (Exception ex)
{
_eventMessage.Level = EventMessage.EventLevel.Error;
}
return _serializer.Serialize(new ServerData(result, _eventMessage));
}
这似乎适用于大型数据集,OutOfMemory
不再出现异常