2011-05-03 56 views
2

我使用ayende這裏提出的方法:使用NHibernate流式傳輸大型結果集實際上工作嗎?

http://ayende.com/Blog/archive/2010/06/27/nhibernate-streaming-large-result-sets.aspx

的SQL Server 2005與NHibernate 3.0。

我的測試(試圖用10,000,000項流式傳輸結果集)表明結果沒有被流式傳輸(看來整個結果集首先被加載到內存中)。

我該如何得到這個工作?我將接受任何允許在NHibernate中傳輸結果集的解決方案,它不一定非得是ayende的解決方案。

+0

一些ADO.Net緩存結果在內存中,不知道是否該建在不 – Firo 2011-12-08 12:19:20

回答

1

Ayende這樣說:

我們仍然有內存消耗的問題,雖然。會話 將跟蹤所有加載的對象,並且如果我們加載了大量的數據,它將最終以內存不足異常的形式出現。

這很可能是原因。你確定會話不跟蹤對象嗎?嘗試選擇不是實體,但他們的一些成員來測試這一點。

+0

是的,我已經驗證,本次會議沒有跟蹤的對象。 NHibernate在將任何結果返回給調用方法之前,從數據庫中檢索整個結果集非常清楚。我認爲NHibernate只是這類工作的錯誤工具,所以我已經遷移到使用Dapper進行這些類型的操作。 – jason 2013-05-29 01:25:01

1

您可以從LINQ的與NH 4.0.0.4000以下擴展方法流結果(如果你不喜歡的反射黑客傳遞ISessionImplementor):

public static EnumerableImpl Stream<T>(this IQueryable<T> source) 
{ 
    var provider = ((NhQueryable<T>) source).Provider as DefaultQueryProvider; 
    var sessionImpl = (ISessionImplementor)provider.GetType() 
     .GetProperty("Session", BindingFlags.NonPublic | 
      BindingFlags.Instance).GetValue(provider); 
    var expression = new NhLinqExpression(source.Expression, sessionImpl.Factory); 
    var query = sessionImpl.CreateQuery(expression); 
    query.SetParameters(expression.ParameterValuesByName); 
    provider.SetResultTransformerAndAdditionalCriteria(
     query, expression, expression.ParameterValuesByName); 
    return (EnumerableImpl)((AbstractQueryImpl2)query).Enumerable(); 
} 

private static void SetParameters(this IQuery query, 
    IDictionary<string, Tuple<object, IType>> parameters) 
{ 
    foreach (var parameterName in query.NamedParameters) 
    { 
     var param = parameters[parameterName]; 
     if (param.Item1 == null) 
     { 
      if (typeof(IEnumerable).IsAssignableFrom(param.Item2.ReturnedClass) && 
       param.Item2.ReturnedClass != typeof(string)) 
       query.SetParameterList(parameterName, null, param.Item2); 
      else query.SetParameter(parameterName, null, param.Item2); 
     } 
     else 
     { 
      if (param.Item1 is IEnumerable && !(param.Item1 is string)) 
       query.SetParameterList(parameterName, (IEnumerable)param.Item1); 
      else if (param.Item2 != null) 
       query.SetParameter(parameterName, param.Item1, param.Item2); 
      else query.SetParameter(parameterName, param.Item1); 
     } 
    } 
} 

你需要把它包在using語句,以確保讀寫器關閉:

using (var results = session.Query<Fark>().Take(50).Where(x => x.Enabled).Stream()) 
{ 
    results.ForEach(x => writer.WriteLine(x.ToCsv())); 
} 
+0

開箱即用,此解決方案不起作用。如果您將其粘貼到Visual Studio 12,NH 3.2中,則會出現構建錯誤。你能證明這段代碼實際上是否流式傳輸,而不是枚舉已經在內存中的集合? – 2016-09-28 11:49:38

+1

這是用NH 4.0.0.4000完成的,更新了答案。您可以通過查看查詢大型數據集的進程的內存佔用情況來驗證它是否正常工作。如果它的緩衝,內存使用率會飛漲,如果它是流媒體,它將保持不變。這是我驗證它是如何工作的。 – hcoverlambda 2016-09-28 20:28:57

+0

如果我們切換到NH 4,我會給它一個。 Thx的更新 – 2016-09-29 09:03:54

相關問題