Castle ActiveProject正在从FindAllByProperty检索过时的数据



我有一个旧的WinForms 4.x应用程序,它在NHibernate 3.1.0.4000(不是最新的,但当时是最新的(之上使用Castle.ActiveRecord 3.0.0 RC(我认为这是最新可用的版本(。

我注意到一个表单中有一种奇怪的数据不一致行为。它为表单的生命周期创建了一个TransactionScope,直到最后才提交。它获取一个对象列表,并为它们提供一些编辑UI。其中之一是IsPrimary布尔属性的复选框。

只有一个对象应该具有IsPrimary==true,所以当您切换复选框时,它确实具有:

var others = MyData.FindAllByProperty("IsPrimary", true)
.Where(x => x.Name != current.Name).ToList();
foreach (var data in others)
{
data.IsPrimary = false;
data.Save();
}
current.IsPrimary = true;
current.Save();

(这可能可以更有效地完成,但现在忽略它。current是勾选复选框的对象。它们都有唯一的名称。(

这在大多数情况下都能正常工作,但如果您打开窗口,勾选其他项目上的复选框(因此它会执行上述操作,并正确地将前一个设置为false(,然后在不关闭窗口的情况下,尝试再次勾选第一个项目,最终会有两个对象设置为IsPrimary

问题似乎是FindAllByProperty在表单事务之外返回原始对象状态,忽略任何更改。

如果我用以下代码替换呼叫:

var others = MyData.FindAll().Where(x => x.IsPrimary)
.Where(x => x.Name != current.Name).ToList();

然后它返回正确的结果(包括在表单事务内部所做的更改(。

这是一个已知的bug吗?除了使用FindAll()之外,还有其他解决方法吗?


编辑:使用显式标准的FWIW具有相同的结果(它返回过时的数据,而不是正确的数据(:

var criteria = DetachedCriteria.For(typeof(MyData))
.SetResultTransformer(CriteriaSpecification.DistinctRootEntity)
.Add(Restrictions.Eq("IsPrimary", true))
.Add(Restrictions.Not(Restrictions.IdEq(current.Id)));
var others = MyData.FindAll(criteria);
// still stale

这里一起播放三件事:

  • 在不提交的情况下,数据库内部的数据不会更改
  • 在可能的情况下,nhibernate将restrictins转换为SQL,数据库服务器运行检查。只有在可能的情况下
  • 会话有一个chace,如果返回的记录(主(键已经在chace中,它将忽略记录(值(,只重用缓存中的对象

这意味着Restrictions.Eq("IsPrimary",true(或Where(x=>x.IsPrimary(将(我认为(在数据库服务器中运行,并且永远看不到任何只在应用程序中更改的数据(又名无提交,又名瞬态数据,又名脏数据/对象(。这意味着,如果您的应用程序/会话/chace中有多个对象的IsPrimary=true,但在数据库中仍然是IsPrimary=false,那么您设置的IsPrimary=false对象列表就是worong列表!

你要么必须做以下任何一件事,但都有自己的糟糕之处:

  • 无限制地加载所有对象
  • 或者手动扫描场景以查找所有瞬态/脏对象
  • 或在每次更改IsPrimary后提交

如果可能的话,我建议您从表/类中的布尔字段切换到另一个表/类(只有一个条目(中数据对象类型的引用字段,并将主对象存储在另一个表格/类中。它将自动只允许一个主AND。如果两个会话/用户试图同时创建一个主(比拥有两个主更好:D(,它将导致并发。

也许你的数据结构已经有了一种数据类的父类/父类,并且应该知道IT的主类。

问候Juy Juka

最新更新