Everyone knows that there is cache in session. This cache generally could be cleared by 2 methods:
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?
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.
It sounds like you could use a Stateless session for this and not bother with cache at all.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With