Preface:
In my application, I store raw WAV data in the database as byte[]. In my domain model there is a class PcmAudioStream that represents that raw WAV data. I created an implementation of NHibernate’s IUserType to convert between my class and byte[].
There are several classes that use the PcmAudioStream class, all of which are mapped to database tables. To avoid always loading all WAV data when retrieving a row from such a table, I created an implementation of Fluent NHibernate’s IUserTypeConvention that specifies that those properties should always be lazy loaded.
All of this works like a charm.
Question:
Because the content of these PcmAudioStreams rarely ever changes, I want to put retrieved instances in the second level cache. Now, I know how to activate the second level cache for a complete class, but how do I achieve this only for a lazy loaded property?
The relevant part of my domain model looks like this:
public class User : Entity
{
public virtual string FirstName { get; set; }
public virtual string LastName { get; set; }
public virtual PcmAudioStream FullNameRecording { get; set; }
// ...
}
The mapping is simple (note: that is not my mapping, I am using a convention, but it is equivalent):
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>();
}
}
You could use a private static cache to accomplish this. It’s a little more work to set up but doesn’t require an additional class or public changes to your domain model. A big drawback is that entries are not removed from the cache, but you could use a custom collection or a “global” cache that limits the number of entries.
Mapping:
Edited in response to comments:
I don’t see that it’s possible to achieve this in a user type because the IDataReader is already open in NullSafeGet. I think you could do it in a listener implementing IPreLoadEventListener but that doesn’t allow you to invalidate the cache. I don’t think either option is viable.
After thinking about it some more I still think my original solution (or a variant) is the best option. I understand (and share) your desire for a clean domain model but sometimes compromises are necessary and my solution does not change the public members of the model or require any additional references. Another justification is that the object is the first to know that the recording has changed and needs to be replaced in or added to the cache.