AutoMapper和实体框架包含循环关系,无跟踪

时间:2018-05-14 19:53:19

标签: c# entity-framework automapper

使用实体框架6,我尝试使用Caller从数据库急切加载.AsNoTracking()模型,但是当我尝试映射这些模型时,我遇到了麻烦使用AutoMapper 6到他们的ViewModels。

CallerAddress,这是多对一关系(来电者可以有一个地址,地址可以有多个来电)。

以下是(简化的)模型类(ViewModel几乎相同)

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 - &gt; CallerViewModel.Address ...当使用NoTracking合并选项返回对象时,只能在EntityCollection或EntityReference不包含对象时调用Load。

当我删除.AsNoTracking()时,此工作正常,但出于性能原因,我试图将其保留。

我不需要知道Caller -> Address -> Callers,我只需要Caller -> Address

关于如何实现这一目标的任何建议?

编辑/更新:

感谢FoundNil's answer我能够完成这项工作。

我将Address地图更改为:


    CreateMap<Address, AddressViewModel>()
        .ForMember(vm => vm.Id, map => map.MapFrom(m => m.Id))
        .ForMember(vm => vm.CallerViewModels, map => map.MapFrom(m => m.Callers).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.MapFrom(m => m.CallDetails).Ignore())

我和Address之间的相似之处在于CallerAddress的父对象,而CallDetailCaller的父对象< / p>

这两个父项都是各自Model类中的导航属性:

Caller -> public virtual ICollection<CallDetail> CallDetails { get; set; }
Address -> public virtual ICollection<Caller> Callers { get; set; }

也许这可能会给其他人带来一个有用的旗帜,告诉他们可能会遇到这个问题。

注意:我的CallDetailCaller有多对多的关系,因此它的导航属性也为Callers,我和# 39;我不会在我的CallDetail地图中忽略它。

1 个答案:

答案 0 :(得分:1)

我不完全确定它为什么会发生,但我猜这个问题是当你使用.AsNoTracking()在上下文中Address -> Callers之间发生某些事情时,所以不再有办法映射ICollection<Caller>及其视图模型。

既然你提到你只想要Caller -> Address,你应该试试这张地图:

// Address
CreateMap<Address, AddressViewModel>()
    .ForMember(x => x.Callers, opt => opt.Ignore())
    .ReverseMap();

// Caller
CreateMap<Caller, CallerViewModel>()
    .ForMember(vm => vm.AddressViewModel, map => map.MapFrom(m => m.Address))
    .ReverseMap();