9

我们有一个绑定到一个List<T>项目的网格。每当用户点击“刷新”时,都会从数据库中获取更改,并更新绑定列表。我遇到了重复项目被添加到网格中的问题,我不知道为什么。

数据库调用返回两个值:aList<int>已更改的记录 ID,以及已更改List<MyClass>记录的更新数据。我正在调试的现有代码代码找出需要更新的内容如下所示:

public void FindUpdates(IList<MyClass> existingRecords,
                    IList<MyClass> updatedRecords,
                    List<int> updatedIds,
                    out IDictionary<int, int> existing,
                    out IDictionary<int, int> updated,
                    out List<int> updates,
                    out List<int> removes,
                    out List<int> adds)
{
    updates = new List<int>();
    removes = new List<int>();
    adds = new List<int>();

    existing = FindUpdated(existingRecords, updatedIds);
    updated = FindUpdated(updatedRecords, updatedIds);

    if (updatedIds != null)
    {
        // split add/update and remove
        foreach (int id in updatedIds)
        {
            if (!existing.ContainsKey(id))
                adds.Add(id);
            else if (updated.ContainsKey(id))
                updates.Add(id);
            else
                removes.Add(id);
        }

        WriteToLog(updatedIds, adds, updates, removes);
    }
}

private IDictionary<int, int> FindUpdated(IList<MyClass> records, List<int> updatedIds)
{
    IDictionary<int, int> foundItems = new Dictionary<int, int>();

    if (records != null && updatedIds != null)
    {
        for (int i = 0; i < records.Count; i++)
        {
            IMyClass r = records[i] as IMyClass ;
            if (r != null && !r.IsDisposed)
            {
                if (updatedIds.Contains(r.Id))
                {
                    foundItems.Add(r.Id, i);
                }
            }
        }
    }

    return foundItems;
}

调用的结果FindUpdates()是我得到一个Dictionary<Id, Data>现有记录,一个Dictionary<Id, Data>更新的记录来替换它们,以及一个List<int>应该从数据源中添加、删除或更新项目的 Id。

有时,一条记录会两次添加到网格中,我终生无法弄清楚这段代码哪里出错了。

我从其中一个实例中提取了日志文件,并且可以清楚地看到以下事件序列:

  • 项目 #2 添加到数据列表
  • 20 分钟后,第 2 项再次添加到数据列表中

WriteToLog()从第二个添加告诉我

  • updatedIds包含值 1、2 和 3
  • adds包含 1 和 2
  • updates包含 3

根据其他日志条目,我可以清楚地看到第 2 项是之前添加的,并且从未删除过,因此它应该在existingRecords变量中已显示在updates变量中,而不是在adds. 此外,项目#2 在第一次添加和第二次添加之间成功更新了几次,所以理论上代码应该可以工作。我还有一个 UI 的屏幕截图,并在数据网格中显示了项目 #2 的两个副本。

笔记...

  • IsDisposed仅在.Dispose()项目的覆盖方法中设置为 true。我认为这不会发生。

    编辑:从那时起,我添加了一条日志语句,并且可以验证发生这种情况时IsDisposed未设置为true

  • 这种情况现在已经在几个不同的用户身上发生过几次,所以这不仅仅是一次性的事情。我无法按需重现问题。

  • 记录网格可能相当大,平均有几千个项目。

  • 我没有排除 DB 调用返回无效值的想法,或者没有相同项目的列表,但是我不知道这会如何影响结果

  • 有一次我能够看到这个错误,我们正在运行一些测试,其他用户相当频繁地修改记录#2

  • 这一切都在后台线程中运行

  • 根据日志,这一次只运行一次。它在一分钟前运行,然后在 2 分钟后运行。

  • 从日志文件中,我可以看到第 2 项在第二次错误添加之前已正确更新了几次,因此此代码之前确实与现有数据集一起工作过几次。

上面显示的代码中是否有任何内容可能导致这种情况发生?或者也许是 C# 中一个罕见的已知问题,我不知道会发生这种情况?

4

2 回答 2

1

List<T>使用上面的代码没有理由找不到现有项目。

Dictionary<int,int>当我注意到包含项目 ID 和现有列表中项目索引的值的输出值时,我应该已经敲响了警钟。

发生的事情是使用 删除项目existingRecords[existing[id]],其中existing[id]将返回项目的索引existingRecords。为了使它起作用,必须从最大的索引中删除项目。如果较小的索引在较大的索引之前被删除,则较大的索引现在错误 1 ​​个位置,并且错误的项目被删除。

至于为什么我得到重复的项目,那是因为维护了两个集合,一个用于确定项目是否是新的/更新的/删除的,另一个是绑定在 UI 中显示的。第一个集合被错误地更新,而第二个没有,导致项目可能被多次添加到 UI 集合的情况。

我的短期解决方案是对removes集合进行排序,以确保它按每个项目的索引按降序排序。我的长期解决方案是重写代码。:)

于 2014-05-15T14:31:03.727 回答
0
List.Contains(r) 

将尝试在 a.Equals(r) 的列表中查找对象 a。如果 MyClass 没有覆盖 Equals 你不能确定同一个类的两个不同的对象是相等的。我对此并不完全确定:但我认为 equals 使用 GetHashCode(),如果您决定覆盖其中一个,则应该覆盖另一个。

这是关于它的 MSDN:http: //msdn.microsoft.com/en-us/library/bhkz42b3 (v=vs.110).aspx

于 2014-03-05T16:28:56.543 回答