NHibernate выселить по id

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

  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 ответа

Решение

Если вы уверены, что объект находится в кеше, 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 не будет выбрасывать, если вы попытаетесь выселить прокси, так что это должно работать.

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

Другие вопросы по тегам