【问题标题】:NHibernate - access the ID of an associated object without lazy loading the whole objectNHibernate - 在不延迟加载整个对象的情况下访问关联对象的 ID
【发布时间】:2016-09-02 20:55:36
【问题描述】:

我有两个关联的业务对象 - 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。之前我只 new 如果对象不存在(Session.Load),则一个抛出异常,而另一个返回一个空对象(Session.Get)。在阅读了关于缓存here 的内容后,很明显 Session.Load 返回了对象的代理,并且仅在访问 ID 以外的属性时才懒惰地获取它,这非常像我需要的关联! 现在我添加了单独的对象 id(将 B_Id 添加到 A,因此我可以将其作为 A.B_Id 访问,而不是使用 A.B.Id)

【问题讨论】:

  • 正如我所说,仅用于日志打印等,在 A 的 ToString() 中。我不需要 B 的其他字段。只需要 ID。

标签: nhibernate associations lazy-loading


【解决方案1】:

如果您使用的是 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;
    }
}

【讨论】:

    【解决方案2】:

    出于完全相同的原因,我对所有多对一关系都使用了显式 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 对象,它会触发对数据库的查询(如果它尚未在会话中加载)。

    我很高兴听到任何其他提供解决方案并提供相同灵活性的选项。

    【讨论】:

    • 我仍然希望这可以仅使用 A.B.Id 来完成 - 我不喜欢重复的数据 - 我有这些属性并删除它们...我会调查更重要的是,但现在这就是我要做的。谢谢!
    • @YonatanKarni 完全同意。这也存在一个主要的性能问题。将大量 n 个“代理”实体添加到实体集合(具有设置的支持类型)中,它会降低性能,因为 n 选择,每个代理一个,按顺序执行,正如 set.Add 所做的那样。
    【解决方案3】:

    您可以使用 Nhibernate 会话的 GetIdentifier 方法:

    session.GetIdentifier(obj);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-19
      • 2018-11-28
      相关资源
      最近更新 更多