如何防止在Flush with Castle ActiveRecord / NHibernate上将对象更改写入数据库

时间:2008-11-21 21:40:25

标签: .net nhibernate castle-activerecord

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

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

例如..

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

5 个答案:

答案 0 :(得分:2)

使用ISession.Evict(objectToEvict)方法驱逐无效对象。

请参阅:http://www.tobinharris.com/2007/2/3/nhibernate-faqhttp://www.surcombe.com/nhibernate-1.2/api/html/M_NHibernate_ISession_Evict.htm

答案 1 :(得分:2)

特别针对ActiveRecord:如果您不自行更改SessionScope,AR默认为会话管理模式,每次调用会话,其中为ActiveRecordMediator的每个操作创建一个新会话。因此,检索后,您检索的所有对象都已与其父会话断开连接。除非您调用Save(或SaveAndUpdate,甚至更新),在每个通话会话模式中创建会话,将要保存的对象附加到该会话,调用保存,然后更改将不会保留更改。然后处理会话(导致刷新,从而写入更改)。

当你以这种方式使用AR时,它确实完全符合您的要求(即除非您明确调用Save,否则不会写回任何更改)。但是这显然违背了预期的NHibernate行为,并且你不能进行延迟加载或者从缓存中获得很多用处。我已经将这种模式用于某些Web应用程序,但它们是预先设计用于预先加载的,并且很多持久对象实际上是不可变的和静态的,并且可以在启动时集中加载并在没有任何连接的情况下进行缓存会话。如果您的应用不适合此型号,那么每次通话会话可能是一个坏主意。

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

答案 2 :(得分:1)

  

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

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

  

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

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

答案 3 :(得分:1)

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

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

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

答案 4 :(得分:0)

您也可以使用具有FlushAction.Never的会话。即:

SessionScope session = new SessionScope(FlushAction.Never);

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