有条件地将一种源类型映射到两种目标类型
Conditionally mapping one source type to two destination types
我有一个这样的源 DTO
public class Member
{
public string MemberId {get;set;}
public string MemberType {get;set;}
public string Name {get;set;}
}
成员类型可以是"Person"或"Company"。
还有两个目的地class是这样的
public class PersonMember
{
public int PersonMemberId {get;set;}
public string Name {get;set;}
}
public class CompanyMember
{
public int CompanyMemberId {get;set;}
public string Name {get;set;}
}
我想使用 Automapper 检查源中 MemberType 的值 class 并根据该类型映射到两个目标类型之一。
我看到了 conditionally mapping 的示例,但它映射了执行条件检查的字段。我想检查条件并映射不同的字段。
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo,Bar>()
.ForMember(dest => dest.baz, opt => opt.Condition(src => (src.baz >= 0)));
});
我的目标是这样的 -
cfg.CreateMap<Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId, opt => if the source.MemberType == "Person" perform mapping from MemberId, otherwise do nothing);
cfg.CreateMap<Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId, opt => if the source.MemberType == "Company" perform mapping from MemberId, otherwise do nothing);
使用自动映射器,您必须在调用映射器上指定 return 类型,例如。 mapper.Map<PersonMember>(member)
,这表明 return 类型是 PersonMember
所以你不能 return CompanyMember
.
你可以这样做:
var configPerson = new MapperConfiguration(cfg => cfg.CreateMap<Member, PersonMember>());
var configCompany = new MapperConfiguration(cfg => cfg.CreateMap<Member, CompanyMember>());
PersonMember personMember = null;
CompanyMember companyMember = null;
switch (member.MemberType )
{
case "PersonMember":
var mapper = configPerson.CreateMapper();
personMember = mapper.Map<PersonMember>(member);
break;
case "CompanyMember":
var mapper = configCompany.CreateMapper();
companyMember = mapper.Map<CompanyMember>(member);
break;
default:
throw new Exception("Unknown type");
break;
}
或者您可以尝试 Custom type converters 和 object
作为 return 类型。
I saw the example of conditionally mapping, but it maps the field it performs the conditional check on. I want to check the condition and map a different field.
尝试使用这样的配置:
cfg.CreateMap<Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId, opt => {
opt.Condition(src => src.MemberType == "Person");
opt.MapFrom(src => src.MemberId);
});
cfg.CreateMap<Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId, opt => {
opt.Condition(src => src.MemberType == "Company");
opt.MapFrom(src => src.MemberId);
});
如果您从不兼容的对象进行映射,Id
字段将设置为 0
。
对于版本 5 及更高版本,您可以尝试以下代码:
using System;
using AutoMapper;
namespace AutoMapOneToMulti
{
class Program
{
static void Main(string[] args)
{
RegisterMaps();
var s = new Source { X = 1, Y = 2 };
Console.WriteLine(s);
Console.WriteLine(Mapper.Map<Source, Destination1>(s));
Console.WriteLine(Mapper.Map<Source, Destination2>(s));
Console.ReadLine();
}
static void RegisterMaps()
{
Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
}
}
public class GeneralProfile : Profile
{
public GeneralProfile()
{
CreateMap<Source, Destination1>();
CreateMap<Source, Destination2>();
}
}
public class Source
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Source = X : {0}, Y : {1}", X, Y);
}
}
public class Destination1
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
}
}
public class Destination2
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
}
}
}
对于低于 5 的版本,您可以试试这个:
using System;
using AutoMapper;
namespace AutoMapOneToMulti
{
class Program
{
static void Main(string[] args)
{
RegisterMaps();
var s = new Source { X = 1, Y = 2 };
Console.WriteLine(s);
Console.WriteLine(Mapper.Map<Source, Destination1>(s));
Console.WriteLine(Mapper.Map<Source, Destination2>(s));
Console.ReadLine();
}
static void RegisterMaps()
{
Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
}
}
public class GeneralProfile : Profile
{
protected override void Configure()
{
CreateMap<Source, Destination1>();
CreateMap<Source, Destination2>();
}
}
public class Source
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Source = X : {0}, Y : {1}", X, Y);
}
}
public class Destination1
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
}
}
public class Destination2
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
}
}
}
如果你想要一个动态函数,使用这个扩展:
public static dynamic DaynamicMap(this Source source)
{
if (source.X == 1)
return Mapper.Map<Destination1>(source);
return Mapper.Map<Destination2>(source);
}
Console.WriteLine(new Source { X = 1, Y = 2 }.DaynamicMap());
Console.WriteLine(new Source { X = 2, Y = 2 }.DaynamicMap());
介绍一些基础classMember
。从新基数 class.
继承 PersonMember
, CompanyMember
然后定义这些映射:
cfg.CreateMap<Dto.Member, Member>()
.ConstructUsing((memberDto, context) => {
switch (memberDto.MemberType)
{
case "PersonMember":
return context.Mapper.Map<PersonMember>(memberDto);
case "CompanyMember":
return context.Mapper.Map<CompanyMember>(memberDto);
default:
throw new ArgumentOutOfRangeException($"Unknown MemberType {memberDto.MemberType}");
}
});
cfg.CreateMap<Dto.Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId,
opt => opt.MapFrom(src => src.MemberId));
cfg.CreateMap<Dto.Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId,
opt => opt.MapFrom(src => src.MemberId));
现在您可以使用 _mapperInstance.Map<Member>(memberDto);
进行映射
我有一个这样的源 DTO
public class Member
{
public string MemberId {get;set;}
public string MemberType {get;set;}
public string Name {get;set;}
}
成员类型可以是"Person"或"Company"。
还有两个目的地class是这样的
public class PersonMember
{
public int PersonMemberId {get;set;}
public string Name {get;set;}
}
public class CompanyMember
{
public int CompanyMemberId {get;set;}
public string Name {get;set;}
}
我想使用 Automapper 检查源中 MemberType 的值 class 并根据该类型映射到两个目标类型之一。
我看到了 conditionally mapping 的示例,但它映射了执行条件检查的字段。我想检查条件并映射不同的字段。
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<Foo,Bar>()
.ForMember(dest => dest.baz, opt => opt.Condition(src => (src.baz >= 0)));
});
我的目标是这样的 -
cfg.CreateMap<Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId, opt => if the source.MemberType == "Person" perform mapping from MemberId, otherwise do nothing);
cfg.CreateMap<Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId, opt => if the source.MemberType == "Company" perform mapping from MemberId, otherwise do nothing);
使用自动映射器,您必须在调用映射器上指定 return 类型,例如。 mapper.Map<PersonMember>(member)
,这表明 return 类型是 PersonMember
所以你不能 return CompanyMember
.
你可以这样做:
var configPerson = new MapperConfiguration(cfg => cfg.CreateMap<Member, PersonMember>());
var configCompany = new MapperConfiguration(cfg => cfg.CreateMap<Member, CompanyMember>());
PersonMember personMember = null;
CompanyMember companyMember = null;
switch (member.MemberType )
{
case "PersonMember":
var mapper = configPerson.CreateMapper();
personMember = mapper.Map<PersonMember>(member);
break;
case "CompanyMember":
var mapper = configCompany.CreateMapper();
companyMember = mapper.Map<CompanyMember>(member);
break;
default:
throw new Exception("Unknown type");
break;
}
或者您可以尝试 Custom type converters 和 object
作为 return 类型。
I saw the example of conditionally mapping, but it maps the field it performs the conditional check on. I want to check the condition and map a different field.
尝试使用这样的配置:
cfg.CreateMap<Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId, opt => {
opt.Condition(src => src.MemberType == "Person");
opt.MapFrom(src => src.MemberId);
});
cfg.CreateMap<Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId, opt => {
opt.Condition(src => src.MemberType == "Company");
opt.MapFrom(src => src.MemberId);
});
如果您从不兼容的对象进行映射,Id
字段将设置为 0
。
对于版本 5 及更高版本,您可以尝试以下代码:
using System;
using AutoMapper;
namespace AutoMapOneToMulti
{
class Program
{
static void Main(string[] args)
{
RegisterMaps();
var s = new Source { X = 1, Y = 2 };
Console.WriteLine(s);
Console.WriteLine(Mapper.Map<Source, Destination1>(s));
Console.WriteLine(Mapper.Map<Source, Destination2>(s));
Console.ReadLine();
}
static void RegisterMaps()
{
Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
}
}
public class GeneralProfile : Profile
{
public GeneralProfile()
{
CreateMap<Source, Destination1>();
CreateMap<Source, Destination2>();
}
}
public class Source
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Source = X : {0}, Y : {1}", X, Y);
}
}
public class Destination1
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
}
}
public class Destination2
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
}
}
}
对于低于 5 的版本,您可以试试这个:
using System;
using AutoMapper;
namespace AutoMapOneToMulti
{
class Program
{
static void Main(string[] args)
{
RegisterMaps();
var s = new Source { X = 1, Y = 2 };
Console.WriteLine(s);
Console.WriteLine(Mapper.Map<Source, Destination1>(s));
Console.WriteLine(Mapper.Map<Source, Destination2>(s));
Console.ReadLine();
}
static void RegisterMaps()
{
Mapper.Initialize(cfg => cfg.AddProfile<GeneralProfile>());
}
}
public class GeneralProfile : Profile
{
protected override void Configure()
{
CreateMap<Source, Destination1>();
CreateMap<Source, Destination2>();
}
}
public class Source
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Source = X : {0}, Y : {1}", X, Y);
}
}
public class Destination1
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination1 = X : {0}, Y : {1}", X, Y);
}
}
public class Destination2
{
public int X { get; set; }
public int Y { get; set; }
public override string ToString()
{
return string.Format("Destination2 = X : {0}, Y : {1}", X, Y);
}
}
}
如果你想要一个动态函数,使用这个扩展:
public static dynamic DaynamicMap(this Source source)
{
if (source.X == 1)
return Mapper.Map<Destination1>(source);
return Mapper.Map<Destination2>(source);
}
Console.WriteLine(new Source { X = 1, Y = 2 }.DaynamicMap());
Console.WriteLine(new Source { X = 2, Y = 2 }.DaynamicMap());
介绍一些基础classMember
。从新基数 class.
PersonMember
, CompanyMember
然后定义这些映射:
cfg.CreateMap<Dto.Member, Member>()
.ConstructUsing((memberDto, context) => {
switch (memberDto.MemberType)
{
case "PersonMember":
return context.Mapper.Map<PersonMember>(memberDto);
case "CompanyMember":
return context.Mapper.Map<CompanyMember>(memberDto);
default:
throw new ArgumentOutOfRangeException($"Unknown MemberType {memberDto.MemberType}");
}
});
cfg.CreateMap<Dto.Member, PersonMember>()
.ForMember(dest => PersonMember.PersonMemberId,
opt => opt.MapFrom(src => src.MemberId));
cfg.CreateMap<Dto.Member, CompanyMember>()
.ForMember(dest => CompanyMember.CompanyMemberId,
opt => opt.MapFrom(src => src.MemberId));
现在您可以使用 _mapperInstance.Map<Member>(memberDto);