C# 自动映射:分层中间对象问题
我继承了一个项目,它有一个相当新颖的类结构,我需要为第三方Web服务操纵它 基本上,源对象的结构是C# 自动映射:分层中间对象问题,c#,automapper,hierarchy,C#,Automapper,Hierarchy,我继承了一个项目,它有一个相当新颖的类结构,我需要为第三方Web服务操纵它 基本上,源对象的结构是parent->collection->collection member object(也就是说,collection成员有简单的属性加上一个class成员对象,这个示例应该更好地解释它)。Dto更简单,只是parent->collection 问题在于TrackInfoDto对象(它们构成Dto中的集合成员)必须从TrackDefinition.TrackType对象中获取属性。这是属于源父集合
parent->collection->collection member object
(也就是说,collection成员有简单的属性加上一个class成员对象,这个示例应该更好地解释它)。Dto更简单,只是parent->collection
问题在于TrackInfoDto
对象(它们构成Dto中的集合成员)必须从TrackDefinition.TrackType
对象中获取属性。这是属于源父集合的对象
我尝试了很多方法在AutoMapper中映射这种关系,但都是空白
我的主要问题是:
- 如果源对象和目标对象有一个要导航的中间对象,如何将源结构映射到目标结构李>
为了提供帮助,下面是我迄今为止尝试的代码示例
using System;
using System.Collections.Generic;
using AutoMapper;
namespace AutoMapperTest
{
/*
* requires Automapper PM>
* Install-Package AutoMapper -Version 3.0.0
*/
/* source class objects */
public class Track
{
public string Id { get; set; }
public string FileId { get; set; }
public string MediaName { get; set; }
public List<TrackDefinition> TrackDefinitions { get; set; }
public Track()
{
TrackDefinitions = new List<TrackDefinition>();
}
}
public class TrackDefinition
{
public string Id { get; set; }
public string TrackTypeName { get; set; }
public TrackType TrackType { get; set; }
public TrackDefinition()
{
TrackType = new TrackType();
}
}
public class TrackType
{
public int Id { get; set; }
public string FileTag { get; set; }
public string Name { get; set; }
}
/* destination mapped object model */
public class TrackDto
{
public string Id { get; set; }
public string MediaName { get; set; }
public string FileId { get; set; }
public List<TrackInfoDto> TrackInfo { get; set; }
public TrackDto()
{
TrackInfo = new List<TrackInfoDto>();
}
}
public class TrackInfoDto
{
public string FileTag { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
#region setup
// create small test bed of source data
var sourceTracks = new List<Track>();
// add a few tracks (index start 1 loops)
for (int i = 1; i < 4; i++)
{
var newTrack = new Track
{
Id = string.Format("{0}", i),
MediaName = string.Format("media track {0}", i),
FileId = string.Format("file reference {0}", i)
};
for (int j = 1; j < 3; j++)
{
var trackDefinition = new TrackDefinition
{
Id = string.Format("TD Id {0}", i),
TrackTypeName = "a track type",
TrackType =
{
Id = j*i,
FileTag = string.Format("file tag {0}", j*i),
Name = string.Format("name # {0}", j*i)
}
};
newTrack.TrackDefinitions.Add(trackDefinition);
}
sourceTracks.Add(newTrack);
}
#endregion
#region map
// now for the problem - how to map the fact that the hierarchy
// in Track->TrackDefinition->TrackType
// needs to *miss out* the middle object (TrackDefinition) when
// we map down to the Dto's
Mapper.CreateMap<Track, TrackDto>()
.ForMember(x => x.TrackInfo, opt => opt.Ignore());
Mapper.CreateMap<TrackDefinition, TrackInfoDto>()
.ForMember(dest => dest.FileTag, func => func.MapFrom(src => src.TrackType.FileTag));
Mapper.CreateMap<TrackDefinition, TrackInfoDto>()
.ForMember(dest => dest.Name, func => func.MapFrom(src => src.TrackType.Name));
// first thing -make sure no mapping issues
Mapper.AssertConfigurationIsValid();
// i've even tried to see if that would coerce - nope!!
//Mapper.CreateMap<TrackType, TrackInfoDto>();
// map our source objects down to our dtos
var trackDtos = Mapper.Map<ICollection<Track>, ICollection<TrackDto>>(sourceTracks);
// by inspecting the trackDtos members, we SHOULD see the TrackInfoDto as being
// populated, but alas not. This is the missing puzzle piece
#endregion
}
}
}
使用系统;
使用System.Collections.Generic;
使用自动制版机;
命名空间自动映射测试
{
/*
*需要Automapper PM>
*安装软件包AutoMapper-版本3.0.0
*/
/*源类对象*/
公共类轨道
{
公共字符串Id{get;set;}
公共字符串FileId{get;set;}
公共字符串MediaName{get;set;}
公共列表TrackDefinitions{get;set;}
公共轨道()
{
TrackDefinitions=新列表();
}
}
公共类轨道定义
{
公共字符串Id{get;set;}
公共字符串TrackTypeName{get;set;}
公共TrackType TrackType{get;set;}
公共轨道定义()
{
TrackType=新的TrackType();
}
}
公共类轨道类型
{
公共int Id{get;set;}
公共字符串文件标记{get;set;}
公共字符串名称{get;set;}
}
/*目标映射对象模型*/
公共类跟踪
{
公共字符串Id{get;set;}
公共字符串MediaName{get;set;}
公共字符串FileId{get;set;}
公共列表TrackInfo{get;set;}
公共轨道
{
TrackInfo=新列表();
}
}
公共类TrackInfoDto
{
公共字符串文件标记{get;set;}
公共字符串名称{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
#区域设置
//创建源数据的小型测试平台
var sourceTracks=新列表();
//添加一些曲目(索引开始1循环)
对于(int i=1;i<4;i++)
{
var newTrack=新轨道
{
Id=string.Format(“{0}”,i),
MediaName=string.Format(“媒体曲目{0}”,i),
FileId=string.Format(“文件引用{0}”,i)
};
对于(int j=1;j<3;j++)
{
var trackDefinition=新的trackDefinition
{
Id=string.Format(“TD Id{0}”,i),
TrackTypeName=“一种曲目类型”,
轨道类型=
{
Id=j*i,
FileTag=string.Format(“文件标记{0}”,j*i),
Name=string.Format(“Name{0}”,j*i)
}
};
newTrack.TrackDefinitions.Add(trackDefinition);
}
sourceTracks.Add(newTrack);
}
#端区
#区域地图
//现在来看问题-如何映射层次结构
//在轨迹->轨迹定义->轨迹类型中
//需要在以下情况下*遗漏*中间对象(轨迹定义)
//我们向下映射到Dto的
Mapper.CreateMap()
.ForMember(x=>x.TrackInfo,opt=>opt.Ignore());
Mapper.CreateMap()
.ForMember(dest=>dest.FileTag,func=>func.MapFrom(src=>src.TrackType.FileTag));
Mapper.CreateMap()
.ForMember(dest=>dest.Name,func=>func.MapFrom(src=>src.TrackType.Name));
//第一件事-确保没有映射问题
assertConfigurationsValid();
//我甚至试着看看这是否会强迫-不!!
//CreateMap();
//将源对象映射到DTO
var trackDtos=Mapper.Map(sourceTracks);
//通过检查trackDtos成员,我们应该看到TrackInfoDto
//填充,但可惜没有。这是丢失的拼图块
#端区
}
}
}
希望代码不要太难理解,我已经从现实场景中简化了很多,但保留了关键的注意事项。我已经解决了它,我正在寻找错误的方法来映射中间对象,我只需要ResolveUsing()
它。这里有一个变化:
Mapper.CreateMap<Track, TrackDto>()
.ForMember(dest => dest.TrackInfo, func => func
.ResolveUsing(src => src.TrackDefinitions));
Mapper.CreateMap()
.ForMember(dest=>dest.TrackInfo,func=>func
.ResolveUsing(src=>src.TrackDefinitions));
还不够。现在还不清楚你在问什么。这只是一个代码示例和一堆华夫饼干。您在使用BeforeMap
之前看过吗?我现在没有时间看这个,但是您可以使用BeforeMap
,并且在匿名函数声明中,显式地调用您正在努力映射常规levelnis的成员的Mapper.Map
——感谢您立即理解我的问题并提供了一个很好的建议。我来看看。再次感谢你-我已经编辑了我的问题。如果是