Используя Entity Framework 6, я пытаюсь загружать свои Caller
модели из базы данных, используя .AsNoTracking()
, но у меня возникает затруднение, когда я пытаюсь сопоставить эти модели их ViewModels с помощью AutoMapper 6.
Caller
имеет Address
, что является отношением многие-к-одному (вызывающий может иметь один адрес, адрес может иметь несколько вызывающих).
Вот (уменьшенные) классы моделей (ViewModels почти идентичны)
public class Caller
{
public Guid Id { get; set; }
public string FirstName { get; set; }
public Address Address { get; set; }
}
public class Address
{
public Guid Id { get; set; }
public string City { get; set; }
public virtual ICollection<Caller> Callers { get; set; }
}
Вот как я их отображаю
// Address
CreateMap<Address, AddressViewModel>()
.ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
.ForMember(vm => vm.CallerViewModels, map => map.MapFrom(m => m.Callers))
.ForMember(vm => vm.City, map => map.MapFrom(m => m.City))
.ReverseMap();
// Caller
CreateMap<Caller, CallerViewModel>()
.ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
.ForMember(vm => vm.AddressViewModel, map => map.MapFrom(m => m.Address))
.ForMember(vm => vm.FirstName, map => map.MapFrom(m => m.FirstName))
.ReverseMap();
В моем CallerRepository
я использую эту функцию:
public async Task<Caller> GetFullCallerAsNoTrackingAsync(Guid id)
{
return await _context.Callers
.AsNoTracking()
.Include(c => c.Address)
.FirstOrDefaultAsync(c => c.Id == id);
}
Моя проблема происходит здесь:
// Map Caller to a CallerViewModel
Caller caller = await unitOfWork.CallerRepo.GetFullCallerAsNoTrackingAsync(Guid.Parse(callerId));
CallerViewModel callerViewModel = Mapper.Map<CallerViewModel>(caller); // Throws exception
Исключение, которое выдается, говорит
Типы отображения ошибок ... Caller.Address -> CallerViewModel.Address ... Когда объект возвращается с параметром слияния NoTracking, метод Load может быть вызван, только если EntityCollection или EntityReference не содержат объектов.
Это прекрасно работает, когда я удаляю .AsNoTracking()
, но из соображений производительности я пытаюсь сохранить это.
Мне не нужно знать Caller -> Address -> Callers
, мне просто нужно Caller -> Address
Любые предложения о том, как мне этого добиться?
<Ч />
Редактировать / Обновить:
Благодаря FoundNil ответ Мне удалось это сделать.
Я изменил свою карту Address
на:
CreateMap<Address, AddressViewModel>()
.ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
.ForMember(vm => vm.CallerViewModels, map => map<strike>.MapFrom(m => m.Callers)</strike>.Ignore())
.ForMember(vm => vm.City, map => map.MapFrom(m => m.City))
.ReverseMap();
И я сделал то же самое с другим свойством, CallDetailViewModels
, на моей Caller -> CallerViewModel
карте
CreateMap<Caller, CallerViewModel>()
.ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
.ForMember(vm => vm.AddressViewModel, map => map.MapFrom(m => m.Address))
.ForMember(vm => vm.CallDetailViewModels, map => map<strike>.MapFrom(m => m.CallDetails)</strike>.Ignore())
Сходство, которое я вижу между этим и Address
, заключается в том, что Caller
является родительским объектом Address
, а CallDetail
является родительским объектом Caller
Оба этих родителя были навигационными свойствами в соответствующем классе модели:
Caller -> public virtual ICollection<CallDetail> CallDetails { get; set; }
Address -> public virtual ICollection<Caller> Callers { get; set; }
Возможно, это может дать полезный флаг другим людям, где они могут столкнуться с этой проблемой.
Примечание: My CallDetail
имеет отношение многие ко многим с Caller
, поэтому оно также имеет свойство навигации Callers
, и я не игнорирую это в моем CallDetail
Карта.