使用 Redis、key 或 ID 存储对象标识符
本文关键字:ID 存储 对象标识符 key Redis 使用 | 更新日期: 2023-09-27 18:36:33
我有一个主基类,用于(几乎)我应用程序中的所有 POCO 类。
public abstract class AceOfBase
{
public long Id { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public string Key { get; set; }
}
我的一些主要类(Member , Building, Community, etc.
)具有相当多的属性,因此我计划利用ServiceStack的强类型客户端提供的简单管理。
从我所做的研究中,客户似乎使用结构化方法来创建密钥
本质上,POCO作为序列化的JSON存储在Redis中,类型为(Poco)。名称和用于形成该实例的唯一键的 ID。例如:
urn:Poco:{Id} => '{"Id":1,"Foo":"Bar"}'
因为有时我会检索一个继承基类的对象(但我不知道编译时的派生类),我怎样才能最好地存储密钥以便我可以轻松获取任何对象?
一个理想的世界,我将能够配置RedisClient
和RedisTypedClient
以对键使用相同的命名约定,但我还没有找到任何可以让我这样做的东西(还没有),并且很难获得有关单个方法的文档对于两个客户端来说。
在深入研究 ServiceStack 程序集后,我发现强类型客户端的 Store()
方法实际上只是与用于生成密钥结构的实用程序方法SetEntry(key,value)
。
实用工具方法 IdUtils.CreateUrn
具有一些重载,允许您指定 Type
和 Id
,然后返回用作键的字符串。
然后,我所做的是在我的 Repository 基类中编写一个 CreateKey
方法,然后在创建任何AceOfBase
对象并将其设置为 Key
时调用该方法。
//In BaseRepository
public virtual string CreateKey<T>(T entity) where T : AceOfBase
{
return IdUtils.CreateUrn<AceOfBase>(entity.Id);
}
//In MemberRepository
Member m = new Member(); //inherits from AceOfBase
m.Key = CreateKey(m);
我还在我的应用程序中实现了两组类,这些类帮助我利用 Redis 疯狂的快速查询时间,同时允许我像使用 EF 一样正常使用关系。
DomainModels -- 这些看起来像普通类,因为它们的属性传统上是结构化的。
public class Activity : AceOfBase { public AceOfBase IndirectObject { get; set; } public Participant Predicate { get; set; } public Participant Subject { get; set; } public Verb Verb { get; set; } }
DataModels -- 这些包含与其 DomainModel 对应项相同的原语和枚举,但如果字段是存储在 Redis 中的自定义类型,则会将其替换为表示该对象的键的字符串(具有相同的属性名称)。
public class Activity : AceOfBase { public string IndirectObject { get; set; } public string Predicate { get; set; } public string Subject { get; set; } public Verb Verb { get; set; } }
我已经使用一组自定义TypeConverter
类实现了AutoMapper
,这些类完成了将DataModel
字符串属性转换为DomainModel
中具有相同名称的相应属性的繁重工作。 然后,AutoMapper
在存储任何对象之前以及从 Redis 中提取对象并在两种模型类型之间转换后立即被调用。
//In Configure()
Mapper.CreateMap<string,Member>().ConvertUsing<KeyToBaseConverter<Member>>();
Mapper.CreateMap<Member, string>().ConvertUsing<BaseToKeyConverter<Member>>();
public class KeyToBaseConverter<T> : ITypeConverter<string, T> where T : AceOfBase
{
public RedisRepository Repository { get; set; }
public T Convert(ResolutionContext context)
{
return Repository.GetByKey<T>(context.SourceValue.ToString());
}
}
public class BaseToKeyConverter<T> : ITypeConverter<T, string> where T : AceOfBase
{
public string Convert(ResolutionContext context)
{
var f = context.SourceValue as AceOfBase;
return f.Key;
}
}
剩下唯一需要解决的组件是确保我创建的任何Lists
或Sets
为其密钥获得相同的格式。
使用此架构,我将能够无缝地将强类型客户端与字符串客户端一起使用,确保即使在没有强类型客户端的情况下拉取对象时,我也可以通过仅检查 Key 属性来确定并将 JSON blob 安全地转换为正确的类型。