如果排队事件在调用FireQueuedEvents

时间:2015-06-02 22:54:06

标签: c# events devforce

我们遇到的情况是我们更改了我们实体的属性,但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.

我发现我可以从空的实体管理器中执行另一次合并,这将导致先前排队的事件触发。在我们遇到这种情况的一个案例中,这是一个好的解决方法。但我担心可能还有其他地方遇到这个问题,而且解决方法对我们没有用。

1 个答案:

答案 0 :(得分:1)

你应该在Dispose逻辑的开头清除IsLoadingEntity标志,我们将为此打开一个错误报告。

如果您能够使用EntityChanging事件而不是EntityChanged,这也可能是一种解决方法。更改事件未排队,因此执行处理程序会导致在处理LoadingBlock之前处理PropertyChanged事件。