Tired of magical strings for Redis hashes?

Elgars Logins
3 min readSep 8, 2018

--

If you have worked with different data types in Redis, you most likely have used hashes. Initially it looks like a great idea, to have ability for manipulating particular keys only instead of whole object.

Passing “string” key names, serializing and deserializing values manually. It might look an OK solution, for beginning, but once your object gets more complex, with more fields and types. It quickly becomes a mess, when keys become a magical strings, because of developer laziness. Besides that, values set can became of invalid type, it takes time for developer to open object class definition, find property by name and check type of property value before setting it — serialized value, might not match with expected format when deserializing.

// BAD EXAMPLE ON HOW THINGS OFTEN LOOK LIKEvar productProperties = new RedisValue[] {
"Id",
"Name",
"Url",
"....",
"..."
};
product.Category = redisValues[1].HasValue ? redisValues[1].ToString() : "";
product.IsOnDiscount = redisValues[14].HasValue ? bool.Parse(redisValues[14]) : false;
....
product.Breadcrumb = JsonConvert.DeserializeObject < IList < BreadCrumbItem >> (redisValues[72].HasValue ? redisValues[72].ToString() : "");

What is most common fix?

Constants. People do use constants, that can partly help for keeping track on where which key is being used and would make it easier to see usages or rename it.

But, accessing values and parsing is as bad as it was before. Still using numbers for index positions.

How it can be improved?

As an proof of concept, I have been working on a project called STRHM ( aka Strongly Typed Redis Hashset Model).

Its idea is to expose as much as possible strongly typed properties and reduce amount of work for developer when getting and settings values into Redis hashes.

Example usage of result.

This paragraph shows the result we achieve by using STRHM approach. Let’s say, we have a book store, book has properties as id, rating, published date, authors and so on …

var updatedBook = await _bookRepository.HashGetAsync(book.Id.ToString(),
b => b.Id,
b => b.PublishedOn,
b => b.Authors,
b => b.Rating
);

That’s better, because book repository expects book class to be used, it knows what properties can be used when we want to get values out of hash.

Accessing and converting values is simple as possible:

// Check if value is set on property
if (updatedBook.HasValue(b => b.Rating))
// Get values
updatedBook.Get<IEnumerable<Author>>(b => b.Authors)
updatedBook.Get<int?>(b => b.Rating)

So far, we have looked at how values can be get from Redis and parsed/deserialized into desired type of object.

We are done with getting values, now what about setting them?

// To updated particular keys with particular valuesawait _bookRepository.HashSetAsync(book.Id.ToString(), new StronglyTypedDictionary<Book>(Serializer)
{
{ b => b.Rating, 10 },
{ b => b.Authors, new List<Author>()},
{ b => b.PublishedOn, DateTime.Now }
}
);
// OR, if you want to set whole object into hashawait _bookRepository.SaveAsync(book.Id.ToString(), book);

How does it work and how to start using it

STRHM package consists of basic classes, allowing you to define how you configure Redis connections, exposes parameters for your repositories to extend functionality if needed.

STRHM is based on StackExchange.Redis, and for serialization it is your decision what library to use — Newtonsoft.Json, Jil or anything else. By default you can use STRHM Newtonsoft Serialization Package, or implement your own version of IStronglyTypedRedisSerializer .

More information and examples you can find on GitHub.

Thanks for reading and I hope you can find usage of this approach! :)

--

--