如何在具有自己用户类型的延迟加载属性上激活二级缓存
本文关键字:延迟加载 属性 二级缓存 激活 类型 用户 自己 | 更新日期: 2023-09-27 18:14:13
前言:
在我的应用程序中,我将原始WAV数据作为byte[]
存储在数据库中。在我的域模型中,有一个类PcmAudioStream
表示原始WAV数据。我创建了NHibernate的IUserType
的实现,以便在我的类和byte[]
之间进行转换
有几个类使用PcmAudioStream
类,所有这些类都映射到数据库表。为了避免在从这样的表中检索行时总是加载所有WAV数据,我创建了Fluent NHibernate的IUserTypeConvention
的实现,该实现指定这些属性应该始终延迟加载
所有这些都很有魅力。
问题:
因为这些PcmAudioStream
的内容很少更改,所以我想将检索到的实例放在二级缓存中。现在,我知道如何为一个完整的类激活二级缓存,但如何仅为懒惰加载的属性实现这一点?
我的域模型的相关部分如下:
public class User : Entity
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual PcmAudioStream FullNameRecording { get; set; }
// ...
}
映射很简单(注意:这不是我的映射,我使用的是一个约定,但它是等效的(:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.FullNameRecording).CustomType<PcmAudioStreamAsByteArray>();
}
}
您可以使用专用静态缓存来实现这一点。这需要做更多的设置工作,但不需要对域模型进行额外的类或公共更改。一个很大的缺点是,条目不会从缓存中删除,但您可以使用自定义集合或"全局"缓存来限制条目的数量。
public class Entity
{
public virtual int Id { get; protected set; }
}
public class PcmAudioStream
{}
public class User : Entity
{
private static readonly IDictionary<int, PcmAudioStream> _fullNameRecordingCache;
private PcmAudioStream _fullNameRecording;
static User()
{
_fullNameRecordingCache = new Dictionary<int, PcmAudioStream>();
}
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual PcmAudioStream FullNameRecording
{
get
{
if (_fullNameRecordingCache.ContainsKey(Id))
{
return _fullNameRecordingCache[Id];
}
// May need to watch for proxies here
_fullNameRecordingCache.Add(Id, _fullNameRecording);
return _fullNameRecording;
}
set
{
if (_fullNameRecordingCache.ContainsKey(Id))
{
_fullNameRecordingCache[Id] = value;
}
_fullNameRecording = value;
}
}
// ...
}
映射:
public class UserMap : ClassMap<User>
{
public UserMap()
{
Id(x => x.Id);
Map(x => x.FirstName);
Map(x => x.LastName);
Map(x => x.FullNameRecording).CustomType<PcmAudioStreamAsByteArray>()
.Access.CamelCaseField(Prefix.Underscore);
}
}
根据评论编辑:
我认为在用户类型中不可能实现这一点,因为IDataReader已经在NullSafeGet中打开。我认为您可以在实现IPreLoadEventListener的侦听器中执行此操作,但这不允许您使缓存无效。我认为这两种选择都不可行。
经过进一步思考,我仍然认为我的原始解决方案(或变体(是最好的选择。我理解(并同意(您对干净域模型的渴望,但有时妥协是必要的,我的解决方案不会改变模型的公共成员,也不需要任何额外的引用。另一个理由是,对象是第一个知道记录已更改,需要在缓存中替换或添加到缓存的对象。
我不确定是否只缓存单个属性,但我的猜测是NH缓存基础设施不是这样构建的。IMHO您可以将整个类实例或查询结果放入二级缓存。
但我会尝试草拟一个解决方案。
在NH3和对懒惰属性的支持之前,如果你不想从DB加载整个实体(在你的情况下,这完全有意义!(,你必须将这样"昂贵"的数据保存在一个引用的、懒惰加载的表中。至少我是这样解决的。
这看起来像是后退了一步,但使用这种方法,我非常确信您将能够缓存这些数据。
另一方面,NH3+中的缓存和QueryOver似乎存在问题:https://nhibernate.jira.com/browse/NH-2740