如何使用自己的用户类型激活延迟加载属性上的二级缓存?

Dan*_*rth 12 .net c# nhibernate caching fluent-nhibernate

前言:
在我的应用程序中,我将原始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; }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

映射很简单(注意:这不是我的映射,我使用的是约定,但它是等效的):

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>();
    }
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*Ide 2

您可以使用私有静态缓存来完成此操作。设置起来需要做更多的工作,但不需要对域模型进行额外的类或公共更改。一个很大的缺点是条目不会从缓存中删除,但您可以使用自定义集合或限制条目数量的“全局”缓存。

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;
        }
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

映射:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

针对评论进行编辑:

我不认为可以在用户类型中实现此目的,因为 IDataReader 已在 NullSafeGet 中打开。我认为您可以在实现 IPreLoadEventListener 的侦听器中执行此操作,但这不允许您使缓存无效。我认为这两种选择都不可行。

经过更多思考后,我仍然认为我原来的解决方案(或变体)是最好的选择。我理解(并分享)您对干净域模型的渴望,但有时妥协是必要的,并且我的解决方案不会更改模型的公共成员或需要任何额外的引用。另一个理由是该对象是第一个知道记录已更改并且需要在缓存中替换或添加到缓存中的对象。