5

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

我们的想法是我们希望能够从集合客户端获取实体、添加、更新和删除它们,然后将这些更改发送到服务器端,在那里它们将被持久化到数据库中。

自我跟踪实体,顾名思义,自己跟踪他们的状态。创建新的 STE 时,它具有已添加状态,当您修改属性时,它会设置已修改状态,它也可以具有已删除状态,但是当从实体中删除时ObservableCollection(显然)不会设置此状态。如果您想要这种行为,您需要自己编写代码。

在我当前的实现中,当从 中删除实体时ObservableCollection,我将其保存在影子集合中,以便在将ObservableCollection发送回服务器时,我可以将删除的项目一起发送,以便 Entity Framework 知道删除它们。

类似于以下内容:

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垃圾回收时,我们无法知道我们需要从字典中删除影子集合。

我想出了一些复杂的解决方案,在这种情况下基本上可以进行手动内存管理。我每隔几秒钟检查一次引用是否处于非活动状态,在这种情况下,我会删除影子集合WeakReferenceObservableCollection

但这似乎是一个糟糕的解决方案......我希望 StackOverflow 的集体天才能够阐明更好的解决方案。

编辑:

最后我决定继承ObservableCollection. 生成了服务代理代码,因此将其更改为返回我的派生类型是一项相对简单的任务。

感谢所有的帮助!

4

3 回答 3

1

HttpRuntime.Cache您可以使用(适用于所有项目类型,而不仅仅是 Web 项目),而不是滚动您自己的“弱引用 + 轮询 Is it Dead, Is it Alive”逻辑。

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

它与您自己的解决方案并没有太大的不同,但它确实使用了久经考验且值得信赖的 .Net 组件

除此之外,您正在考虑扩展 ObservableCollection 并改用该新类(我想这是一个不小的变化),或者更改/包装UpdateCustomers方法以删除阴影收集表单DeletedCollections

对不起,我想不出别的,但希望这会有所帮助。
体重

于 2010-06-03T16:29:43.803 回答
1

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

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

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

顺便说一句,您不关心 GetHashCode() 为不同的集合返回相同的值吗?使用对集合的弱引用可能更适合作为键,那么就没有发生冲突的机会。

于 2010-06-04T04:43:30.453 回答
1

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

但在 1% 的情况下,人们需要意识到他们必须加大赌注并通过加强在这些领域的缓存/内存管理来走“老派”。向您致敬,因为您意识到您处于这种情况并试图避免 IDispose/WeakReference 技巧。我认为你真的会帮助下一个在你的代码中工作的人。

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

- 明确何时需要创建对象 - 明确何时需要销毁对象 - 明确何时需要将对象推送到服务器

祝你好运!告诉我们进展如何:)

于 2010-06-08T04:19:05.463 回答