nHibernate渴望加载 - 奇怪的更新行为

时间:2010-12-15 09:27:41

标签: nhibernate second-level-cache

我的域名是一个机场,包含多个终端,每个终端包含区域等 由于机场/航站楼/区域实体的数量非常少,我想:
1.在检索机场时,急切地加载所有的层次 (使用以下流畅的配置:

//eagerly load terminals
mapping.HasMany(x => x.Terminals).Not.LazyLoad()
            .Cache.ReadWrite();


2.启用第二级缓存,以便机场对象的所有检索都不会到达DB
急切的加载和缓存工作正常,但以下测试会产生一些奇怪的行为 (以下代码检索机场实体两次(第二次没有点击数据库),并更新其中一个。)

        [TestMethod]
    public void TestSecondLevelCache()
    {
        Airport firstAirport = null, secondAirport = null;

        Console.WriteLine("first select");
        using (ISession session = this.SessionFactory.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                //the idea here is to see whether there are two calls to DB here. check the sql output
                AirportDAO dao = new AirportDAO(session);
                firstAirport = dao.GetAirport();
                transaction.Commit();
            }
        }

        Console.WriteLine("second select");
        using (ISession session = this.SessionFactory.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                //the idea here is to see whether there are two calls to DB here. check the sql output
                AirportDAO dao = new AirportDAO(session);
                secondAirport = dao.GetAirport();
                transaction.Commit();
            }
        }

        Console.WriteLine("Are those the same airport instance? " + firstAirport.Equals(secondAirport));

        Console.WriteLine("now adding a terminal");
        using (ISession session = this.SessionFactory.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                secondAirport.Terminals.Add(new Terminal() { Name = "terminal added to second airport", Zones = new List<Zone>() });
                session.Update(secondAirport);
                transaction.Commit();
            }
        }
        //this Assert fails, since firstAirport != secondAirport
        Assert.IsNotNull(firstAirport.Terminals.FirstOrDefault(t => t.Name.Contains("second airport")));
    }

查看结果输出:

  

首先选择
  NHibernate:SELECT airport0_.Id as Id36_0_,airport0_.Name as Name36_0_,airport0_.IsDeleted as IsDeleted36_0_ FROM dbo。[Airport] airport0_ WHERE airport0_.Id=@p0; @ p0 = 1

  NHibernate:SELECT terminals0_.Airport_id as Airport4_1_,terminals0_.Id as Id1_,terminals0_.Id as Id50_0_,terminals0_.Name as Name50_0_,terminals0_.IsDeleted as IsDeleted50_0_,terminals0_.Airport_id as Airport4_50_0_ FROM dbo。[Terminal] terminals0_ WHERE terminals0_.Airport_id = @ p0; @ p0 = 1

  NHibernate:SELECT zones0_.Terminal_id为Terminal4_1_,zones0_.Id为Id1_,zones0_.Id为Id51_0_,zones0_.Name为Name51_0_,zones0_.IsDeleted为IsDeleted51_0_,zones0_.Terminal_id为Terminal4_51_0_ FROM dbo。[Zone] zones0_ WHERE zones0_.Terminal_id = @ p0; @ p0 = 2

  
  第二选择
  那些机场实例是一样的吗?假
  
  现在添加一个终端
  NHibernate:从dbo._uniqueKey中选择next_hi(updlock,rowlock)
  NHibernate:更新dbo._uniqueKey set next_hi = @ p0其中next_hi = @ p1; @ p0 = 17,@ p1 = 16

  NHibernate:INSERT INTO dbo。[终端](名称,IsDeleted,Airport_id,Id)VALUES(@ p0,@ p1,@ p2,@ p3); @ p0 ='终端添加到第二个机场',@ p1 = False,@ p2 = NULL,@ p3 = 16
  NHibernate:UPDATE dbo。[Airport] SET Name = @ p0,IsDeleted = @ p1 WHERE Id = @ p2; @ p0 ='test airport',@ p1 = False,@ p2 = 1

  NHibernate:UPDATE dbo。[Terminal] SET Name = @ p0,IsDeleted = @ p1,Airport_id = @ p2 WHERE Id = @ p3; @ p0 ='test terminal',@ p1 = False,@ p2 = 1,@ p3 = 2

  NHibernate:UPDATE dbo。[Zone] SET Name = @ p0,IsDeleted = @ p1,Terminal_id = @ p2 WHERE Id = @ p3; @ p0 ='test zone',@ p1 = False,@ p2 = 2,@ p3 = 3

  NHibernate:UPDATE dbo。[终端] SET Airport_id = @ p0 WHERE Id = @ p1; @ p0 = 1,@ p1 = 16
  

  

我的问题是:
  1.更新所有内容的奇怪更新行为...
  2. firstAirport和secondAirport不是同一个对象的事实(也许我错过了关于二级缓存的东西?)

  提前谢谢,
  的Jhonny

1 个答案:

答案 0 :(得分:1)

firstAirport和secondAirport不是同一个对象的事实是由于默认情况下比较引用类型的引用类型。

由于您使用单独的NHibernate ISession加载first和secondAirport,因此未使用缓存,因为session1对session2一无所知,反之亦然。
由NHibernate会话实现的“身份”模式的范围限定在该会话中。

您可以通过正确覆盖Equals和GetHashcode方法来覆盖此行为。 您可以覆盖Equals方法,以便根据机场的“Id”确定相等性。

奇怪的更新行为是由于您正在更新另一个会话中的对象,然后是从中检索它的会话。 您应该将ISEssion视为UnitOfWork。因此,最好加载对象并将对象保存在同一会话中,而不是在每个会话中执行这些操作。 (您也可以通过将现有机场对象“锁定”到您用于执行更新的会话中来解决此问题。

using (ISession session = this.SessionFactory.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {

                session.Lock (secondAirport, LockMode.None);

                secondAirport.Terminals.Add(new Terminal() { Name = "terminal added to second airport", Zones = new List<Zone>() });
                session.Update(secondAirport);
                transaction.Commit();
            }
        }