#entity-framework #integration-testing #automapper #code-first
#entity-framework #интеграция-тестирование #automapper #сначала код
Вопрос:
Я хочу создать интеграционный тест, который извлекает объект EF из базы данных, клонирует его в отдельный объект, изменяет его, а затем сохраняет обратно и снова сравнивает с оригиналом.
Тем не менее, я использовал AutoMapper для создания клона класса, но оказывается, что это также отслеживается или является псевдонимом исходного объекта. Мне нужно, чтобы он был полностью отделен от EF, и я могу сделать это вне моего класса репозитория (т. Е. не используя никаких методов отсоединения EF).
Причина этого в том, что мой класс EF содержит вложенные коллекции других классов, а EF не обрабатывает сохранение всего дерева объектов. Следовательно, мой метод Update() в моем классе репозитория обрабатывает это, и я хочу, чтобы мой тест NUnit тестировал этот код. Я хочу, чтобы тест позволял быстро создавать копию моего исходного класса без отслеживания EF.
Комментарии:
1. Я думаю, что это нечто подобное, это тест сопоставления для объектов EF Code First: valueinjecter.codeplex.com /… , хотя это не automapper
Ответ №1:
Создание клонированного объекта, содержащего текущие, исходные значения или значения базы данных Объект DbPropertyValues, возвращаемый из CurrentValues, OriginalValues или GetDatabaseValues, может быть использован для создания клона объекта. Этот клон будет содержать значения свойств из объекта DbPropertyValues, используемого для его создания. Например:
using (var context = new UnicornsContext()) { var unicorn = context.Unicorns.Find(1); var clonedUnicorn = context.Entry(unicorn).GetDatabaseValues().ToObject(); }
Обратите внимание, что возвращаемый объект не является сущностью и не используется
отслеживается контекстом. Возвращаемый объект также не имеет
отношения, установленные для других объектов.Клонированный объект может быть полезен для решения проблем, связанных с одновременными обновлениями базы данных, особенно там, где используется пользовательский интерфейс, который включает привязку данных к объектам определенного типа. (Смотрите часть 9 для получения более подробной информации о работе с оптимистичным параллелизмом.)
Надеюсь, это поможет другим
Комментарии:
1. Привет, спасибо за код, я мог бы попробовать это, когда столкнусь с этим сценарием в будущем.
2. Большое спасибо за этот фрагмент кода. Я использовал его для копирования / клонирования объекта EF 5. Когда объект добавляется в базу данных с контекстом. MyEntity. Add(clonedEntity) также сохраняет отношения до тех пор, пока они отображаются в модели в виде идентификаторов (я включил FK-Ids при создании модели).
3. Также был бы полезен некоторый подход к включению загруженных связанных объектов.
Ответ №2:
Все проблемы исчезают, как только вы используете EF 5 , где они внедрили метод AsNoTracking(). Строка ниже возвращает несвязанный экземпляр, поэтому весь контекст не будет знать о каких-либо изменениях в этом экземпляре:
context.Clients.AsNoTracking().FirstOrDefault(item => item.Id == id);
Если у клиентов есть ссылка на Address, и вам также нужен его несвязанный экземпляр, просто используйте Include:
context.Clients
.Include("Address").AsNoTracking()
.FirstOrDefault(item => item.Id == id);
Ответ №3:
Если это тест, вы можете делать что угодно, и вам не нужно привязываться к какому-либо архитектурному подходу, такому как repository. Ваш репозиторий, вероятно, получает контекст в виде инъекции, чтобы вы могли иметь к нему доступ. Другой момент заключается в том, что я не верю, что AutoMapper создаст отслеживаемый объект.
Одним из способов создания копии класса является использование сериализации, которая по умолчанию сохраняет только общедоступные поля (сериализация Xml или сериализация DataContract). Сериализуйте объект и десериализуйте его обратно в новый экземпляр. Сериализация сохранит весь объектный граф, а десериализованный объектный граф будет отсоединен. Просто имейте в виду, что этим сериализациям не нравятся циклические ссылки в графе объектов (свойство навигации от A к B и от B к A из циклов). Сериализация также слишком агрессивна, поэтому она может проходить по графу глубже, чем вы хотите — это может быть особенно опасно в отношениях «многие ко многим».
Наилучший подход — использовать либо ICloneable
интерфейс и реализовать Clone
, либо определить методы поддержки, которые будут создавать разные клоны с требуемой глубиной.
Здесь представлен другой подход к клонированию EntityObject
объектов на основе. Это сложный код, особенно часть с Reflection.Emit
. Но это вам не поможет, потому что code-first использует POCOs.