【问题标题】:NHibernate - saving huge detached objectNHibernate - 保存巨大的分离对象
【发布时间】:2011-12-29 12:56:18
【问题描述】:

我有一个两层(非 Web)系统,我会将一些对象加载到系统内存中,并偶尔将它们刷新回数据库。假设我只需要更新一个对象,但该对象是一个相当大的图,可能包含数百个实体,我使用级联将保存传播到整个图。

当在第二个会话中调用 Session.Update(the_big_object) 时,NHibernate “正确”地将整个对象图中的每个实体覆盖到数据库中,从而创建大量更新,即使它们没有更改。这是可以理解的,因为它不知道在会话之外发生了什么变化。使用 Session.Merge(the_big_object) 并没有多大帮助,因为它还需要大量查询。

问题出在我的例子中,通常大图中只有少数实体实际发生了变化。我在想的是,与其使用级联来保存整个对象,不如将脏实体集合保留在内存中,并且只在需要时才刷新它们。为了做到这一点,我可能需要为那些绑定到它们的设置器的类添加一个脏标志,等等。

然后我想,这不正是 NHibernate 在会话中一直在做的事情,以确定哪些对象是脏的吗?所有这些代理/版本的东西都适用于持久对象,但不适用于分离的对象(或者它们是吗?)。我只是觉得需要手动再次执行此操作有点愚蠢。

有什么我可以采取的建议/方法,或者我缺少什么魔术吗?

非常感谢!

【问题讨论】:

  • 哦,我不能在每个实体更改时都将其刷新到数据库中,因为它可能发生得太频繁了。我只分批冲洗它们。
  • 前段时间我在网络应用中搜索了很多东西。

标签: .net nhibernate cascade


【解决方案1】:

除非您自己手动跟踪更改的实体,否则似乎没有办法按照您的要求进行操作。看看这篇文章。这与您要问的类似:

What is the best approach to update only changed properties in NHibernate when session detached?

编辑:

您可以在进行更新之前将您的对象重新附加到会话吗?如果是这样,你可以这样做:

using(var session = sessionFactory.OpenSession())
    using(var tx = session.BeginTransaction()) 
    {
        var p = new Person {PersonId = 1};
        session.Lock(p, LockMode.None); // <-- This is the secret sauce!
        p.Firstname = "Bob";
        // No need to call session.Update(p) since p is already associated with the session.
        tx.Commit();
    }

以上代码取自:NHibernate - flagging specific properties as 'dirty'

【讨论】:

  • 感谢您的回答!我实际上阅读了您提供的文章 - 但它并不完全相同,因为我真的不介意它更新到未更改的字段/列 - 它仍然是相同数量的更新。我更关心不必要的更新 sql 命令(比如只更改了 3 个实体,但触发了 100 个更新)。至于您提供的示例,从逻辑上讲,它肯定会起作用,我不太愿意这样做的原因是因为实体可能一直在调整,我担心它会导致性能问题。
  • 我进一步阅读了文章“将特定属性标记为'脏'”,用例场景有点不同 - 更改似乎只有一次,所以 Session.Lock() 在那里有意义.
【解决方案2】:

只是为了有个线索:

考虑将原始对象存储在内存中(例如 Web 应用程序的 Session),并在更新的对象返回时找出变更集(例如在回发中)。

我正在寻找一种方法来将分离的对象附加到会话而不查询数据库。

【讨论】:

  • 几乎是我要问的 - 但在会话范围之外,我不认为休眠可以在不再次查询或蛮力覆盖的情况下知道发生了什么变化......所以我只是想知道是否有任何方法更优雅地处理问题
【解决方案3】:

几个未经测试的想法:

  • 在第二个会话中使用查询或访问任何延迟加载的集合来加载整个对象图。然后将分离的对象合并到第二个会话中;这应该不需要任何额外的查询,因为整个对象图都将在缓存中。

  • 在您的对象中实现INotifyPropertyChanged 并跟踪顶级对象中的脏对象。如果图表中有许多不同的类型,这将是一项相当大的工作量。


另一个选项可能是序列化原始会话并在您准备刷新会话时反序列化。您应该能够将实体合并回原始会话,而无需额外的数据库之旅。

【讨论】:

  • 感谢您的回答!我观察到 Session.Merge() 的行为,它发出的查询与我手动查询它们的查询几乎相同。由于我在其他地方不需要那种“未保存的状态”,所以查询的总量保持不变。虽然 INotifyPropertyChanged 很有趣,但是是的,尽管定义了接口,但整个事情仍然很难编码......
猜你喜欢
  • 2021-12-20
  • 1970-01-01
  • 2010-10-06
  • 2011-10-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多