EF核心循环关系映射

时间:2019-10-24 16:57:06

标签: entity-framework asp.net-core entity-framework-core automapper

给出以下实体模型:

public class Workshop
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public ICollection<QuoteRequest> QuoteRequests { get; set; }
}

public class QuoteRequest
{
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    public Guid WorkshopId { get; set; }
    public bool Responded { get; set; }
    public decimal? Amount { get; set; }

    public virtual Customer Customer { get; set; }
    public virtual Workshop Workshop { get; set; }
}

和以下2个视图模型:

public class WorkshopModel
{
    public Guid Id { get; set; }
    public string Name { get; set; }

    public ICollection<QuoteRequestModel> QuoteRequests { get; set; }
}

public class QuoteRequestModel
{
    public Guid Id { get; set; }
    public Guid CustomerId { get; set; }
    public Guid WorkshopId { get; set; }
    public bool Responded { get; set; }
    public decimal? Amount { get; set; }

    public CustomerModel Customer { get; set; }
    public WorkshopModel Workshop { get; set; }
}

接下来,给出以下查询:

    public async Task<Workshop> GetWorkshopAsync(Guid id, bool includeQuotes = false)
    {
        IQueryable<Workshop> query = _context.Workshops;

        if (includeQuotes)
        {
            query = query.Include(w => w.QuoteRequests);
        }

        return await query.FirstOrDefaultAsync(w => w.Id == id);
    }

无论我做什么,在查询Workshop时都无法获得EF而不给我循环关系。例如,我查询一个具有14个Workshop的{​​{1}},每个都有一个QuoteRequests,每个都有14个Workshop等,等等:

enter image description here

我确实将json序列化程序引用循环处理设置设置为忽略,但这并没有给我想要的结果

QuoteRequests

因此,我想在我的地图资料中删除该圆圈。我正在使用自动映射器。从services.AddControllers() .AddNewtonsoftJson(x => x.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore); 方面,我设法用映射配置文件打破了循环引用:

QuoteRequest

这可能是一个简单的解决方案,但是当我查询一个单独的CreateMap<QuoteRequestModel, QuoteRequest>() .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer)) .ForMember(dest => dest.Workshop, opt => opt.MapFrom(src => src.Workshop)) .ForPath(dest => dest.Customer.QuoteRequests, opt => opt.MapFrom(src => new List<QuoteRequest>())) .ForPath(dest => dest.Workshop.QuoteRequests, opt => opt.MapFrom(src => new List<QuoteRequest>())); CreateMap<QuoteRequest, QuoteRequestModel>() .ForMember(dest => dest.Customer, opt => opt.MapFrom(src => src.Customer)) .ForMember(dest => dest.Workshop, opt => opt.MapFrom(src => src.Workshop)) .ForPath(dest => dest.Customer.QuoteRequests, opt => opt.MapFrom(src => new List<QuoteRequestModel>())) .ForPath(dest => dest.Workshop.QuoteRequests, opt => opt.MapFrom(src => new List<QuoteRequestModel>())); 时,它现在可以正常工作。我想弄清楚的是如何从QuoteRequest方面在映射配置文件中执行相同的操作:

Workshop

我不能真正地以CreateMap<WorkshopModel, Workshop>() .ForMember(dest => dest.QuoteRequests, opt => opt.MapFrom(src => src.QuoteRequests)); CreateMap<Workshop, WorkshopModel>() .ForMember(dest => dest.QuoteRequests, opt => opt.MapFrom(src => src.QuoteRequests)); 的每次迭代为目标来将QuoteRequests设置为默认值。

1 个答案:

答案 0 :(得分:1)

这不是问题。您所看到的是EF的对象修复。因为它已经在对象缓存中包含了这些实体,所以它会自动“修复”每个实体上的关系,而无需再次查询任何内容。

唯一的问题可能是在序列化期间,因为序列化将尝试无限期地递归向下钻取。但是,根据序列化方法的不同,可以采用多种方法来防止递归序列化。另外,您实际上绝对不应该直接序列化实体。相反,您应该将它们映射到DTO类中,然后在其中定义一个不会遇到相同的递归问题的更基本的结构。然后,您将序列化DTO而不是实体。