Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NHibernate evict by id

Tags:

nhibernate

Everyone knows that there is cache in session. This cache generally could be cleared by 2 methods:

  1. Session.Evict
  2. Session.Clear

Second method removes all cache not only for single entry.

I have business method. It receives id of large object (from aspx site) or sometimes several ids. And do native sql operation in database (using sql-query with complex logic to not load all data in C#). Then I need to invalidate cache. So every potential load of object goes without cache direct from database.

Unfortunately evict accepting only objects. Also its implementation DefaultEvictEventListener has clear separation in code path - separate for proxy and not proxied classes. I have tried simply to create entity, fill id manually and pass it to Evict. This will not works. As I understand Evict by not proxied class use GetHashCode to find and remove object from cache. So if I am not overriding it it will not works. I have a lot native sql batch operations so overriding all GetHashcode in all entities objects will create a lot of work. Also I am not sure is this case removes proxies from cache or no. Update: As far as I have tried for me overriding GetHashCode also not helped. StatefulPersistenceContext.RemoveEntry not found entity because it uses RuntimeHelpers.GetHashCode. So this solution is not even possible

Using sources of NHibernate I have produced following solution:

public static class NHSessionHelper: DefaultEvictEventListener
 public static void RemoveEntityFromCache(this ISession session, Type type, object entityId)
    {
        ISessionImplementor sessionImpl = session.GetSessionImplementation();
        IPersistenceContext persistenceContext = sessionImpl.PersistenceContext;
        IEntityPersister persister = sessionImpl.Factory.GetEntityPersister(type.FullName);

        if (persister == null)
        {
            return;
        }

        EntityKey key = new EntityKey(entityId, persister, sessionImpl.EntityMode);
        persistenceContext.RemoveProxy(key);

        object entity = persistenceContext.RemoveEntity(key);
        if (entity != null)
        {
            EntityEntry e = persistenceContext.RemoveEntry(entity);
            DoEvict(entity, key, e.Persister, (IEventSource)sessionImpl);
        }
    }

It just uses part of NHibenate implementation. But it seem to me not good idea to duplicate code. May be anyone have other ideas?

like image 907
Yauhen.F Avatar asked Nov 05 '10 15:11

Yauhen.F


2 Answers

If you are sure that the object is in the cache, Session.Get(id) will not hit the db. It's probably easiest to do that and then Evict the object you get back:

Model m = Session.Get(id);
Session.Evict(m);

Edit

It is not clear to me if you are talking about the first-level cache or the second-level cache. The above will evict something from the first-level cache. To evict from the second-level cache, use the evict method on SessionFactory.

Edit in response to comment

In that case, you might try Session.Load:

Model m = Session.Load(id);
Session.Evict(m);

If m is in the cache, Session.Load will return the instance which you can evict. If not it returns a proxy (no db hit). My tests suggest that Session.Evict will not throw if you try to evict the proxy, so this should work.

like image 183
Gabe Moothart Avatar answered Oct 02 '22 23:10

Gabe Moothart


It sounds like you could use a Stateless session for this and not bother with cache at all.

like image 41
tom.dietrich Avatar answered Oct 03 '22 00:10

tom.dietrich