我的域名是一个机场,包含多个终端,每个终端包含区域等
由于机场/航站楼/区域实体的数量非常少,我想:
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
答案 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();
}
}