Skip to content

Commit

Permalink
Fix cache.Group MissingKeyException Fixes #527 (#666)
Browse files Browse the repository at this point in the history
  • Loading branch information
RolandPheasant committed Nov 25, 2022
1 parent b44fdee commit 9f7638f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 13 deletions.
37 changes: 37 additions & 0 deletions src/DynamicData.Tests/Cache/GroupFixture.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
Expand All @@ -22,6 +23,42 @@ public GroupFixture()
_source = new SourceCache<Person, string>(p => p.Name);
}

[Fact]
public void Kaboom()
{
SourceCache<Mytype, int> cache = new(x => x.Key);
List<Mytype> listWithDuplicates = new()
{
new(1, "G1"),
new(1, "G2"),
};
cache
.Connect()
.Group(x => x.Grouping)
.Subscribe();

cache.Edit(x =>
{
x.AddOrUpdate(listWithDuplicates);
x.Clear();
x.AddOrUpdate(listWithDuplicates);
});
}

class Mytype
{
public Mytype(int key, string grouping)
{
Key = key;
Grouping = grouping;
}

public int Key { get; set; }
public string Grouping { get; set; }

public override string ToString() => $"{Key}, {Grouping}";
}

[Fact]
public void Add()
{
Expand Down
18 changes: 5 additions & 13 deletions src/DynamicData/Cache/Internal/GroupOn.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,7 @@ public Grouper(Func<TObject, TGroupKey> groupSelectorKey)

// 1. iterate and maintain child caches (_groupCache)
// 2. maintain which group each item belongs to (_itemCache)
grouped.ForEach(
group =>
grouped.ForEach(group =>
{
var groupItem = GetCache(group.Key);
var groupCache = groupItem.group;
Expand All @@ -119,22 +118,16 @@ public Grouper(Func<TObject, TGroupKey> groupSelectorKey)
switch (current.Reason)
{
case ChangeReason.Add:
{
groupUpdater.AddOrUpdate(current.Item, current.Key);
_itemCache[current.Key] = current;
break;
}
case ChangeReason.Update:
{
groupUpdater.AddOrUpdate(current.Item, current.Key);
// check whether the previous item was in a different group. If so remove from old group
var previous = _itemCache.Lookup(current.Key).ValueOrThrow(() => new MissingKeyException($"{current.Key} is missing from previous value on update. Object type {typeof(TObject).FullName}, Key type {typeof(TKey).FullName}, Group key type {typeof(TGroupKey).FullName}"));
var previous = _itemCache.Lookup(current.Key);
if (!EqualityComparer<TGroupKey>.Default.Equals(previous.GroupKey, current.GroupKey))
if (previous.HasValue && !EqualityComparer<TGroupKey>.Default.Equals(previous.Value.GroupKey, current.GroupKey))
{
_groupCache.Lookup(previous.GroupKey).IfHasValue(
_groupCache.Lookup(previous.Value.GroupKey).IfHasValue(
g =>
{
g.Update(u => u.Remove(current.Key));
Expand All @@ -146,10 +139,9 @@ public Grouper(Func<TObject, TGroupKey> groupSelectorKey)
_groupCache.Remove(g.Key);
result.Add(new Change<IGroup<TObject, TKey, TGroupKey>, TGroupKey>(ChangeReason.Remove, g.Key, g));
});
_itemCache[current.Key] = current;
}
_itemCache[current.Key] = current;
break;
}
Expand Down

0 comments on commit 9f7638f

Please sign in to comment.