Подтвердить что ты не робот

Включение и удаление объектов из контекста правильно в EF4.1

Я пытаюсь реализовать механизм кэширования для объектов. И чтобы использовать объекты правильно и плавно с кешированием, мне нужно отделить объект от текущего контекста, прежде чем я поместил его в кеш и приложил его обратно к новому контексту, когда я получу его из кеша. (Мое время жизни зависит от HTTP-запроса)

Требования:

  • Все связанные с ним навигационные свойства (которые я уже заполнил) не должны удаляться при отсоединении объекта.
  • Я могу обновить кешированные элементы, если захочу (поэтому важно правильно привязать их к новому контексту).

Это моя попытка создания класса EntityCache - (ServerCache - это мой класс-оболочка, который подталкивает объект к кешу ASP.NET)

public static class EntityCache
    {
        private static DbContext context
        {
            get
            {
                return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey];
            }
        }

        private static void Detach(object entity)
        {
            var trackedEntity = entity as IEntityWithChangeTracker;
            trackedEntity.SetChangeTracker(null);
            ((IObjectContextAdapter)context).ObjectContext.Detach(entity);
        }

        private static void Attach(object entity)
        {
            ((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity);
        }

        public static void Remove(string key)
        {
            ServerCache.Remove(key);
        }

        public static object Get(string key)
        {
            object output = ServerCache.Get(key);
            if (output != null)
                Attach(output);
            return output;
        }

        public static void ShortCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.ShortCache(key, data);
            }
        }

        public static void LongCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.LongCache(key, data);
            }
        }
    }

Когда я помещаю объект в кеш, он имеет тип DynamicProxy и НЕ настоящий класс.

Прикрепление вообще не работает - я получаю исключение, которое не может иметь объект case, который имеет тип Dynamic_ {blahblah} для IEntityWithKey.

Я только что увидел эти примеры подключения и отсоединения в Интернете и попробовал их, я открыт для любой новой реализации методов Attach/Detach здесь.

Спасибо.

Последующий вопрос -

context.Entry(entity).State = EntityState.Detached;

Работает, но делает все навигационные свойства, которые загружаются NULL, как мы это делаем, сохраняем навигационные свойства и НЕ заменяем (или теряем) их с помощью NULL, когда мы отключаемся от контекста.

4b9b3361

Ответ 1

IEntityWithKey - это интерфейс для других типов объектов. Это для "больших" сущностей. Например, EntityObject реализовать этот интерфейс. Эти объекты не считаются POCO и не поддерживаются API DbContext.

Если вы хотите использовать IEntityWithKey, ваши классы должны его реализовать - это не то, что произойдет автоматически.

Правильное присоединение с API DbContext должно быть:

dbContext.Set(typeof(entity)).Attach(entity); 

и это, надеюсь, также будет работать:

dbContext.Entry(entity).State = EntityState.Unchanged;

Правильное отключение с помощью DbContext API должно быть:

dbContext.Entry(entity).State = EntityState.Detached;

Также вам лучше использовать общие методы вместо object.

Ответ 2

К вашему следующему вопросу:

... как мы можем сохранить навигационные свойства и НЕ замените (или проиграете) их с помощью NULL, когда мы отсоединяемся от контекста...

Я считаю, что невозможно отделить граф объекта от контекста, сохраняя его свойства навигации. Из MSDN:

В независимой ассоциации информация о взаимоотношениях не является поддерживается для отдельного объекта.

Несмотря на то, что это утверждение относится к независимым ассоциациям, это не означает, что свойства навигации сохраняются в связи с внешним ключом (отношения, которые предоставляют свойство внешнего ключа в модели). Да, "Информация о взаимоотношениях" поддерживается, поскольку свойства внешнего ключа (которые являются скалярными свойствами) будут живыми и содержат правильное значение внешнего ключа после отсоединения. Но соответствующие свойства навигации по-прежнему будут null для ссылочных свойств, или для коллекций навигации ссылка будет удалена из коллекции.

Я думаю, что единственный способ отделить полный граф объекта от контекста - либо полностью избавиться от контекста, либо создать копию графика, прежде чем начать отделять исходный граф. Для создания копии потребуется написать методы Clone, которые копируют все свойства и перемещаются по графику или используют "трюк", например this, который сериализует граф в двоичный поток а затем десериализует его обратно на новые объекты. Для этого сущности должны быть сериализуемыми. Также могут возникнуть проблемы с эталонными циклами (которые мы часто используем при использовании двунаправленных навигационных свойств между объектами). (Также обратите внимание, если ваши объекты являются прокси-серверами, которые содержат ссылки на внутренние объекты EF и которые вы, вероятно, не хотите копировать, сериализовывать и десериализовать.)

В этом аспекте Detach не является аналогом Attach, потому что он ведет себя совершенно по-другому: Attach присоединяет весь граф объекта и поддерживает свойства навигации. Detach отделяет только отдельные объекты без связанных объектов и уничтожает свойства навигации. На той же странице, указанной выше:

Отключение влияет только на конкретный объект, переданный методу. Если объект, находящийся в стороне, имеет связанные объекты в контексте объекта, те объекты не отсоединяются.

Я мог представить себе, что это основная причина, по которой API DbContext не имеет объяснительного метода Detach (в отличие от ObjectContext) - отключение рассматривается как дополнительная функция, которая не ведет себя как одна может ожидать.

MSDN упоминает как единственную причину отсоединения объекта от контекста "для сохранения ресурсов" (опять же статья выше):

В приложениях Entity Framework вы можете отсоединять объекты от контекст объекта. Вы можете отсоединять объекты для экономии ресурсов, поскольку выполнение повторяющихся запросов в одном и том же объектном контексте увеличивает требования к памяти контекста объекта.

Я думаю, что этот метод просто не подготовлен и предназначен для работы с объектами после того, как они были отделены от контекста. Основная цель - освободить их для немедленной сборки мусора.