我有两个相关的业务对象--A和B. 该关联是(A-> B)多对一,其中B.Id是A中的外键(因此A在DB中具有A.B_id)。
我正在使用lazy = true并解决了我的大部分问题, 但是在A的ToString中,我想要打印A.B.Id,我应该没有进一步访问数据库。但是访问A.B会激活代理,因为这不是在开放会话的上下文中,所以会抛出异常。
一个简单但丑陋的解决方案是拥有A.B_id属性。但这是我们首先想要避免的东西的一部分。 任何“有机”的方式来做到这一点? :) 谢谢!
更新:刚刚阅读有关缓存和Session.Get与Session.Load的内容。如果对象不存在(Session.Load),那么只有新的那个抛出异常,而另一个返回一个空对象(Session.Get)。在阅读了有关缓存here之后,很明显Session.Load会向对象返回一个代理,并且只有在访问ID以外的属性时才会懒惰地获取它,这非常类似于我需要的关联! 现在我添加了单独的对象id(将B_Id添加到A中,因此我可以将其作为A.B_Id访问而不是使用A.B.Id)
答案 0 :(得分:6)
如果您使用的是NHibernate 3.2或更高版本,则可以使用以下代码获取关联对象的id,而无需另外往返数据库以加载整个对象:
using NHibernate.Proxy;
...
object id = null;
if (obj.IsProxy()) // obj is the object you want to get its identifier.
{
var proxy = obj as INHibernateProxy;
if (proxy != null)
{
var li = proxy.HibernateLazyInitializer;
if (li != null)
id = li.Identifier;
}
}
答案 1 :(得分:4)
出于同样的原因,我在所有多对一关系中都使用了明确的A.B-ID属性。我不认为这是一个快速而肮脏的解决方案,因为它提供了这个问题的解决方案,并且还有很多灵活性是保存更新区域,即我不需要从数据库中获取B对象只是为了将其分配给A我在查询字符串或其他地方拥有B_ID时创建关联。
我的映射文件通常如下所示:
<property name="CreatorID" column="CreatorID" type="Int32" not-null="true" />
<many-to-one name="Creator" column="CreatorID" class="SystemUser" insert="false" update="false" cascade="none" />
正如您所看到的,必须只读取其中一个属性,以避免在插入或更新时发生NHibernate将此列发送2次到数据库。以上内容使得只读(通过使用insert =“false”update =“false”属性)多对一,但如果您愿意,可以将其作为只读的CreatorID属性。
只有多对一,你的实体类A中没有属性来保存B.ID值。获取它的唯一方法是访问将触发代理的B对象,它将向数据库发出查询(如果它尚未在会话中加载)。
我很乐意听到提供解决方案的任何其他选项,并提供相同的灵活性。
答案 2 :(得分:1)
您可以使用Nhibernate会话的GetIdentifier方法:
session.GetIdentifier(obj);