如果在调用FireQueuedEvents期间排队,DevForce并不总是触发排队事件

本文关键字:排队 事件 调用 FireQueuedEvents 如果 DevForce | 更新日期: 2023-09-27 17:52:57

我们正在遇到这样的情况:我们改变了实体的属性,但PropertyChanged事件没有触发。我们正在做这个逻辑作为保存的一部分,所以问题似乎是DevForce在保存期间这样排队事件的方式。

查看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.

我发现我可以从一个空的实体管理器做另一个合并,这将导致以前排队的事件触发。在我们遇到这种情况时,这是个不错的变通方法。但我担心可能在其他地方我们会遇到这个问题,而这种解决方法对我们不起作用。

如果在调用FireQueuedEvents期间排队,DevForce并不总是触发排队事件

你是对的,IsLoadingEntity标志应该在Dispose逻辑的开始被清除,我们将为此打开一个bug报告。

如果你能够使用EntityChanging事件而不是EntityChanged,这也可能是一个变通的尝试。更改事件没有排队,因此处理程序的执行导致PropertyChanged事件在LoadingBlock被处置之前被处理。