C
C#2y ago
Kiel

❔ How to prevent hardcoding a cache key when looking it up in a way that isn't hacky?

I currently have an interface which my cache-able DB entities can implement to a) mark them as able to be cached, and b) define how the cache key is formatted:
public interface ICachedDbEntity
{
string CacheKey { get; }
}
public interface ICachedDbEntity
{
string CacheKey { get; }
}
example:
public sealed class GuildConfiguration : ICachedDbEntity
{
public Snowflake Id { get; set; }
string ICachedDbEntity.CacheKey => $"G:{Id}";
}
public sealed class GuildConfiguration : ICachedDbEntity
{
public Snowflake Id { get; set; }
string ICachedDbEntity.CacheKey => $"G:{Id}";
}
Elsewhere, I define convenience methods for obtaining one of these types via a GetOrCreate:
public ValueTask<GuildConfiguration> GetOrCreateGuildConfigAsync(Snowflake guildId)
=> GetOrFetchOrCreateAsync($"G:{guildId}", () => Guilds.FindAsync(guildId).AsTask(), () => GuildConfiguration.Create(guildId));
public ValueTask<GuildConfiguration> GetOrCreateGuildConfigAsync(Snowflake guildId)
=> GetOrFetchOrCreateAsync($"G:{guildId}", () => Guilds.FindAsync(guildId).AsTask(), () => GuildConfiguration.Create(guildId));
The thing I don't like about this, however, is the fact that the ICachedDbEntity interface isn't taken advantage of at all in this GetOrCreate method - I have to hardcode the cache key format. Is there a better solution here? Any suggestions are welcome. Some things I've considered: - Instead of hardcoding the ID in my GetOrCreate (or GetOrFetch) methods, I could new() up an instance of the type and use .CacheKey instead. But that seems like a waste and an unnecessary creation of a type 🤔. - Using reflection in some yet-to-be-thought-of way to accomplish this programmatically. But that seems like it would have a more than negligible performance hit across hundreds or thousands of read calls here.
5 Replies
Saber
Saber2y ago
How about a static method on GuildConfiguration which returns the cache key for a given id that you can call from there, and from the CacheKey property.
Kiel
KielOP2y ago
what would your example look like? This was actually an idea I considered but didn't jot down, the downside is annoyingly that I'd have to implement this static method on every type which implements this interface, which...isn't THAT many (less than 10), but still feels weird like...
// GuildConfiguration.GetCacheKey(guildId)
public static string GetCacheKey(Snowflake guildId)
=> new GuildConfiguration{Id = guildId}.CacheKey;
// GuildConfiguration.GetCacheKey(guildId)
public static string GetCacheKey(Snowflake guildId)
=> new GuildConfiguration{Id = guildId}.CacheKey;
?
Saber
Saber2y ago
No lol. The method would do the string interpolation. CacheKey would also call the method and pass the id GetCacheKey(Snowflake guildId) => $"G:{guildId}";
Kiel
KielOP2y ago
ah
// GuildConfiguration.GetCacheKey(guildId)
public static string GetCacheKey(Snowflake guildId)
=> $"G:{guildId}";

string ICachedDbEntity.CacheKey => GetCacheKey(Id);
// GuildConfiguration.GetCacheKey(guildId)
public static string GetCacheKey(Snowflake guildId)
=> $"G:{guildId}";

string ICachedDbEntity.CacheKey => GetCacheKey(Id);
Only downside is that this actually all started because I wanted to change the prefix for my cached types to their type name instead of an arbitrary single letter prefix, so it was more helpful for logging, so I wanted to be able to prepend {GetType().Name}:, and I wanted to, y'know, not have to hardcode that either there just isn't a solution that covers every base I want pepehands for the help, though!
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server