Troubles with PersistentDictionary

I am converting a .NET Core 3.1 web application from Couchbase 2.7.x client to 3.2.x and am having trouble with PersistentDictionary. I created a simple program to test inserting data, but cannot add more than1 item to the dictionary; throws “Couchbase.Core.Exceptions.KeyValue.PathExistsException”.

Any ideas?

Thanks,
T

try
{
    using (var cluster = await Cluster.ConnectAsync("couchbase://server", "Administrator", "password"))
    {
        var bucket = await cluster.BucketAsync("test-data").ConfigureAwait(false);
        var collection = await bucket.DefaultCollectionAsync().ConfigureAwait(false);
        var dict = collection.Dictionary<Foo>("test-dictionary");
        await dict.ClearAsync().ConfigureAwait(false);
        await dict.AddAsync("Tom", new Foo { Name = "Tom", Age = 50 });
        await dict.AddAsync("Dick", new Foo { Name = "Dick", Age = 30 });
    }
}
catch(Exception ex)
{
    Console.WriteLine($"Exception - {ex.GetType()}, {ex.Message}");
}
type or paste code here

@ticontask

I stumbled on this myself the other day, the fix is already merged. It will be included in the 3.2.5 release due out any day.

@btburnett3

Thanks,
T

@ticontask 3.2.5 is available now

@btburnett3

Thanks, updated my test project this morning and can now add items to the PersistentDictionary.

I have run into a new problem when iterating over the dictionary.

Exception - Newtonsoft.Json.JsonSerializationException, Could not create an instance of type System.Collections.Generic.IEnumerator`1[System.Collections.Generic.KeyValuePair`2[System.String,TestCouchbaseCollection.Foo]]. Type is an interface or abstract class and cannot be instantiated. Path 'Fred', line 1, position 8.

Thanks,
T

                using (var cluster = await Cluster.ConnectAsync("couchbase://dev-docker01", "Administrator", "password"))
                {
                    var bucket = await cluster.BucketAsync("sms-data").ConfigureAwait(false);
                    var collection = await bucket.DefaultCollectionAsync().ConfigureAwait(false);
                    var dict = collection.Dictionary<Foo>("testdatadict");
                    await dict.ClearAsync().ConfigureAwait(false);
                    await dict.AddAsync("Fred", new Foo { Name = "Tom", Age = 50 });
                    await dict.AddAsync("Bill", new Foo { Name = "Dick", Age = 30 });

                    foreach (var item in dict)
                    {
                        Console.WriteLine($"{item.Key} - {item.Value.Name}, {item.Value.Age}");
                    }
                }
            }

@ticontask

Looks like that’s broken, too. I’ve filed an issue to track: https://issues.couchbase.com/browse/NCBC-3050

Also, using sync iteration has some issues, too, I’m planning to add IAsyncEnumerable at some point.

@btburnett3

Thanks for the update. If I have other issues with PersistentDictionary, should I create a new topic, or just keep them in this thread?

Thanks,
T

@ticontask Since this task is still open, here should be fine.

During testing, I noticed that using the “Item” property to update existing data in the collection throws a “System.ArgumentException - An element with the same key already exists in the Dictionary”

                using (var cluster = await Cluster.ConnectAsync("couchbase://server", "Administrator", "password"))
                {
                    var bucket = await cluster.BucketAsync("test").ConfigureAwait(false);
                    var collection = await bucket.DefaultCollectionAsync().ConfigureAwait(false);
                    var dict = collection.Dictionary<Foo>("testdatadict");
                    await dict.ClearAsync().ConfigureAwait(false);
                    await dict.AddAsync("Tom", new Foo { Name = "Tom", Age = 50 }).ConfigureAwait(false);
                    await dict.AddAsync("Dick", new Foo { Name = "Dick", Age = 30 }).ConfigureAwait(false);
                    await dict.AddAsync("Harry", new Foo { Name = "Harry", Age = 40 }).ConfigureAwait(false);

                    // Get Tom from the Dictionary
                    var key = "Tom";
                    var item = dict[key];

                    // Update Age
                    item.Age = 55;
                    dict[key] = item;
                    await Task.Delay(1000).ConfigureAwait(false);

                }

Thanks,
T

@ticontask

You’re right, I see the bug, the setter is forwarding to Add when it should overwrite existing values. I’ve filed another issue to track.

https://issues.couchbase.com/browse/NCBC-3061

I have another issue with PersistentDictionary. TryGetValue with a non-existent key returns true.

            try
            {
                using (var cluster = await Cluster.ConnectAsync("couchbase://server", "Administrator", "password"))
                {
                    var bucket = await cluster.BucketAsync("test-data").ConfigureAwait(false);
                    var collection = await bucket.DefaultCollectionAsync().ConfigureAwait(false);
                    var dict = collection.Dictionary<Foo>("testdatadict");
                    await dict.ClearAsync().ConfigureAwait(false);
                    await dict.AddAsync("Tom:1", new Foo { Name = "Tom-1", Age = 50 }).ConfigureAwait(false);
                    await dict.AddAsync("Tom:3", new Foo { Name = "Tom-3", Age = 40 }).ConfigureAwait(false);

                    for(var i = 1; i <= 3; i++)
                    {
                        var tempKey = string.Format($"Tom:{i}");
                        if (dict.TryGetValue(tempKey, out var tempItem))
                        {
                            Console.WriteLine($"{tempItem.Name}, {tempItem.Age}");
                        }
                        else
                        {
                            Console.WriteLine($"No value exists for key:{tempKey}");
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Exception - {ex.GetType()}, {ex.Message}");
            }

Thanks,
T

Its a bug: https://issues.couchbase.com/browse/NCBC-3073

@ticontask

Fixes for both of these issues have been merged and will arrive soon in release 3.2.6. Thanks for the info.

I saw CouchbaseNetClient for 3.2.6 has come out. Are you going to release Couchbase.Extensions.DependencyInjection 3.2.6 soon? Thanks.

@DongHsu

The team typically doesn’t release the Extensions packages every time they release the main SDK if there are no changes. CouchbaseNetClient 3.2.6 may be safely used with Couchbase.Extensions.DependencyInjection 3.2.5.