我有一个在NHibernate 3.0中使用Linq到NHibernate的asp.net Web应用程序。
在一个函数中,我需要从一个包含1000列记录和20列的表中获取大约20000条记录。
我正在使用Session.QueryOver<>()方法来获取记录。
功能代码是:
public IList<BatchDetails> GetBatchRecordsOnBatchId_BatchSize(int batchId,int stratingRowdId,int batchSize)
{
// If the stratingRowdId will be 0 than frist count of the Batch Records equivlent to the batchSize will be return
//If the batchSize will be 0 than all the Batch Records starting from the RowId equivlent to the stratingRowdId will be return
// If both the stratingRowdId & batchSize are 0 than all the BatchReocrds for the BatchId will be return
if (batchId <= 0)
{
throw new ArgumentException();
}
using (var session = _sessionFactory.OpenSession())
{
using (var transaction = session.BeginTransaction())
{
try
{
//Get Batch data from the Database for the BatchId
var batchData = from batchRecords in session.QueryOver<BatchDetails>()
.Where(x => x.BatchId == batchId)
.List().Skip(stratingRowdId).Take(batchSize)
select batchRecords
;
transaction.Commit();
return batchData.ToList();
}
catch (ArgumentException ex)
{
if (transaction != null) transaction.Rollback();
throw;
}
catch (Exception exception)
{
if (transaction != null) transaction.Rollback();
throw;
}
finally
{
session.Flush();
}
}
}
}
此代码正在运行,直到该表有2个lac记录。
但是在表中添加了10个lac记录后,此方法会抛出错误:
NHibernate.Util.ADOExceptionReporter |抛出了'System.OutOfMemoryException'类型的异常。
NHibernate.Util.ADOExceptionReporter |抛出了'System.OutOfMemoryException'类型的异常。
NHibernate.Util.ADOExceptionReporter |抛出了'System.OutOfMemoryException'类型的异常。
[DAL.GetBatchRecordsOnBatchId]:应用程序中出现未保留错误,异常:无法执行查询 [将this_.ReferenceId选为Referenc1_2_0_,this_.AccountNumber为AccountN2_2_0_,this_.AccountStatus为AccountS3_2_0_,this_.AccountType为AccountT4_2_0_,this_.AccountSubType为AccountS5_2_0_,this_.AccountDescription为AccountD6_2_0_,this_.ActivationDate为Activati7_2_0_,this_.CombinedBilling为Combined8_2_0_, this_.PlanAmount为PlanAmount2_0_,this_.PlanCode为PlanCode2_0_,this_.CustomerName为Custome11_2_0_,this_.CustomerEmail为Custome12_2_0_,this_.CustomerPhone为Custome13_2_0_,this_.CustomerAddress为Custome14_2_0_,this_.CustomerCity为Custome15_2_0_,this_.CustomerState为Custome16_2_0_,this_。 CustomerZipCode为Custome17_2_0_,this_.PaymentAmount为Payment18_2_0_,this_.PaymentCurrency为Payment19_2_0_,this_.PaymentDate为Payment20_2_0_,this_.TransactionId为Transac21_2_0_,this_.BatchId为BatchId2_0_ FROM TIOTestDB.dbo.BatchDetails this_ WHERE this_.BatchId =? ] 位置参数:#0&gt; 3 [SQL:选择this_.RefereId作为Referenc1_2_0_,this_.AccNumber作为AccountN2_2_0_,this_.AcStatus作为AccountS3_2_0_,this_.AcType作为AccountT4_2_0_,this_.AccSubType作为AccountS5_2_0_,this_.AccountDescription作为AccountD6_2_0_,this_.ActivationDate作为Activati7_2_0_,this_.CombinedBilling as Combined8_2_0_,this_.PlanAmount为PlanAmount2_0_,this_.PlanCode为PlanCode2_0_,this_.CustomerName为Custome11_2_0_,this_.Email为Custome12_2_0_,this_.Phone为Custome13_2_0_,this_.Address为Custome14_2_0_,this_.City为Custome15_2_0_,this_.State为Custome16_2_0_, this_.ZipCode为Custome17_2_0_,this_.PayAmount为Payment18_2_0_,this_.Currency为Payment19_2_0_,this_.PayDate为Payment20_2_0_,this_.TransactionId为Transac21_2_0_,this_.bhId为bhId2_0_ FROM bDetails this_ WHERE this_.bhId =?]
因为我在foreach()迭代中执行此函数, 虽然查询执行1或2次并检索数据但在此之后它会抛出内存不足异常。
作为一名经验丰富的NHibernate开发人员,我可以理解我需要重构LINQ查询以优化其性能。
我也在互联网上搜索过但我无法获得太多信息。
最早的回复将不胜感激。
答案 0 :(得分:3)
首先,您的查询:
from batchRecords in session.QueryOver<BatchDetails>()
.Where(x => x.BatchId == batchId)
.List().Skip(stratingRowdId).Take(batchSize)
select batchRecords
可以简化为:
session.QueryOver<BatchDetails>()
.Where(x => x.BatchId == batchId)
.List().Skip(stratingRowdId).Take(batchSize)
它的行为完全相同。您的from
和select
所做的就是在查询末尾添加.Select(x => x)
。
现在,您的问题是您过早地致电List()
。 List()
的作用是将查询的所有结果检索到内存中。如果之后使用LINQ方法(就像使用Skip()
和Take()
那样),它们将在内存中执行,这不是你想要的。
您应该做的是将List()
移到查询的末尾:
session.QueryOver<BatchDetails>()
.Where(x => x.BatchId == batchId)
.Skip(stratingRowdId).Take(batchSize)
.List()
这样,Skip()
和Take()
都将被转换为SQL,这意味着您不会将所有数据都检索到内存中,只检索您实际需要的数据。这应该可以修复你的OOM。