Question

I want to cache a never-changing aggregate which would be accessible by a root object only (all other entities are accessible only by using Reference/HasMany properties on the root object)?

Should I use NHibernate (which we are already using) second-level-cache or is it better to build some sort of singleton that provides access to all entities in the aggregate?

I found a blog post about getting everything with MultiQuery but my database does not support it.

The 'old way' to do this would be to

  • Do a select * from all aggregate tables
  • Loop the entities and set the References and the Collections manually

Something like:

foreach (var e in Entities)
{
    e.Parent = loadedParentEntities.SingleOrDefault(pe => e.ParentId = pe.Id);
}

But surely there is a way to tell NHibernate to do this for me?

Update

Currently I tried merely fetching everything from the db and hope NHibernate does all the reference setting. It does not however :(

var getRoot = Session.Query<RootObject>().ToList();
var getRoot_hasMany = Session.Query<RootObjectCollection>().ToList();
var getRoot_hasMany_ref = Session.Query<RootObjectCollectionReference>().ToList();
var getRoot_hasMany_hasMany = Session.Query<RootObjectCollectionCollection>().ToList();

Domain:

Root objects are getRoot. These have a collection property 'HasMany'. These HasMany have each a reference back to GetRoot, and a reference to another entity (getRoot_hasMany_ref), and a collection of their own (getRoot_hasMany_hasMany). If this doesn't make sense, I'll create an ERD but the actual structure is not really relevant for the question (I think).

This results in 4 queries being executed. (which is good)

However, when accessing properties like getRoot.First().HasMany.First().Ref or getRoot.First().HasMany.First().HasMany().First() it still results in extra queries being executed even altough everything should already be known to the ISession?

So how do I tell NHibernate to perform those 4 queries and then build the graphs without using any proxy properties, ... so that I have access to everything even after the ISession went out of scope?

Was it helpful?

Solution

I think there are several questions in one.

I stopped trying to trick NHibernate too much. I wouldn't access entities from multiple threads, because they are usually not thread safe. At least when using lazy loading. Caching lazy entities is therefore something evil.

I would avoid too many queries by the use of batch size, which is far the cleanest and easiest solution and in most cases "good enough". It's fully transparent to the business logic, which makes it so cool.

I would:

  • Consider not caching the entity at all. Use NH first level cache (say: always load it using session.Get()). Make use of lazy loading when only a small part of the data is used in a single transaction.
  • Is there is a proven need to cache the data, consider to turn off lazy loading at all (by making the entities non-lazy and setting all the collections to non lazy. Load the entity once and cache it. Still consider thread safety when accessing the data while it is still loaded.
  • Should the entities be lazy, because some instances of the same type are not in the cache, consider using a DTO-like structure as cache. Copy all data in a similar class structure which are not entities. This may sound like a lot of additional work, but at the end it will avoid many strange problems and safe you much time.

Usually, query time is less important as flush time. This time is used by NH to find which entities changed in a session. To avoid this, make entities read only if you can.

OTHER TIPS

if the whole object tree never changes (config settings?) then just load them efficiently with all references/collections initialised

using(var Session = Sessionfactory = OpenSession())
{
    var root = Session.Query<RootObject>().FetchMany(x => x.Collection).ToFutureValue();
    Session.Query<RootObjectCollection>().Fetch(x => x.Ref).FetchMany(x => x.Collection).ToFuture();

    // Do something with root.Value
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top