Automapper Circular Reference 无限循环

Automapper Circular Reference Infinite loops

我在使用 AutoMapper 时遇到一些问题,我映射的对象会产生循环引用,因此我无法return它JSON 使用 ActionResult 查看。

我已经将一个 DTO 的对象与另外两个链接起来。

 public class MasterJobsDTO
{
    public int function_id { get; set; }
    public string function_name { get; set; }
    public bool is_active { get; set; }
    public job_family job_family
    {
        get; set;

    }
    public functional_area functional_area
    {
        get; set;

    }
}

功能模式:

 public partial class function
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public function()
    {
        this.t_actual_organization = new HashSet<t_actual_organization>();
        this.t_actual_organization_split_position = new HashSet<t_actual_organization_split_position>();
    }

    public int function_id { get; set; }
    public string function_name { get; set; }
    public bool is_active { get; set; }
    public Nullable<int> job_family_id { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization> t_actual_organization { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization_split_position> t_actual_organization_split_position { get; set; }
    public virtual job_family job_family { get; set; }
}

Job_Family 型号:

public partial class job_family
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public job_family()
    {
        this.t_actual_organization = new HashSet<t_actual_organization>();
        this.t_actual_organization_split_position = new HashSet<t_actual_organization_split_position>();
        this.functions = new HashSet<function>();
    }

    public int job_family_id { get; set; }
    public string job_family_name { get; set; }
    public Nullable<int> functional_area_id { get; set; }

    public virtual functional_area functional_area { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization> t_actual_organization { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization_split_position> t_actual_organization_split_position { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<function> functions { get; set; }
}

Automapper 配置:

cfg.CreateMap<function, MasterJobsDTO>().MaxDepth(1).PreserveReferences()
        .ForMember(x => x.functional_area_id, opts => opts.MapFrom(source => source.job_family.functional_area.functional_area_id))
        .ForMember(x => x.functional_area_extended_name, opts => opts.MapFrom(source => source.job_family.functional_area.functional_area_extended_name))
        .ForMember(x => x.job_family_name, opts => opts.MapFrom(source => source.job_family.job_family_name))
        .ForMember(x => x.functional_area, opts => opts.MapFrom(source => source.job_family.functional_area))
        ;

function_area class:

 public partial class functional_area
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public functional_area()
    {
        this.job_family = new HashSet<job_family>();
        this.t_actual_organization = new HashSet<t_actual_organization>();
        this.t_actual_organization_split_position = new HashSet<t_actual_organization_split_position>();
    }

    public int functional_area_id { get; set; }
    public string functional_area_name { get; set; }
    public string functional_area_extended_name { get; set; }

    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<job_family> job_family { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization> t_actual_organization { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection<t_actual_organization_split_position> t_actual_organization_split_position { get; set; }
}

然后调用:

List<MasterJobsDTO> mjd = Mapper.Map<List<function>, List<MasterJobsDTO>>(data);

我在浏览器中得到的错误是:

A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.job_family_D3FE2013BDB6002B7BE94915E73AEA531401...

谢谢!

在您的自动映射器配置中,您可以排除有问题的循环引用点。

.ForMember(dest => dest.OffendingVariable, source=> source.Ignore());

自动映射器完成后得到的结果对象将比 "entity" 对象 "smaller" 并且可以毫无问题地序列化为 JSON。

编辑:如果您真正的错误在于您最终希望能够将您的 "infinite" 对象序列化为 JSON,并且您不关心通过摆弄 automapper i 来修复它可以建议 "cropping" 沿着你的对象的圆点背面,像这样:

List<MasterJobsDTO> mjd = Mapper.Map<List<function>, List<MasterJobsDTO>>(data);

var jsonPrepMJD = new List<MasterJobsDTO>(from m in mjd
                            select new MasterJobsDTO()
                            {
                              id = m.id,
                              ...,
                              pointBackMember = new PointBackMember(){set all but the virtual pointback}
                            }.Cast<MasterJobsDTO>();

如果 pointBackMember 是一个列表,那么 select 从它开始并将它投射到你需要的深度

jsonPrepMJD 将是可序列化的。

等等,是自动映射器的问题还是 json 格式化程序无法处理循环引用 (CR)?

如果是 json,您可以配置 api 来处理 CR。 Here is a link to an overly academic example of how to have it ignore the CR. Here 是设置的选项。我能够在 WebApiConfig.cs

中全局解决该问题

就我个人而言,我宁愿 json 能够正确表示数据,也不愿改变我的编码实践,因为我只能深入 X 级。

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        //this will ignore
        json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        //this will serialize them to objects.
        json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
        json.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
     }
}

我 运行 遇到了新版本自动映射器的类似问题。 Automapper 应该能够 statically figure out the CRs in 6.1+ 但我有一个非常复杂的 dto 模型,其中包含许多 CR。我正在等待 automapper 团队解决我的问题。在此期间,我恢复到 4.2.1.0,一切正常。在我解决了 automapper 异常之后,我从 json 格式化程序中得到了一个异常,上面的忽略配置解决了我的问题。

Here 是让我在 json 问题上走上正轨的原因。