NHibernate是否使用对象实习?

NHibernate是否使用对象实习?,hibernate,nhibernate,architecture,Hibernate,Nhibernate,Architecture,为什么这个代码有效 NHibernate是否使用对象实习 如果不是,则以下操作有效,因为NHibernate重载等于运算符 foreach (var c in s.Query<Country>()) { Console.WriteLine("\n{0}", c.CountryName); // code in question foreach(var p in s.Query<Person>().Where(x => x.Country

为什么这个代码有效

NHibernate是否使用对象实习

如果不是,则以下操作有效,因为NHibernate重载等于运算符

foreach (var c in s.Query<Country>())
{
    Console.WriteLine("\n{0}", c.CountryName);

    // code in question 
    foreach(var p in s.Query<Person>().Where(x => x.Country == c) )
        Console.WriteLine("{0}", p.PersonName);

}
foreach(s.Query()中的变量c)
{
Console.WriteLine(“\n{0}”,c.CountryName);
//问题代码
foreach(s.Query()中的var p,其中(x=>x.Country==c))
Console.WriteLine(“{0}”,p.PersonName);
}

无法确定NHibernate的情况,但如果它遵循与Hibernate相同的规则(我怀疑),它保证在给定会话中,对于给定ID,您可能只有一个给定实体的实例。这意味着如果会话中已经加载了一个国家/地区实例,并且某人的国家/地区具有该加载实例的ID,国家和个人的国家将是同一个实例,这是非常合乎逻辑的

会话是一个缓存,该缓存中只有一个具有给定ID的实体实例。不需要运算符重载。

我想,如果使用Linq,您可能会得到一个“错误”的结论,即Hibernate正在使用对象interning。由于这也起作用(即生成行):

foreach(s.Query()中的变量c)
{
Console.WriteLine(“\n{0}的人”,c.CountryName);
//不同的内存拷贝
var cx=新国家{CountryId=1};
foreach(s.Query()中的var p,其中(x=>x.Country==cx))
Console.WriteLine(“{0}”,p.PersonName);
}
NHibernate的Linq to db提供程序在比较对象时不关心实体的其他字段(实际上,在db级别比较对象,而不是对象),它只比较id。因此,上面代码的Linq to db仅将内容转换为:其中CountryId=1。

然而,如果我们急切地将对象提取到内存中,我们可以更容易地推断行为。这不会产生任何行,即使我们复制所有属性,因为cx指向不同的地址。因此,此Linq to memory不会生成任何行:

foreach (var c in s.Query<Country>())
{
    Console.WriteLine("\n{0}'s people", c.CountryName);

    var cx = new Country
    {
         CountryId = c.CountryId,
         CountryName = c.CountryName,
         People = c.People.ToArray().ToList(),
         Population = c.Population
    };

    foreach(var p in s.Query<Person>().Fetch(x => x.Country)
                      .ToList().Where(x => x.Country == cx) )
    {
        Console.WriteLine("{0}", p.PersonName);
    }

}
foreach(s.Query()中的变量c)
{
Console.WriteLine(“\n{0}的人”,c.CountryName);
var cx=新国家/地区
{
CountryId=c.CountryId,
CountryName=c.CountryName,
People=c.People.ToArray().ToList(),
人口=c.人口
};
foreach(s.Query().Fetch中的var p(x=>x.Country)
.ToList()。其中(x=>x.Country==cx))
{
Console.WriteLine(“{0}”,p.PersonName);
}
}
这里是另一个Linq to memory代码,这次它生成行,因此我们可以得出结论,NHibernate实习生是对象

var china = s.Get<Country>(1);
china.Population = 777;

foreach (var c in s.Query<Country>())
{
    Console.WriteLine("\n{0}'s people", c.CountryName);

    foreach(var p in s.Query<Person>().Fetch(x => x.Country)
                      .ToList().Where(x => x.Country == china) )
    {   
        Console.WriteLine("{0} {1}", p.PersonName, p.Country.Population);
    }
}
var中国=s.Get(1);
中国。人口=777;
foreach(s.Query()中的变量c)
{
Console.WriteLine(“\n{0}的人”,c.CountryName);
foreach(s.Query().Fetch中的var p(x=>x.Country)
.ToList().Where(x=>x.Country==中国))
{   
Console.WriteLine(“{0}{1}”,p.PersonName,p.Country.Population);
}
}
除了上面的代码生成行之外,另一个证明中国与个人的国家共享相同的内存位置的证据是:Person.Country.Population也输出777


所以我猜,我可以得出结论,NHibernate也采用对象内部(实现方面,我认为NH实现起来很有效,当它决定内部对象时,它不需要比较所有属性,它可以使用ID作为一种机制,你认为呢?:-)

你的回答促使我比较不同会话中的对象。即使这两个对象来自同一个ID,但它们处于不同的会话中,它们也不共享相同的内存。因此,NHibernate可以在同一个会话中,但不能在不同的会话中,对对象进行实习生。这是预期的行为。会话应该表示与数据库的相对较短的交互,与其他并发会话隔离。这基本上是正确的,但有一点需要更正:会话不是缓存:它是一个身份映射(请参阅)。下面是来自Hibernate参考文档的会话定义的一部分:“维护应用程序的持久对象和集合的一级持久缓存;此缓存用于导航对象图或按标识符查找对象。“Martin Fowler将此缓存称为身份映射并不意味着它不再是缓存。
var china = s.Get<Country>(1);
china.Population = 777;

foreach (var c in s.Query<Country>())
{
    Console.WriteLine("\n{0}'s people", c.CountryName);

    foreach(var p in s.Query<Person>().Fetch(x => x.Country)
                      .ToList().Where(x => x.Country == china) )
    {   
        Console.WriteLine("{0} {1}", p.PersonName, p.Country.Population);
    }
}