【问题标题】:How to prevent writing object changes to the database on Flush with Castle ActiveRecord / NHibernate如何使用 Castle ActiveRecord / NHibernate 防止将对象更改写入 Flush 上的数据库
【发布时间】:2008-11-24 13:15:54
【问题描述】:

NHibernate 的默认行为是在调用 Session.Flush() 时将对对象的所有更改写入数据库。无论您是否愿意,它都会这样做。

当我们需要执行诸如验证业务规则或输入等操作时,如何防止将错误数据写入数据库?

例如..

  • 客户名称不为空。
  • 用户打开 Web 浏览器(不带 javascript)并删除客户名称。
  • 点击更新。
  • Customer.Name 属性已更新和..
  • Customer.IsValid() 被调用。
  • 即使IsValid() 为假并且我们显示错误消息,NHibernate 仍会更新数据库。

【问题讨论】:

    标签: .net nhibernate castle-activerecord


    【解决方案1】:

    专门针对 ActiveRecord:如果您不自己更改 SessionScope,AR 默认为 session-per-call 的会话管理模式,其中为 ActiveRecordMediator 的每个操作创建一个新会话。因此,一旦您检索到它们,您检索的所有对象都已与其父会话断开连接。除非您调用 Save(或 SaveAndUpdate,甚至是 Update),否则更改将不会持续存在然后处理会话(导致刷新并因此写入更改)。

    当您以这种方式使用 AR 时,它会完全按照您的意愿行事(即,除非您明确调用 Save,否则不会写回任何更改)。但这明显违背了预期的 NHibernate 行为,您不能进行延迟加载或充分利用缓存。我已经在一些 Web 应用程序中使用了这种模式,但是它们是为预先加载而设计的,并且相当多的持久对象实际上是不可变的和静态的,并且可以在启动时整体加载并缓存而无需连接到任何会议。如果您的应用不适合此模型,那么每次调用会话可能不是一个好主意。

    由于您似乎使用的是 UOW 模式,因此您无法利用这种行为。因此,您必须要么从 NHibernate 会话中逐出对象(并且访问真实的 ISession 实例实际上并不像在 AR 中看起来那么容易),要么更改您的应用程序的工作方式,以便不会实际修改持久对象的属性直到您的业务规则得到验证。

    【讨论】:

      【解决方案2】:

      【讨论】:

      • 同意,这行得通,但是我在我的客户端代码中都调用了 evict。不理想。
      【解决方案3】:

      NHibernate 的默认行为是在调用 Session.Flush() 时将对对象的所有更改写入数据库。无论您是否愿意,它都会这样做。

      如果您不希望 NHibernate 刷新会话,那么为什么要告诉它刷新会话? Flush()WriteAllChangesToObjectsToTheDatabase() 的简写。

      当我们需要做诸如验证业务规则或输入之类的事情时,我们如何防止将不良数据写入数据库?

      • 在修改模型对象之前验证更改。不允许无效的模型对象存在于内存中(从模型公开的公共 API 的角度来看,不包括多线程场景)。
      • 将您的更改包装在一个事务中,如果您的模型对象验证失败,该事务将失败(为什么首先允许无效的模型对象?)。

      【讨论】:

      • 此应用程序是 Web 应用程序,会话由工作单元处理。它在每个 Web 请求后自动刷新。您如何建议我验证我的业务对象?给出的例子很简单,但是,如果不创建对象,其他例子就更难验证了。
      • 在调用时验证所有数据和操作,这样属性就不会变成无效的东西。 NHibernate 的比喻很简单——内存中的持久对象和数据库中的数据应该被认为是不可分割的;改变一个==改变另一个。忽略管道。
      【解决方案4】:

      所以,我知道这完全是矫枉过正,但这是我修复它的方法。

      转换为 NHibernate 2.0 并使用 NHibernate Validator 项目来运行我的输入验证规则。我还没有处理业务规则,但我认为我可以使用自定义验证器规则来完成它们,如果这不起作用,我可以使用 nhibernate 事件。

      由于我已经在使用存储库模式,因此转换非常简单。只花了大约 4-5 个小时,我们的模型非常广泛。能够从 AR 属性生成 .xml 文件可以节省大量时间。

      【讨论】:

        【解决方案5】:

        您还可以将 Session 与 FlushAction.Never 一起使用。即:

        SessionScope session = new SessionScope(FlushAction.Never);
        

        这会将默认行为从自动保存所有内容切换到您明确需要在实体上调用 .Save() 。所以你可以做任何你需要做的验证,然后才保存你想要的......

        【讨论】:

        • 保存并不意味着“保存更改”。更改会在幕后自动保存(这就是 Flush 所做的)。 Save 将对象的状态从瞬态更改为持久,并按照对象映射的指示级联更改;它不一定会立即执行 SQL。
        • 我在 Web 应用程序中使用它,所以我无法直接访问会话(它由工作单元处理)。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多