使用NHibernate实现流式传输大型结果集是否有效?

时间:2011-05-03 17:19:34

标签: nhibernate stream resultset

我正在使用ayende提出的方法:

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

在带有NHibernate 3.0的SQL Server 2005上。

我的测试(尝试使用10,000,000个项目流式传输结果集)表明结果未被流式传输(看起来整个结果集首先被加载到内存中)。

我怎样才能让它发挥作用?我将接受任何允许在NHibernate中传输结果集的解决方案,它不一定是ayende的解决方案。

2 个答案:

答案 0 :(得分:2)

您可以使用以下扩展方法使用NH 4.0.0.4000来传输来自Linq的结果(如果您不喜欢反射黑客,则传递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()));
}

答案 1 :(得分:1)

Ayende说:

  

但我们仍然存在内存消耗问题。会议   将跟踪所有加载的对象,如果我们加载了很多   数据,它最终会因内存不足而爆发。

这很可能是原因。您确定会话不跟踪对象吗?尝试选择不是实体,而是选择其中一些成员进行测试。