Automapper循环引用无限循环
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; } }
调用部分:
Listmjd = Mapper.Map , List
>(data);
我在浏览器中收到的错误信息是:
在序列化类型为'System.Data.Entity.DynamicProxies.job_family_D3FE2013BDB6002B7BE94915E73AEA531401...'的对象时检测到了循环引用。
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库的版本。根据具体情况选择合适的解决方法。
Automapper循环引用无限循环是指在使用Automapper进行对象映射时出现的问题。该问题的原因是在对象映射配置中存在引起循环引用的属性。解决方法是通过在映射配置中排除引起循环引用的属性。
例如,在Automapper配置中可以使用Ignore()方法排除引起循环引用的属性。示例代码如下:
.ForMember(dest => dest.OffendingVariable, source => source.Ignore());
排除了循环引用属性后,Automapper完成映射后得到的对象将比原始对象“小”,可以顺利地将其序列化为JSON格式。
如果想要将“无限”对象序列化为JSON并不关心通过调整Automapper来解决循环引用问题,可以考虑手动裁剪对象的循环引用部分。示例代码如下:
Listmjd = 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循环引用无限循环问题的原因和解决方法。