Note that there are some explanatory texts on larger screens.

plurals
  1. POQuerying second-level cache in NHibernate
    text
    copied!<h1>The setup</h1> <h2>The mapping</h2> <p>I've got a MyItem class which has a lazy loaded collection consisting of MyDetail items:</p> <pre><code>[Serializable] class MyItem : IComparable, ICloneable { public virtual int ID { get; set; } } [Serializable] class MyDetail : ICloneable { public virtual int ID { get; set; } public virtual MyItem EnclosingItem { get; set; } } void MyItemMap(IClassMapper&lt;MyItem&gt; ca) { ca.Lazy(false); ca.Cache(cm =&gt; { cm.Usage(CacheUsage.NonstrictReadWrite); cm.Region(cacheRegion); }); ca.Id(x =&gt; x.ID, cm =&gt; { cm.Generator(Generators.Native); }); ca.Discriminator(cm =&gt; { cm.Column("Type"); cm.Type(NHibernateUtil.String); }); ca.Bag(x =&gt; x.Details, cm =&gt; { cm.Key(k =&gt; k.Column("ItemID")); cm.Inverse(true); cm.Type&lt;DetailFactory&gt;(); cm.Cascade(Cascade.All | Cascade.DeleteOrphans); cm.Fetch(CollectionFetchMode.Select); cm.Lazy(CollectionLazy.Lazy); cm.Cache(m =&gt; { m.Usage(CacheUsage.NonstrictReadWrite); }); } cr =&gt; cr.OneToMany()); } void MyDetailMap(IClassMapper&lt;MyDetail&gt; ca) { ca.Lazy(true); ca.Cache(cm =&gt; { cm.Usage(CacheUsage.NonstrictReadWrite); cm.Region(cacheRegion); }); ca.Id(x =&gt; x.ID, cm =&gt; { cm.Generator(Generators.Native); }); ca.ManyToOne(x =&gt; x.EnclosingItem, cm =&gt; { cm.Column("ItemID"); cm.NotNullable(true); cm.Fetch(FetchKind.Select); cm.Lazy(LazyRelation.Proxy); }); } </code></pre> <h2>The collection</h2> <p>The class to load the associated MyDetail items is a PersistentGenericBag:</p> <pre><code>class DetailList : PersistentGenericBag&lt;MyDetail&gt; { } </code></pre> <h2>The collection factory</h2> <p>This happens through a custom collection factory:</p> <pre><code>class DetailFactory : IUserCollectionType { public IPersistentCollection Instantiate(ISessionImplementor session, ICollectionPersister persister) { return new DetailList(session); } public IPersistentCollection Wrap(ISessionImplementor session, object collection) { return new DetailList(session, (IList&lt;MyDetail&gt;)collection); } } </code></pre> <h1>The problem</h1> <p>Suppose I've loaded a MyItem and I've requested Details at least once, so my second level cache (SLC) contains all these things. Also suppose I'm only actively using 1 Detail, while there are actually 100 details connected to MyItem. This means that whenever I access MyItem from the SLC and access the one detail I'm interested in, the whole collection is materialized:</p> <pre><code>// Get item coming from SLC MyItem myItem = nhSession.Get(id); // Access detail, materializing all MyDetails from SLC MyDetail myDetail = myItem.Details["Interesting"]; // Normally, this last line will invoke the default NH proxy // which then materializes the Details collections, fetching // all details belonging to myItem from the database, or from // the SLC for that matter. // // To cater for my scenario, I've got access to an interceptor // to do my own processing (the details to how this is hooked // up are not very relevant). This interceptor should somehow // be able to, instead of initializing the collection, return // the result from the SLC rightaway. This would prevent // the materialization of possibly large collections. </code></pre> <h1>Solving the optimization problem</h1> <p>Now I'd like to optimize this scenario by bypassing the collection loading, and directly querying the SLC for presence of that detail. Note that my problem is not intercepting the actual detail call from the code, but intervening in what is returned in what way.</p> <p>I'm using the SysCache, so theoretically I could read out the ASP.NET cache, but since the cache keys are an implementation detail of NH, I'm not sure that's a good idea.</p> <p>Does anyone have a pointer for me?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload