首页 > 代码库 > 01-05-01-2【Nhibernate (版本3.3.1.4000) 出入江湖】立即加载

01-05-01-2【Nhibernate (版本3.3.1.4000) 出入江湖】立即加载

相关资料:

http://www.cnblogs.com/lyj/archive/2008/10/29/1322373.html

 

 

问题的提出:

1.延迟加载,可能会引起session已经关闭的异常,例如:

当实现延迟加载,当需要Orders时,会通过session去查询,session。但此时,由于session已经关闭,

所以会抛出异常:

{"Initializing[Model.Customer#336]-failed to lazily initialize a collection of role: Model.Customer.Orders, no session or session was closed"}

 

解决方法是,使用强制立即加载:

 

方法一:为类添加一个方法专门用于加载Orders

public Orders LoadOrders(int customerId)
{
    using (ISession _session = new SessionManager().GetSession())
    {
        return _session.Get<Customer>(customerId).Orders;
    }
}

 

方法二:用NHibernateUtil.Initialize()进行强立即迟加载

        public Customer Get(int customerId)
        {
            Customer customer = null;
            ISession session = _sessionManager.GetSession();
            ITransaction transaction = session.BeginTransaction();
            try
            {
                customer = session.Get<Customer>(customerId);
                //强制立即加载
                NHibernateUtil.Initialize(customer.Orders);
                transaction.Commit();
            }
            catch (Exception)
            {
                transaction.Rollback();
                throw;
            }
            finally
            {
                session.Close();
            }

            return customer;
        }


        public Customer Load(int customerId)
        {
            Customer customer = null;
            using (_session)
            {
                 customer = _session.Load<Customer>(customerId);
                //强制立即加载
                NHibernateUtil.Initialize(customer.Orders); 
                 return customer;

            }
        }

 

问题的提出:

2.延迟加载,当关联的表很多,例如:

 Customer--》Orders--》Product--》Company--》。。。

可能会引起连带加载过多其他实体对象,照成资源消耗。

 

解决方案:fetch的HQL查询:

   【1】如果没有用关键fetch的HQL查询是对Orders进行延迟加载的,如下所示:

 

        public IList<Customer> GetByHQL()
        {
            using (_session)
            {
                //注意;如果没有用关键fetch的HQL查询是对Orders进行延迟加载的,
                return _session.CreateQuery("select DISTINCT  c from Customer c  join  c.Orders ")
                               .List<Customer>();

            }
        }

测试代码:
       [TestMethod]
        public void TestGetByHQL()
        {
            CustomerService customerService = new CustomerService();

            IList<Customer> customersList = customerService.GetByHQL();

            //foreach (var customer in customersList)
            //{
            //    Console.WriteLine("{0}的Order数量:{1}", 
            //        customer.CustomerId, customer.Orders.Count());
            //}
        }

从下面输出的SQL语句,可以看出,没用加载Orders

NHibernate: 
    select
        distinct customer0_.CustomerId as CustomerId0_,
        customer0_.Version as Version0_,
        customer0_.Firstname as Firstname0_,
        customer0_.Lastname as Lastname0_,
        customer0_.Age as Age0_ 
    from
        Customer customer0_ 
    inner join
        [
    Order] orders1_ 
        on customer0_.CustomerId=orders1_.CustomerId

 

 

   【2】在HQL查询中加入fetch进行强制立即加载

        public IList<Customer> GetByHQLAndFetch()
        {
            using (_session)
            {
                //注意;如果没哟关键fetch,HQL是对Orders进行延迟加载的,
                //就是通过fetch进行强制立即加载
                return _session.CreateQuery("select DISTINCT  c from Customer c join fetch c.Orders ")
                               .List<Customer>();

            }
        }


测试代码:

        [TestMethod]
        public void TestGetByHQLAndFetch()
        {
            CustomerService customerService = new CustomerService();

            IList<Customer> customersList = customerService.GetByHQLAndFetch();

            //foreach (var customer in customersList)
            //{
            //    Console.WriteLine("{0}的Order数量:{1}", 
            //        customer.CustomerId, customer.Orders.Count());
            //}
        }

从下面输出的SQL语句,可以看出,添加了fetch的HQL对Orders进行了强制立即加载


NHibernate: 
    select
        distinct customer0_.CustomerId as CustomerId0_0_,
        orders1_.OrderId as OrderId1_1_,
        customer0_.Version as Version0_0_,
        customer0_.Firstname as Firstname0_0_,
        customer0_.Lastname as Lastname0_0_,
        customer0_.Age as Age0_0_,
        orders1_.OrderDate as OrderDate1_1_,
        orders1_.CustomerId as CustomerId1_1_,
        orders1_.CustomerId as CustomerId0__,
        orders1_.OrderId as OrderId0__ 
    from
        Customer customer0_ 
    inner join
        [
    Order] orders1_ 
        on customer0_.CustomerId=orders1_.CustomerId

 

fetch的缺陷,来自

http://www.cnblogs.com/lyj/archive/2008/10/29/1322373.html

 

使用HQL查询方法也可以立即加载。HQL语句支持的连接类型为:inner join(内连接)、left outer join(左外连接)、right outer join(右外连接)、full join(全连接,不常用)。

“抓取fetch”连接允许仅仅使用一个选择语句就将相关联的对象随着他们的父对象的初始化而被初始化,可以有效的代替了映射文件中的外联接与延迟属性声明。

几点注意:

  • fetch不与setMaxResults() 或setFirstResult()共用,因为这些操作是基于结果集的,而在预先抓取集合时可能包含重复的数据,也就是说无法预先知道精确的行数。
  • fetch还不能与独立的with条件一起使用。通过在一次查询中fetch多个集合,可以制造出笛卡尔积,因此请多加注意。对多对多映射来说,同时join fetch多个集合角色可能在某些情况下给出并非预期的结果,也请小心。
  • 使用full join fetch 与 right join fetch是没有意义的。 如果你使用属性级别的延迟获取,在第一个查询中可以使用 fetch all properties 来强制NHibernate立即取得那些原本需要延迟加载的属性。