0

私のドメインは、いくつかのターミナルを含む空港であり、各ターミナルにはゾーンなどが含まれています。
空港/ターミナル/ゾーンのエンティティの数が非常に少ないため、次のことを行いたいと思い
ます。1. 空港を取得するときに、すべての階層を熱心にロードします。
(次の流暢な構成を使用:

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

)
2. 第 2 レベルのキャッシュを有効にして、空港オブジェクトのすべての取得が DB にヒットしないようにします。

熱心な読み込みとキャッシングは正常に機能しますが、次のテストでは奇妙な動作が発生します。
(次のコードは空港エンティティを 2 回取得し (2 回目は DB にヒットしません)、そのうちの 1 つを更新します。)

        [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 を選択します: Id36_0_ として airport0_.Id を

選択します。 Terminals0_.Id は Id1_、terminal0_.Id は Id50_0_、terminal0_.Name は Name50_0_、terminal0_.IsDeleted は IsDeleted50_0_、terminal0_.Airport_id は Airport4_50_0_ FROM dbo.[ターミナル] WHEREterminal0_.Airport_id=@p0;@p0 = 1

NHibernate: Zone0_.Terminal_id を Terminal4_1_ として、zones0_.Id を Id1_ として、zones0_.Id を Id51_0_ として、zones0_.Name を Name51_0_ として、zones0_.IsDeleted を IsDeleted51_0_ として、zone0_.Terminal_id を Terminal4_51_0_ として選択します。 ;@p0 = 2


秒の選択
それらは同じ空港インスタンスですか?False

ターミナル
を 追加
する

.[Terminal] (Name, IsDeleted, Airport_id, Id) VALUES (@p0, @p1, @p2, @p3);@p0 = '2 番目の空港に追加されたターミナル', @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 が同じオブジェクトではないという事実 (おそらく、第 2 レベルのキャッシュについて何かが欠けているのでしょうか?)

事前に感謝します、
Jhonny

4

1 に答える 1

1

firstAirportとsecondAirportが同じオブジェクトではないという事実は、デフォルトで参照タイプが参照の同等性について比較されるという事実によるものです。

別々のNHibernateISessionを使用してfirstAirportとsecondAirportをロードしているため、session1はsession2について何も認識していないため、キャッシュは使用されていません。その逆も同様です。
NHibernateのセッションによって実装される「Identity」パターンは、そのセッションのオフコースにスコープされます。

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();
            }
        }
于 2010-12-15T09:35:08.847 に答える