NHibernate выселить по идентификатору - PullRequest
6 голосов
/ 05 ноября 2010

Все знают, что в сессии есть кеш.Этот кэш обычно можно очистить двумя способами:

  1. Session.Evict
  2. Session.Clear

Второй метод удаляет весь кэш не только для одной записи.

У меня есть бизнес-метод.Он получает идентификатор большого объекта (с сайта aspx) или иногда несколько идентификаторов.И сделать нативную SQL-операцию в базе данных (используя SQL-запрос со сложной логикой, чтобы не загружать все данные в C #).Тогда мне нужно аннулировать кэш.Таким образом, каждая потенциальная загрузка объекта обходится без кеша непосредственно из базы данных.

К сожалению, исключают прием только объектов.Также его реализация DefaultEvictEventListener имеет четкое разделение в пути кода - отдельно для прокси и непроксируемых классов.Я попытался просто создать сущность, заполнить идентификатор вручную и передать его в Evict.Это не будет работать.Как я понимаю, Evict не проксируемым классом использует GetHashCode для поиска и удаления объекта из кэша.Так что, если я не переопределю это, это не будет работать.У меня много собственных пакетных операций sql, поэтому переопределение всего GetHashcode во всех объектах сущностей создаст много работы.Также я не уверен, что этот случай удаляет прокси из кэша или нет. Обновление: Насколько я пытался, для меня переопределение GetHashCode также не помогло.StatefulPersistenceContext.RemoveEntry не найден объект, потому что он использует RuntimeHelpers.GetHashCode.Так что это решение даже невозможно

Используя источники NHibernate, я создал следующее решение:

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);
        }
    }

Оно просто использует часть реализации NHibenate.Но мне кажется, не очень хорошая идея дублировать код.Может быть, у кого-то есть другие идеи?

Ответы [ 2 ]

9 голосов
/ 05 ноября 2010

Если вы уверены, что объект находится в кеше, Session.Get(id) не попадет в БД.Это, вероятно, проще всего сделать, а затем Evict объект, который вы получите:

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

Редактировать

Мне не понятно, говорите ли вы окэш первого уровня или кэш второго уровня.Вышесказанное извлечет что-то из кэша первого уровня.Чтобы исключить из кэша второго уровня, используйте метод evict на SessionFactory.

Изменить в ответ на комментарий

В этом случае вы можете попробовать Session.Load:

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

Если m находится в кэше, Session.Load вернет экземпляр, который вы можете выселить.Если нет, он возвращает прокси (без попадания в БД).Мои тесты показывают, что Session.Evict не сработает, если вы попытаетесь выселить прокси, так что это должно работать.

2 голосов
/ 05 ноября 2010

Похоже, вы могли бы использовать для этого сеанс без сохранения состояния и вообще не работать с кешем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...