延迟加载不适用于NHibernate

时间:2011-03-03 18:41:31

标签: c# nhibernate

在我的类中使用lazy =“true”会导致我的应用程序完美运行,但性能非常糟糕。当我从一个教程创建这个时,我把它打开了,只是想让一些东西尽快运行。 (我使用了本教程:http://geekswithblogs.net/BobPalmer/archive/2010/04/23/mapping-object-relationships---quickstart-with-nhibernate-part-3.aspx这对于获得快速工作的东西很有帮助)

当我只需要使用一个对象时,我不需要它来加载所有这些多对一类,所以重新启用延迟加载是有意义的。然后,我查看了对象,只看到了主要对象中那些多对一类的异常。当我稍后尝试使用这些属性时,我收到以下错误:

"Could not initialize proxy - no Session." 

我猜这意味着会话已关闭,因此在尝试延迟加载其他对象时失败。我的会话提供程序看起来像这样(与教程相同):

class SessionProvider {
    private static ISessionFactory _sessionFactory;
    private static Configuration _config;

    public static ISessionFactory SessionFactory {
        get {
            if (_sessionFactory == null) {
                _sessionFactory = Config.BuildSessionFactory();
            }
            return _sessionFactory;
        }
    }

    private static Configuration Config {
        get {
            if (_config == null) {
                _config = new Configuration();
                _config.AddAssembly(Assembly.GetCallingAssembly());
            }
            return _config;
        }
    }
}

然后由我的存储库使用,如下所示:

using (var session = GetSession()) { ... }

从这个函数获取会话:

private static ISession GetSession() {
        return SessionProvider.SessionFactory.OpenSession();
}

所以我的问题是,我期望在这做什么?保持会话开放?使其在所有存储库中保持静态?我没有足够的NHibernate经验来理解它是如何工作的。我现在的优先事项只是从数据库中读取,如果这有任何区别的话。这是一个代码库,最终将在我们的网站和各种C#.Net应用程序中使用。

4 个答案:

答案 0 :(得分:2)

推荐的方法是使用unit of work pattern。如果您知道自己预先需要特定实体,那么另一个选择就是使用预先加载。

答案 1 :(得分:1)

您通过在存储库中打开和关闭会话来对其进行微观管理。它不仅可以打破延迟加载,还会对性能造成很大的伤害。

相反,会话管理应采用更粗粒度的方法。

例如,对于Web应用程序,一个推荐的模式是每个请求的会话(会话由模块或全局处理程序打开和关闭,并绑定到HttpContext)

只需查看每个请求的会话,就会有很多例子。

答案 2 :(得分:0)

您没有说您的应用程序是Web应用程序(例如ASP.NET MVC)还是控制台/ GUI /服务应用程序。 MVC Web应用程序中延迟加载ORM的一个常见问题是会话在控制器的action方法结束时关闭,代理实体对象被传递给视图,然后该视图尝试枚举某些延迟加载的集合,该集合由于会议已经处理完毕。对此的解决方案称为“视图中的开放会话”模式(至少在Java世界中),通常涉及使用过滤器在Web请求开始时打开会话,确保将会话传递给任何控制器或其他请求它的对象(这通常由您的IoC容器管理),然后在执行视图和延迟加载属性时会话仍处于活动状态。

在一些系统中使用Hibernate同时使用Java和.Net,我一般认为延迟加载有点诅咒。虽然它很方便,但它经常需要额外的管道(例如支持'Open Session in View'模式),并经常杀死性能。对于那些您知道很有可能被访问的集合,最好使用预先加载。分析需要急切加载哪些集合会迫使您更好地理解应用程序的数据访问配置文件,这将有助于您更好地了解应用程序的性能特征,这只是一件好事!

答案 3 :(得分:0)

一个简单的问题是,当实体的关联会话被释放时,您正试图访问尚未加载的值。

NHibernate的Session对象旨在遵循工作单元模式。也就是说,您为要完成的每个单元创建一个会话。

明白地说,在完成与该会话相关联的对象之前,必须保持Session实例处于活动状态(未处理)。这意味着您的会话对象成为您工作的范围:

using(var session = GetSession())
{
    // Load some objects.
    // Manipulate some values.
    // Commit changes.
}

NHibernate会话必须与数据库事务类似地处理,其中完成更广泛操作所需的所有步骤必须在会话范围内完成。