Redis SetRangeInHash with nullable types

When using Redis.SetRangeInHash<T>, it might be nice to extend some options, for example, allowing a Dictionary<string,object> where the object is ToString’d automatically. Using the ToStringDictionary ext method is nice, but it is missing a parameter in my opinion (that I have added for my purposes … yay ext methods!), and that is a switch to include nullable types as null or empty strings (like in the JsConfig).

Now for using SetRangeInHash, I call ToObjectDictionary, then iterate and add each to a new string dictionary with string.empty for null objects.

Would be awesome to have that built right into the StoreAsHash method without needing to wrap it with a custom jsconfig using block.

Thoughts?

This is hard to follow without a concrete example, can you provide the overloaded method signatures you’re proposing?

I haven’t tested this fully, but seems to work approach is:

public static void StoreAsHash<T>(this IRedisClient redis, T obj, bool includeNull)
    {
        if (obj == null)
            return;

        var key = obj.ToUrn();
        redis.SetRangeInHash(key, obj.ToStringDictionary(includeNull));
    }

public static Dictionary<string, string> ToStringDictionary<T>(this T obj, bool includeNull)
    {
        if (includeNull == false)
            return obj.ToStringDictionary();

        var result = new Dictionary<string, string>(50);

        obj.ToObjectDictionary().Each(
            (i, kvp) => result.Add(kvp.Key, kvp.Value.ToStringNotnull()));

        return result;
    }

ToStringNotNull is also an ext method I use frequently when I want to ensure a string.

Calling the method is exposed fairly straightforward: Redis.StoreAsHash(something, true);

If there is a faster (in perf) way to do this, I’m all ears.

This isn’t very intuitive as to what the behavior would be and how it differs with the overloaded method. Adding a new overload for different behavior quickly leads to a confusing surface area where users wont know which API they should use.

IMO the primary use for this is to change how StoreAsHash is serialized so I’ve made the behavior configurable in this commit where you can now override how StoreAsHash serializes the object, e.g:

RedisClient.ConvertToHashFn = o =>
{
    var map = new Dictionary<string, string>();
    o.ToObjectDictionary().Each(x => map[x.Key] = (x.Value ?? "").ToJsv());
    return map;
};

var dto = new HashTest { Id = 1 };
Redis.StoreAsHash(dto);
storedHash = Redis.GetHashKeys(dto.ToUrn());  //= Id, Name

I agree that the overload in the method isn’t as clear and keeps the possible confusion for others (which one do I use again?).

I like your approach, looks good. Not sure how easily discoverable this functionality will be for new users tho.

ps: Didn’t realize you could populate a Dictionary like that without explicitly using Add.

FYI this is now available from v4.0.47 that’s now on MyGet.

There are a lot of features that are hard to discover without searching for it, they basically just get mentioned in release notes and hopefully returned in search results if they look for it, otherwise it’s always available if they ever inspect/debug/decompile the source code.