nHibernate нетерпеливая загрузка - странное поведение обновления - PullRequest
0 голосов
/ 15 декабря 2010

мой домен - это аэропорт, который содержит несколько терминалов, и каждый терминал содержит зоны и т. Д.
так как количество объектов аэропорта / терминала / зоны очень мало, я бы хотел:
1. загружать всю иерархию при поиске в аэропорту.
(используя следующую свободную конфигурацию:

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

)
2. включить кэширование 2-го уровня, чтобы все извлечения объекта аэропорта не попадали в БД.

энергичная загрузка и кэширование работают нормально, но следующий тест вызывает странное поведение.
(следующий код извлекает объект аэропорта дважды (без повторного обращения к БД) и обновляет один из них.)

        [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: ВЫБЕРИТЕ airport0_.Id как Id36_0_, airport0_.Name как Name36_0_, airport0_.IsDeleted as IsDeleted36_0_ ИЗ dbo. [Аэропорт] airport0_ WHERE airport0_.Id=@p0; @ p0 = 1

NHibernate: ВЫБРАТЬ терминалы 0_.Airport_id в качестве Airport4_1_, Terminal 0_.Id в качестве Id1_, Terminal0_.Id в качестве Id50_0_, Terminal0_.Name в качестве имени50_0_, TerminalS__I. @ p0; @ p0 = 1

NHibernate:. ВЫБРАТЬ 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_ ИЗ DBO [Зона] zones0_ ГДЕ zones0_.Terminal_id = @ p0; @ p0 = 2


второй выбор
Это один и тот же аэропорт? Ложные

Теперь добавляем терминал
NHibernate: выберите next_hi из dbo._uniqueKey с помощью (updlock, rowlock)
NHibernate: обновить dbo._uniqueKey set next_hi = @ p0, где next_hi = @ p1; @ p0 = 17, @ p1 = 16

NHibernate: INSERT INTO dbo. [Terminal] (Имя, IsDeleted, Airport_id, Id) ЗНАЧЕНИЯ (@ p0, @ p1, @ p2, @ p3); @ p0 = 'терминал добавлен во второй аэропорт', @ p1 = False, @ p2 = NULL, @ p3 = 16
NHibernate: ОБНОВЛЕНИЕ dbo. [Аэропорт] SET Name = @ p0, IsDeleted = @ p1 WHERE Id = @ p2; @ p0 = 'тестовый аэропорт', @ p1 = False, @ p2 = 1

NHibernate: ОБНОВЛЕНИЕ dbo. [Терминал] SET Name = @ p0, IsDeleted = @ p1, Airport_id = @ p2 WHERE Id = @ p3; @ p0 = 'тестовый терминал', @ p1 = False, @ p2 = 1, @ p3 = 2

NHibernate: ОБНОВЛЕНИЕ dbo. [Zone] SET Name = @ p0, IsDeleted = @ p1, Terminal_id = @ p2 WHERE Id = @ p3; @ p0 = 'тестовая зона', @ p1 = False, @ p2 = 2, @ p3 = 3

NHibernate: ОБНОВЛЕНИЕ dbo. [Терминал] SET Airport_id = @ p0 WHERE Id = @ p1; @ p0 = 1, @ p1 = 16



мои проблемы:
1. странное поведение обновления, которое обновляет все ...
2. тот факт, что firstAirport и secondAirport не являются одним и тем же объектом (может быть, я что-то упускаю из-за кэша 2-го уровня?)

заранее спасибо
Jhonny

1 Ответ

1 голос
/ 15 декабря 2010

Тот факт, что firstAirport и secondAirport не являются одним и тем же объектом, объясняется тем, что ссылочные типы сравниваются по равенству ссылок по умолчанию.

Поскольку вы загружаете first и secondAirport, используя отдельные NHibernate ISessionкеш не используется, так как 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();
            }
        }
...