我们遇到的情况是我们更改了我们实体的属性,但PropertyChanged
事件并未触发。我们正在将此逻辑作为Save的一部分,因此问题似乎是DevForce在Save期间将这样的事件排队的方式。
查看LoadingBlock.Dispose()的代码,我看到了:
public void Dispose()
{
this._entityManager.FireQueuedEvents();
this._entityManager.IsLoadingEntity = this._wasLoadingEntity;
}
在那里有一个竞争条件,你在更改IsLoadingEntity
属性之前触发排队的事件。这意味着在FireQueuedEvents期间生成的任何新事件都将排队(因为IsLoadingEntity
仍然是真的)但是排队的事件将永远不会被触发,因为我们已经解雇了排队事件(我们知道) 。似乎DevForce应该在触发事件之前重置IsLoadingEntity标志。我认为这可以解决我们的问题。
以下是一些可能有助于解释我们案例的代码。我将使用Merge调用而不是SaveChanges,因为它在单元测试中更容易使用:
//Create the main Entity Manager and a test entity
var em = new EntityManager();
var entity = new MyEntity {SID = 123};
em.AttachEntity(entity);
//Create a second copy of the entity and another Entity Manager - this is just so
// we can trigger a merge and see the bad behavior
var copy = new MyEntity { SID = 123, MergeCount = 20 };
var em2 = new EntityManager();
em2.AttachEntity(copy);
//This code is a bit contrived but it's similar to what we are doing in our actual app
em.EntityChanged += (sender, args) =>
{
//If it is a MyEntity that changed and it was from a Merge, increment the MergeCount property
var e = args.Entity as MyEntity;
if (e != null && args.Action == EntityAction.ChangeCurrentAndOriginal)
{
e.MergeCount++;
}
};
//Set up a PropertyChanged event handler to see what properties got changed (according to INotifyPropertyChanged)
var propertiesChanged = new List<string>();
entity.PropertyChanged += (sender, args) => { propertiesChanged.Add(args.PropertyName); };
//Merge the copy entity
em2.CacheStateManager.GetCacheState().Merge(em, RestoreStrategy.Normal);
//At this point, the MergeCount property will be 21 - as expected
Assert.AreEqual(21, entity.MergeCount);
//We should have seen a PropertyChanged event for MergeCount since we changed the property (it was 20 and we set it to 21)
Assert.IsTrue(propertiesChanged.Contains("MergeCount"));
//In the debugger, if we look at em._queuedEvents, we'll see some items in there. One of the items is the PropertyChanged event
// for MergeCount. It 'fired' but was queued...and it will be queued forever because the LoadingBlock is long gone.
我发现我可以从空的实体管理器中执行另一次合并,这将导致先前排队的事件触发。在我们遇到这种情况的一个案例中,这是一个好的解决方法。但我担心可能还有其他地方遇到这个问题,而且解决方法对我们没有用。
答案 0 :(得分:1)
你应该在Dispose逻辑的开头清除IsLoadingEntity标志,我们将为此打开一个错误报告。
如果您能够使用EntityChanging事件而不是EntityChanged,这也可能是一种解决方法。更改事件未排队,因此执行处理程序会导致在处理LoadingBlock之前处理PropertyChanged事件。