为什么这段代码有效?
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);
}
答案 0 :(得分:0)
无法确定NHibernate,但是如果它遵循与Hibernate相同的规则(我怀疑),它保证在给定的会话中,您可能只有给定ID的给定实体的一个实例。这意味着如果国家/地区实例已在会话中加载,并且某个人的国家/地区具有此已加载实例的ID,则该国家/地区和该国家/地区将是同一个实例,这非常符合逻辑。
会话是一个缓存,并且在此缓存中只有一个具有给定ID的实体实例。无需操作员重载。
答案 1 :(得分:0)
我想如果使用Linq,Hibernate正在使用对象实习,我可以得到一个“错误”的结论。因为这也有效(即产生行):
foreach (var c in s.Query<Country>())
{
Console.WriteLine("\n{0}'s people", c.CountryName);
// different memory copy
var cx = new Country { CountryId = 1 };
foreach(var p in s.Query<Person>().Where(x => x.Country == cx) )
Console.WriteLine("{0}", p.PersonName);
}
NHibernate的Linq-to-db提供程序在比较对象时并不关心实体的其他字段(实际上,在数据库级别而不是对象上比较事物),它只比较id。所以上面代码的 Linq-to-db ,它只是将事物转换为: WHERE 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);
}
}
这是另一个 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);
}
}
除了上面的代码产生行之外,另一个证明Country China与Person's Country共享相同的内存位置:Person.Country.Population也输出777。
所以我想,我可以得出结论NHibernate也使用对象实习(实现方面,我认为NH有效地实现了事情,它不需要在决定实习对象时比较所有属性,它可以使用ID作为什么机制,什么叫?: - ))