C# Automapper将多个嵌套类映射到一个具有各种属性的类
我有以下通过JSON请求填充的模型类:C# Automapper将多个嵌套类映射到一个具有各种属性的类,c#,.net,automapper,C#,.net,Automapper,我有以下通过JSON请求填充的模型类: public class Driver { public string driverId { get; set; } public string url { get; set; } public string givenName { get; set; } public string familyName { get; set; } public string dateOfBirth { get; set; }
public class Driver
{
public string driverId { get; set; }
public string url { get; set; }
public string givenName { get; set; }
public string familyName { get; set; }
public string dateOfBirth { get; set; }
public string nationality { get; set; }
}
public class Constructor
{
public string constructorId { get; set; }
public string url { get; set; }
public string name { get; set; }
public string nationality { get; set; }
}
public class DriverStanding
{
public string position { get; set; }
public string points { get; set; }
public string wins { get; set; }
public Driver Driver { get; set; }
public List<Constructor> Constructors { get; set; }
}
public class StandingsList
{
public string season { get; set; }
public string round { get; set; }
public List<DriverStanding> DriverStandings { get; set; }
}
public class StandingsTable
{
public string season { get; set; }
public List<StandingsList> StandingsLists { get; set; }
}
public class MRData
{
public string xmlns { get; set; }
public string series { get; set; }
public string url { get; set; }
public string limit { get; set; }
public string offset { get; set; }
public string total { get; set; }
public StandingsTable StandingsTable { get; set; }
}
public class RootObject
{
public MRData MRData { get; set; }
}
试试这样的。您必须明确深入到src对象中,才能使其正确映射。Automapper只会自动匹配具有相同名称且深度相同的属性。如果名称不匹配或嵌套在另一个名称中,则必须准确指定所需的属性。对象列表将正确映射,而无需更改Mapper.CreateMap(),但您必须从单个对象映射到单个对象,或从对象列表映射到另一个对象列表 例如:
Mapper.CreateMap<MVCF1.API.RootObject, MVCF1.Models.DriverResults>()
.ForMember(dest => dest.Season, opt.MapFrom(src => src.MRData.StandingsTable.season));
Mapper.CreateMap()
.ForMember(dest=>dest.seasure,opt.MapFrom(src=>src.MRData.StandingsTable.seasure));
按照@David I get建议运行断言时:
AutoMapper.AutoMapperConfigurationException :
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
=================================================================================
DriverStanding -> DriverResults (Destination member list)
StackOverflow.Null.API.DriverStanding -> StackOverflow.Null.Models.DriverResults (Destination member list)
---------------------------------------------------------------------------------
Season
================================================================================
StandingsList -> DriverResults (Destination member list)
StackOverflow.Null.API.StandingsList -> StackOverflow.Null.Models.DriverResults (Destination member list)
--------------------------------------------------------------------------------
Points
Driver
=============================================================================
RootObject -> DriverResults (Destination member list)
StackOverflow.Null.API.RootObject -> StackOverflow.Null.Models.DriverResults (Destination member list)
-----------------------------------------------------------------------------
Season
Points
Driver
现在基本上您有了一个对象(MRData
),它有一个对象列表(StandingsList
),它有一个对象列表(driversstanding
)。我假设,在应用映射时,您希望将这1个复杂的MRData
对象展平为多个DriverResults
对象。这不是可以直接通过配置轻松完成的事情,但是可以通过在各种对象上重新应用映射来完成
我认为您正在寻找类似于此解决方案的解决方案:
更新-更新代码以匹配更新的要求
我已经部分实施了该解决方案
MVCF1Profile.cs
namespace MVCF1
{
using System.Collections.Generic;
using AutoMapper;
public class MVCF1Profile : Profile
{
public override string ProfileName
{
get { return "MVCF1Profile"; }
}
protected override void Configure()
{
AllowNullDestinationValues = true;
AllowNullCollections = true;
CreateMap<API.Driver, Models.Driver>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.givenName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.familyName));
CreateMap<API.StandingsList, Models.DriverResults>()
.ForMember(dest => dest.Driver, opt => opt.MapFrom(src => src.DriverStandings.Select(ds => Mapper.Map<API.Driver, Models.Driver>(ds.Driver))))
.ForMember(dest => dest.Points, opt => opt.Ignore());
}
}
}
只需再次调用映射器,即可根据需要为更高级别的对象应用映射。例如,修复配置后,可以执行以下操作:
Mapper.Map(root.MRData.StandingsTable, result);
这将把相应的字段从StandingsTable映射到结果目标。您是否尝试在单元测试中使用AssertConfigurationsValid?另外,您在何处/正在调用映射()方法?它在MVC的Global.asax中设置,然后映射到一个controllerAll中。属性是不同的名称和类型,这意味着它们都必须明确说明。是的。似乎@Mightymuke对此做了进一步的解释。我试图做的是在原始类继承人权限的不同点上获取不同的属性值来填充我的DriverResults对象这对于AutoMapper配置文件来说是个坏名字(断言消息中显示的我的命名空间也是如此)。看看这篇描述个人资料的文章。也许我会用LINQ,也许更简单一点,你一个赛季只有一组结果。我希望返回一个DriverResults类型的对象,其中包含从JSON填充的驱动程序列表。我用一个JSON returnedOK的例子更新了我的问题,我对它进行了简化,给出了您期望的结果。将
DriverResults.Points的映射留给您,因为它在目标中处于较高级别,因此需要进行一些计算。
AutoMapper.AutoMapperConfigurationException :
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
=================================================================================
DriverStanding -> DriverResults (Destination member list)
StackOverflow.Null.API.DriverStanding -> StackOverflow.Null.Models.DriverResults (Destination member list)
---------------------------------------------------------------------------------
Season
================================================================================
StandingsList -> DriverResults (Destination member list)
StackOverflow.Null.API.StandingsList -> StackOverflow.Null.Models.DriverResults (Destination member list)
--------------------------------------------------------------------------------
Points
Driver
=============================================================================
RootObject -> DriverResults (Destination member list)
StackOverflow.Null.API.RootObject -> StackOverflow.Null.Models.DriverResults (Destination member list)
-----------------------------------------------------------------------------
Season
Points
Driver
namespace MVCF1
{
using System.Collections.Generic;
using AutoMapper;
public class MVCF1Profile : Profile
{
public override string ProfileName
{
get { return "MVCF1Profile"; }
}
protected override void Configure()
{
AllowNullDestinationValues = true;
AllowNullCollections = true;
CreateMap<API.Driver, Models.Driver>()
.ForMember(dest => dest.FirstName, opt => opt.MapFrom(src => src.givenName))
.ForMember(dest => dest.LastName, opt => opt.MapFrom(src => src.familyName));
CreateMap<API.StandingsList, Models.DriverResults>()
.ForMember(dest => dest.Driver, opt => opt.MapFrom(src => src.DriverStandings.Select(ds => Mapper.Map<API.Driver, Models.Driver>(ds.Driver))))
.ForMember(dest => dest.Points, opt => opt.Ignore());
}
}
}
[Test]
public void AutoMapper_Configuration_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MVCF1Profile>());
Mapper.AssertConfigurationIsValid();
}
[Test]
public void AutoMapper_DriverMapping_IsValid()
{
Mapper.Initialize(m => m.AddProfile<MVCF1Profile>());
Mapper.AssertConfigurationIsValid();
// Convert JSON string from question to RootObject instance
var data = GetData();
var ds = data.MRData.StandingsTable.StandingsLists.First();
var driverResults = Mapper.Map<StandingsList, Models.DriverResults>(ds);
Assert.That(driverResults, Is.Not.Null);
Assert.That(driverResults.Points, Is.Null);
Assert.That(driverResults.Season, Is.EqualTo("2012"));
Assert.That(driverResults.Driver, Is.Not.Null);
Assert.That(driverResults.Driver.Count(), Is.EqualTo(25));
}
private RootObject GetData()
{
string jsonMessage;
#region Initialise String
jsonMessage = @"";
#endregion
var data = JsonConvert.DeserializeObject<RootObject>(jsonMessage);
Assert.That(data, Is.Not.Null);
Assert.That(data, Is.InstanceOf<RootObject>());
Assert.That(data.MRData, Is.Not.Null);
Assert.That(data.MRData, Is.InstanceOf<MRData>());
Assert.That(data.MRData.StandingsTable, Is.Not.Null);
Assert.That(data.MRData.StandingsTable, Is.InstanceOf<StandingsTable>());
return data;
}
Mapper.Map(root.MRData.StandingsTable, result);