使用NHibernate会话加载方法,是否有方法访问实体';没有初始化代理的id?
根据文档,session.Load(id) 返回一个对象,该对象是未初始化的代理,并且实际上没有命中数据库 这很好,因为我有一个场景,我想加载一个对象(我知道它存在于数据库中),然后(在同一个会话中)访问实体的id,通常只访问id,而不初始化代理。在我看来,如果我只访问代理的id,它就不必初始化。至少这是我希望的,但我似乎无法让它以那种方式工作 基本上,我正在尝试通过以下测试:使用NHibernate会话加载方法,是否有方法访问实体';没有初始化代理的id?,nhibernate,Nhibernate,根据文档,session.Load(id) 返回一个对象,该对象是未初始化的代理,并且实际上没有命中数据库 这很好,因为我有一个场景,我想加载一个对象(我知道它存在于数据库中),然后(在同一个会话中)访问实体的id,通常只访问id,而不初始化代理。在我看来,如果我只访问代理的id,它就不必初始化。至少这是我希望的,但我似乎无法让它以那种方式工作 基本上,我正在尝试通过以下测试: [Test] public void Accessing_loaded_entity_id_should_not_in
[Test]
public void Accessing_loaded_entity_id_should_not_initialize_the_proxy()
{
// Arrange
var repo = new NHRepository<Order>();
var order = new OrderBuilder().Build();
repo.Save(order);
repo.Flush();
repo.Clear();
// Act
var fromDb = repo.Load(order.ID);
// Assert
Assert.AreEqual(order.ID, fromDb.ID);
Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb));
}
[测试]
公共无效访问\u加载的\u实体\u id\u不应\u初始化\u代理()
{
//安排
var repo=new NHRepository();
var order=new OrderBuilder().Build();
回购保存(订单);
回购冲水();
回购清晰();
//表演
var fromDb=回购负载(订单ID);
//断言
arest.AreEqual(order.ID,fromDb.ID);
Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb));
}
此测试在此失败:
Assert.IsFalse(NHibernateUtil.IsInitialized(fromDb))
更新
以下是我的id的hbm映射:
<id name="id" access="field">
<generator class="hilo">
<param name="column">OrderNextHi</param>
<param name="max_lo">100</param>
</generator>
</id>
OrderNextHi
100
这是我的基本实体类型。我想问题可能就在这里,因为我很久以前就复制了这个,没有花太多心思。让我知道你的想法:
public abstract class SingleIdentityDomainEntity<T> where T : SingleIdentityDomainEntity<T>
{
private readonly int id;
private int? _oldHashCode;
protected SingleIdentityDomainEntity()
{
this.id = 0;
}
public virtual int ID
{
get { return this.id; }
}
public override bool Equals(object obj)
{
var other = obj as T;
if (other == null)
return false;
// handle the case of comparing two NEW objects
if (other.IsTransient() && this.IsTransient())
return ReferenceEquals(other, this);
return other.ID.Equals(this.ID);
}
/// <summary>
/// Transient objects are not associated with an item already in storage.
/// </summary>
public virtual bool IsTransient()
{
return this.ID == 0;
}
/// <summary>
/// Must be provided to properly compare two objects
/// </summary>
public override int GetHashCode()
{
// Once we have a hash code we'll never change it
if (_oldHashCode.HasValue)
return _oldHashCode.Value;
// When this instance is transient, we use the base GetHashCode()
// and remember it, so an instance can NEVER change its hash code.
if (this.IsTransient())
{
_oldHashCode = base.GetHashCode();
return _oldHashCode.Value;
}
return this.ID.GetHashCode();
}
}
公共抽象类SingleIdentityDomainEntity,其中T:SingleIdentityDomainEntity
{
私有只读int-id;
私有整数?oldHashCode;
受保护的SingleIdentityDomainEntity()
{
此参数为0.id;
}
公共虚拟整数ID
{
获取{返回this.id;}
}
公共覆盖布尔等于(对象对象对象)
{
var other=作为T的obj;
如果(其他==null)
返回false;
//处理比较两个新对象的情况
if(other.IsTransient()&&this.IsTransient())
返回ReferenceEquals(其他,此);
返回其他.ID.Equals(this.ID);
}
///
///临时对象与已在存储器中的项不关联。
///
公共虚拟boolistransient()
{
返回this.ID==0;
}
///
///必须提供以正确比较两个对象
///
公共覆盖int GetHashCode()
{
//一旦我们有了散列码,我们就永远不会改变它
if(_oldHashCode.HasValue)
返回_oldHashCode.Value;
//当这个实例是暂时的时,我们使用基本的GetHashCode()
//记住它,这样实例就永远不会更改其哈希代码。
if(this.IsTransient())
{
_oldHashCode=base.GetHashCode();
返回_oldHashCode.Value;
}
返回此.ID.GetHashCode();
}
}
我不知道您对存储库的实现,但我认为您的问题在于:
repo.Clear();
线路。我猜它会清除您的会话(所有缓存值都会被逐出)。您的断言是否实际强制从数据库加载。你能看到sql吗?@Mark,用var i=fromDb.ID替换这两个断言,我能用sql事件探查器验证select sql语句是否生成。你能在ID属性后面发布代码,以及ID属性与Order的映射吗?我不理解这里的问题。如果要初始化它,请使用Session.Get()@Darren。问题是,如果我只需要id,就不需要初始化它。这就是为什么我使用Load而不是Get,因为Get总是会命中数据库。这有意义吗?Clear()方法正在逐出所有缓存的值,这就是我调用它的原因。调用Load时,我不希望会话中存在订单obj。当我从回购中加载它时,我实际上需要代理。然后我希望,如果我只尝试从代理中获取id,代理将不会初始化,也不会得到db命中。显然,如果我在代理上调用另一个方法,我会期望db命中,但id应该已经加载到代理中,因为我将其用作加载方法的参数。这有意义吗?从nhibernate文档中可以看出:Hibernate从数据库中加载了多少数据,它将使用多少SQL选择?这取决于抓取策略。第19.1节“获取策略”对此进行了解释。这意味着您必须在映射中设置抓取策略。