如何跟踪在CRUD场景中从ObservableCollection中删除的对象?

时间:2010-06-01 09:56:58

标签: entity-framework observablecollection lifecycle self-tracking-entities

在我们的多层业务应用程序中,我们有ObservableCollections个从服务调用返回的自我跟踪实体。

我们希望能够从集合客户端获取实体,添加,更新和删除实体,然后将这些更改发送到服务器端,并将它们保存到数据库中。

自我跟踪实体,正如其名称所暗示的那样,可以自行跟踪其状态。 当创建新STE时,它具有已添加状态,当您修改属性时,它设置已修改状态,它也可以具有已删除状态,但是当从ObservableCollection中删除实体时,不会设置此状态(明显)。如果你想要这种行为,你需要自己编写代码。

在我当前的实现中,当一个实体从ObservableCollection中删除时,我将它保存在一个阴影集合中,这样当ObservableCollection被发送回服务器时,我可以发送删除的项目沿着,因此实体框架知道删除它们。

有些事情:

protected IDictionary<int, IList> DeletedCollections = new Dictionary<int, IList>();

protected void SubscribeDeletionHandler<TEntity>(ObservableCollection<TEntity> collection)
{
    var deletedEntities = new List<TEntity>();
    DeletedCollections[collection.GetHashCode()] = deletedEntities;

    collection.CollectionChanged += (o, a) =>
        {
            if (a.OldItems != null)
            {
                deletedEntities.AddRange(a.OldItems.Cast<TEntity>());
            }
        };
}

现在,如果用户决定将更改保存到服务器,我可以获取已删除项目的列表,并将其发送到:

ObservableCollection<Customer> customers = MyServiceProxy.GetCustomers();

customers.RemoveAt(0);

MyServiceProxy.UpdateCustomers(customers);

此时,如果删除了任何项目,UpdateCustomers方法将验证我的阴影收集,并将它们发送到服务器端。

这种方法很好,直到你开始考虑这些影子集合的生命周期。基本上,当ObservableCollection被垃圾收集时,无法知道我们需要从字典中删除阴影集合。

我提出了一些复杂的解决方案,在这种情况下基本上都是手动内存管理。我向WeakReference保留了ObservableCollection,每隔几秒钟检查一次参考是否处于非活动状态,在这种情况下我会删除阴影集合。

但这似乎是一个可怕的解决方案......我希望StackOverflow的集体天才可以为更好的解决方案提供帮助。

编辑:

最后我决定继承ObservableCollection的子类。生成服务代理代码,因此更改它以返回我的派生类型是一个相对简单的任务。

感谢您的帮助!

3 个答案:

答案 0 :(得分:1)

您可以使用HttpRuntime.Cache(可从所有项目类型中获取,而不仅仅是Web项目),而不是滚动您自己的“弱引用+民意调查是否死亡,是否活着”逻辑。

将每个影子集合添加到缓存中,或者使用大量超时,或者委托可以检查原始集合是否仍然存在(或两者都有)。

与您自己的解决方案不同可怕,但它确实使用了经过尝试和信任的.Net组件。

除此之外,您正在考虑扩展ObservableCollection并使用该新类(我想象这是一个不小的改动),或者更改/包装UpdateCustomers方法以删除阴影集合形式{{ 1}}

抱歉,我想不出别的什么,但希望这会有所帮助 BW

答案 1 :(得分:1)

如果有可能替换ObservableCollection(例如,如果您对所有集合实例使用公共工厂),则可以继承ObservableCollection并添加Finalize方法,该方法清除属于此集合的已删除项目。

另一种方法是更改​​计算删除项目的方式。您可以维护原始集合,并为客户端提供浅表副本。当收集回来时,您可以比较两者以查看哪些项目不再存在。如果对集合进行排序,则可以在线性时间内对集合的大小进行比较。如果它们未被排序,则修改后的集合值可以放在哈希表中,并用于查找原始集合中的每个值。如果实体具有自然id,则将其用作密钥是确定返回集合中不存在哪些项目的安全方式,即已删除。这也是线性时间。

否则,您的原始解决方案听起来并不那么糟糕。在java中,WeakReference可以注册在清除引用时调用的回调。 .NET中没有类似的功能,但使用轮询非常接近。我不认为这种方法是如此糟糕,如果它有效,那么为什么要改变呢?

顺便说一下,你不关心GetHashCode()为不同的集合返回相同的值吗?使用对集合的弱引用可能更适合作为键,因此不存在碰撞的可能性。

答案 2 :(得分:1)

我认为你走的是一条好路,我会考虑在这种情况下进行重构。我的经验是,在99%的情况下,垃圾收集器使内存管理变得非常棒 - 几乎不需要真正的工作。

但在1%的情况下,需要有人意识到他们必须通过加强他们在这些领域的缓存/内存管理来提高赌注和“旧学校”。向你致意,因为你意识到自己处于这种状况,并试图避免使用IDispose / WeakReference技巧。我想你真的会帮助下一个在你的代码中工作的人。

至于获得解决方案,我认为你已经很好地掌握了这种情况

- 在需要创建对象时清楚 - 当你的物体需要被摧毁时清楚 - 当你的对象需要被推送到服务器时清楚

祝你好运!告诉我们它是怎么回事:))