我有一个较旧的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();
然后它返回正确的结果(包括在表单事务中进行的更改)。
这是一个已知的错误吗?除了使用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
答案 0 :(得分:0)
这是一起玩三件事:
这意味着Restrictions.Eq(“ IsPrimary”,true)或Where(x => x.IsPrimary)将(我认为)将在数据库服务器中运行,并且永远不会看到仅在应用程序中更改过的任何数据(aka。没有提交,又称瞬态数据,又称脏数据/对象)。这意味着,如果您的应用程序/会话/聊天中的一个对象中有多个对象具有IsPrimary = true,但您在数据库中仍然设置了IsPrimary = false,则设置为IsPrimary = false的对象列表就是最麻烦的列表。
您要么必须执行以下操作之一,但以自己的方式都不好:
如果可能的话,我建议您从表/类中的布尔字段切换到另一表/类中仅具有一个条目的数据对象类型的引用字段,并在其中存储主要对象其他表/类。如果两个会话/用户尝试同时创建一个主数据库(最好再创建两个主数据库:D),它将自动只允许一个主数据库并且会导致并发。
也许您的数据结构已经对您的数据类具有一种父级/上级类,并且应该知道IT是主要的。
问候 朱伊·朱卡