Automapper循环引用无限循环

7 浏览
0 Comments

Automapper循环引用无限循环

我在使用AutoMapper时遇到了一些问题,我映射的对象出现了循环引用,因此我无法使用ActionResult将其以JSON格式返回给视图。

我已经创建了一个与其他两个对象相关联的DTO对象。

函数模型:

public partial class function
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public function()
    {
        this.t_actual_organization = new HashSet();
        this.t_actual_organization_split_position = new HashSet();
    }
    public int function_id { get; set; }
    public string function_name { get; set; }
    public bool is_active { get; set; }
    public Nullable job_family_id { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection t_actual_organization { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection t_actual_organization_split_position { get; set; }
    public virtual job_family job_family { get; set; }
}

职位族群模型:

public partial class job_family
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public job_family()
    {
        this.t_actual_organization = new HashSet();
        this.t_actual_organization_split_position = new HashSet();
        this.functions = new HashSet();
    }
    public int job_family_id { get; set; }
    public string job_family_name { get; set; }
    public Nullable 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 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection t_actual_organization_split_position { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection functions { get; set; }
}

AutoMapper配置:

cfg.CreateMap().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));

函数区域模型:

public partial class functional_area
{
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
    public functional_area()
    {
        this.job_family = new HashSet();
        this.t_actual_organization = new HashSet();
        this.t_actual_organization_split_position = new HashSet();
    }
    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 { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection t_actual_organization { get; set; }
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
    public virtual ICollection t_actual_organization_split_position { get; set; }
}

调用部分:

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

我在浏览器中收到的错误信息是:

在序列化类型为'System.Data.Entity.DynamicProxies.job_family_D3FE2013BDB6002B7BE94915E73AEA531401...'的对象时检测到了循环引用。

0
0 Comments

Automapper Circular Reference Infinite Loops是一个常见的问题,产生的原因是在使用Automapper库时,当对象之间存在循环引用时,会导致无限循环。这个问题的解决方法有两种,一种是配置Json格式化程序来处理循环引用,另一种是降级Automapper库的版本。

首先,如果问题是由于Json格式化程序无法处理循环引用导致的,可以通过配置API来处理循环引用。可以通过以下代码在全局范围内解决该问题:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        //忽略循环引用
        json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
        //将循环引用序列化为对象
        json.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
        json.SerializerSettings.PreserveReferencesHandling = PreserveReferencesHandling.Objects;
     }
}

这段代码将忽略循环引用,并将循环引用序列化为对象。

其次,如果使用了较新版本的Automapper库,它本身应该能够静态地解决循环引用问题。但是,如果DTO模型非常复杂且存在多个循环引用,可能会遇到问题。在这种情况下,可以考虑降级Automapper库的版本。回退到较旧的版本(例如4.2.1.0)可能可以解决这个问题。

需要注意的是,虽然Automapper库团队已经提供了解决循环引用的方法,但是在某些情况下可能无法正常工作。因此,降级Automapper库的版本是一种可行的解决方法。

解决Automapper Circular Reference Infinite Loops问题的方法包括配置Json格式化程序来处理循环引用以及降级Automapper库的版本。根据具体情况选择合适的解决方法。

0
0 Comments

Automapper循环引用无限循环是指在使用Automapper进行对象映射时出现的问题。该问题的原因是在对象映射配置中存在引起循环引用的属性。解决方法是通过在映射配置中排除引起循环引用的属性。

例如,在Automapper配置中可以使用Ignore()方法排除引起循环引用的属性。示例代码如下:

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

排除了循环引用属性后,Automapper完成映射后得到的对象将比原始对象“小”,可以顺利地将其序列化为JSON格式。

如果想要将“无限”对象序列化为JSON并不关心通过调整Automapper来解决循环引用问题,可以考虑手动裁剪对象的循环引用部分。示例代码如下:

List mjd = Mapper.Map, List>(data);
var jsonPrepMJD = new List(
    from m in mjd
    select new MasterJobsDTO()
    {
        id = m.id,
        //...
        pointBackMember = new PointBackMember()
        {
            //设置非虚拟属性
        }
    }.Cast()
);

如果pointBackMember是一个列表,则可以从列表中选择并进行类型转换,以达到所需的深度。jsonPrepMJD将可以被序列化。

循环引用问题的根源是Function类中的public virtual job_family job_family属性,其中job_family又链接到Function类,导致循环引用。解决方法是手动裁剪虚拟指针,例如将pointBackMember = new PointBackMember()替换为function_area = new function_area(){}。

问题的关键在于点返回的用途是根据对象自身的角度来组织对象的。在循环点返回中,你得到的“真实映射”树会根据你从哪个角度开始而有所不同。因此,你可能需要自己进行硬定义,没有其他办法。

关于树的深度是否有限制,树的深度是有限制的,因为对象变量存储在有限的数据大小中。

如果functional_area类没有循环引用问题,可以直接设置:functional_area = m.functional_area。如果它像job_family那样存在问题,你可以这样处理:functional_area = new functional_area() { functional_area_id= m.functional_area.id, ...,不设置引起循环引用的属性}。

基本上,对于每个复杂对象,你需要设置所需的属性,并丢弃不需要的属性。如果复杂对象有复杂属性,则需要继续深入设置。你需要手动排除重新启动树的特定部分。

在重新审视MasterJobDTO对象后,如果想要删除与job_family相关的DTO的其他属性(如public string job_family_name {get; set;}),是否可以应用上述解决方法?可以尝试这样做。

最后,请注意function_area类中也存在指向job_family的虚拟指针,这可能意味着模型设计可以进行优化。可以通过两个不同的Json树图来展示这一点,两者都以不同的方式包含相同的数据。例如,你可以从MasterJobDTO->job_family或MasterJobDTO->functional_area->job_family进行深入挖掘,并获得相同的数据。不过,根据你的选择,只能保留一个,这会改变树的形状(数据相同)。

新的MasterJobDTO对象在视觉上简化了我们所看到的内容。它删除了一些[stuff],但同样的问题仍然存在。

在看了function_area类的代码后,我发现它也有一个指向job_family的虚拟指针,这表明模型设计可能可以进行优化。我可以通过两个Json树状图来展示这一点,两者都以不同的方式包含相同的数据。例如,你可以从MasterJobDTO->job_family或MasterJobDTO->functional_area->job_family进行深入挖掘,并获得相同的数据。但只能保留一个,这会改变树的形状(数据相同)。

最后一个Json树的展开如下:{[stuff],job_family:{[stuff],function:{[stuff],NO job_family},NO functional_area}},functional_area:{[stuff],NO job_family}}。

希望以上解释对你有所帮助,让你更好地理解Automapper循环引用无限循环问题的原因和解决方法。

0