Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I've got this working, but the net effect is that my app is now even taking longer. As this doesn't make sense to me yet, I'm still investigating, but I'll post the code already anyway.</p> <p>First I hooked up a listener. It inserts an extra mapping everytime a MyDetail is saved. That means that, besides having the ID's of MyDetail in the SLC, I can also look them up by EnclosingItem.ID and MyDetail.Name.</p> <pre><code>class PostLoadListener : IPostLoadEventListener { public void OnPostLoad(PostLoadEvent @event) { // Only act when MyDetail is loaded var detail = @event.Entity as MyDetail; if (detail == null) return; ISessionImplementor session = @event.Session; var persister = @event.Persister; // Still tak into account caching settings (copied over these checks from NH) if (persister.HasCache == false || ((session.CacheMode &amp; CacheMode.Put) != CacheMode.Put)) return; // Create the mapping by combining the collection ID and the detail // name, which together are being mapped to the actual detail ID var id = detail.EnclosingItem.ID + "#" + detail.Name; var cacheKey = new CacheKey(id, NHibernateUtil.String, PersistentContentDetailsList.IdMapRole, session.EntityMode, session.Factory); // Cache the mapping [detail.EnclosingItem.ID#detail.Name] =&gt; [detail.ID] persister.Cache.Put(cacheKey, detail.ID, session.Timestamp, null, null, true); } } </code></pre> <p>Then, I made sure my DetailList does the aforementioned lookups when applicable:</p> <pre><code>class DetailList : PersistentGenericBag&lt;MyDetail&gt; { public MyDetail this[string name] { get { MyDetail detail; TryGetValue(name, out detail); return detail; } set { /* */ } } private IList&lt;ContentDetail&gt; List { get { return this; } } /* * If the collection was already initialized, it doesn't make sense * to reach for the SLC, so skip it in that case. If it wasn't, * then try to fetch from the SLC. If the detail wasn't found there, * initialize the collection by triggering the enumerator and * subsequently find the detail by name. */ public bool TryGetValue(string name, out MyDetail value) { return (value = WasInitialized ? List.FirstOrDefault(i =&gt; i.Name == name) : (GetCachedDetail(name) ?? List.FirstOrDefault(i =&gt; i.Name == name)) ) != null; } /* * GetCachedDetail uses the collection identifier, combines it with * the detail name, and tries to find that mapping in the SLC. * If it exists, the ID is returned. So basically, you get to know * which MyDetail to fetch from the SLC when you know its EnclosingItem * and its name. */ private ContentDetail GetCachedDetail(string name) { var mapId = Key + "#" + name; var persister = Session.Factory.GetEntityPersister(typeof(ContentDetail).FullName); var key = new CacheKey(mapId, NHibernateUtil.String, IdMapRole, Session.EntityMode, Session.Factory); var cacheEntry = persister.Cache.Get(key, Session.Timestamp); // This last step might be optimized by only executing the relevant // loading statements of the Session.Load invocation chain return cacheEntry != null ? ((ISession)Session).Load&lt;MyDetail&gt;((int)cacheEntry) : null; } } </code></pre>
 

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