C# Automapper -> 条件映射
C# Automapper -> Conditional Mapping
我正在尝试做一些条件映射,我通读的所有文档和问题似乎都没有涵盖这个特定的条件。我希望这里有人有经验或知道如何最好地解决这个问题。
我正在映射一个具有两个属性的对象。但是,如果特定 属性 具有值,我不想映射 EITHER 属性。想象一下:
foreach(var object in objectB) {
If (object.propertyA == "SomeValue")
continue;
else
Mapper.Map<ObjectA>(object);
}
但是,我想要上面语句的 AutoMapper
等价物。所以更像是:
cfg.CreateMap<ObjectB, ObjectA>()
.ForMember(dest => dest.PropertyA, m => m.Condition(source => source.PropertyA != "SomeValue"))
.ForMember(dest => dest.PropertyB, m => m.Condition(source => source.PropertyA != "SomeVAlue" ? source.PropertyB : ignore))
但是上面的版本显然不行。
预先感谢您的帮助。
可以使用条件映射来实现,请参阅文档 (http://docs.automapper.org/en/latest/Conditional-mapping.html) for details. To cover arrays filtering case I created a custom type converter which is a little bit tricky (see http://docs.automapper.org/en/stable/Custom-type-converters.html)。更新后的示例如下
using AutoMapper;
using System;
using System.Collections.Generic;
namespace ConsoleAppTest2
{
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(cfg => {
//Using specific type converter for specific arrays
cfg.CreateMap<Foo[], FooDto[]>().ConvertUsing(new ArrayFilterTypeConverter<Foo[], FooDto[], Foo, FooDto>(
(src, dest) => (src.Age > 0)
));
cfg.CreateMap<Foo, FooDto>()
.ForMember(dest => dest.Age, opt => opt.Condition(src => (src.Age >= 0)))
.ForMember(dest => dest.CurrentAddress, opt =>
{
opt.Condition(src => (src.Age >= 0));
opt.MapFrom(src => src.Address);
});
});
var foo = new Foo() { Name = "Name", Address = "Address", Age = -1 };
var fooDTO = new FooDto();
var fooArray = new Foo[] {
new Foo() { Name = "Name1", Address = "Address1", Age = -1 },
new Foo() { Name = "Name2", Address = "Address2", Age = 1 },
new Foo() { Name = "Name3", Address = "Address3", Age = 1 }
};
var fooDTOArray = Mapper.Map<Foo[], FooDto[]>(fooArray); //get 2 elements instead of 3
Mapper.Map(foo, fooDTO);
//The result is we skipped Address and Age properties becase Age is negative
Console.ReadLine();
}
}
public class ArrayFilterTypeConverter<TSourceArray, TDestArray, TSource, TDest> : ITypeConverter<TSourceArray, TDestArray>
{
private Func<TSource, TDest, bool> filter;
public ArrayFilterTypeConverter(Func<TSource, TDest, bool> filter)
{
this.filter = filter;
}
public TDestArray Convert(TSourceArray source, TDestArray destination, ResolutionContext context)
{
var sourceArray = source as TSource[];
List<TDest> destList = new List<TDest>();
var typeMap = context.ConfigurationProvider.ResolveTypeMap(typeof(TSource), typeof(TDest));
foreach (var src in sourceArray)
{
var dest = context.Mapper.Map<TSource, TDest>(src);
if (filter(src, dest))
destList.Add(dest);
}
// Little hack to cast array to TDestArray
var result = (TDestArray)(object)destList.ToArray();
return result;
}
}
internal class FooDto
{
public string Name { get; set; }
public string CurrentAddress { get; set; }
public int Age { get; set; }
}
internal class Foo
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
}
我正在尝试做一些条件映射,我通读的所有文档和问题似乎都没有涵盖这个特定的条件。我希望这里有人有经验或知道如何最好地解决这个问题。
我正在映射一个具有两个属性的对象。但是,如果特定 属性 具有值,我不想映射 EITHER 属性。想象一下:
foreach(var object in objectB) {
If (object.propertyA == "SomeValue")
continue;
else
Mapper.Map<ObjectA>(object);
}
但是,我想要上面语句的 AutoMapper
等价物。所以更像是:
cfg.CreateMap<ObjectB, ObjectA>()
.ForMember(dest => dest.PropertyA, m => m.Condition(source => source.PropertyA != "SomeValue"))
.ForMember(dest => dest.PropertyB, m => m.Condition(source => source.PropertyA != "SomeVAlue" ? source.PropertyB : ignore))
但是上面的版本显然不行。 预先感谢您的帮助。
可以使用条件映射来实现,请参阅文档 (http://docs.automapper.org/en/latest/Conditional-mapping.html) for details. To cover arrays filtering case I created a custom type converter which is a little bit tricky (see http://docs.automapper.org/en/stable/Custom-type-converters.html)。更新后的示例如下
using AutoMapper;
using System;
using System.Collections.Generic;
namespace ConsoleAppTest2
{
class Program
{
static void Main(string[] args)
{
Mapper.Initialize(cfg => {
//Using specific type converter for specific arrays
cfg.CreateMap<Foo[], FooDto[]>().ConvertUsing(new ArrayFilterTypeConverter<Foo[], FooDto[], Foo, FooDto>(
(src, dest) => (src.Age > 0)
));
cfg.CreateMap<Foo, FooDto>()
.ForMember(dest => dest.Age, opt => opt.Condition(src => (src.Age >= 0)))
.ForMember(dest => dest.CurrentAddress, opt =>
{
opt.Condition(src => (src.Age >= 0));
opt.MapFrom(src => src.Address);
});
});
var foo = new Foo() { Name = "Name", Address = "Address", Age = -1 };
var fooDTO = new FooDto();
var fooArray = new Foo[] {
new Foo() { Name = "Name1", Address = "Address1", Age = -1 },
new Foo() { Name = "Name2", Address = "Address2", Age = 1 },
new Foo() { Name = "Name3", Address = "Address3", Age = 1 }
};
var fooDTOArray = Mapper.Map<Foo[], FooDto[]>(fooArray); //get 2 elements instead of 3
Mapper.Map(foo, fooDTO);
//The result is we skipped Address and Age properties becase Age is negative
Console.ReadLine();
}
}
public class ArrayFilterTypeConverter<TSourceArray, TDestArray, TSource, TDest> : ITypeConverter<TSourceArray, TDestArray>
{
private Func<TSource, TDest, bool> filter;
public ArrayFilterTypeConverter(Func<TSource, TDest, bool> filter)
{
this.filter = filter;
}
public TDestArray Convert(TSourceArray source, TDestArray destination, ResolutionContext context)
{
var sourceArray = source as TSource[];
List<TDest> destList = new List<TDest>();
var typeMap = context.ConfigurationProvider.ResolveTypeMap(typeof(TSource), typeof(TDest));
foreach (var src in sourceArray)
{
var dest = context.Mapper.Map<TSource, TDest>(src);
if (filter(src, dest))
destList.Add(dest);
}
// Little hack to cast array to TDestArray
var result = (TDestArray)(object)destList.ToArray();
return result;
}
}
internal class FooDto
{
public string Name { get; set; }
public string CurrentAddress { get; set; }
public int Age { get; set; }
}
internal class Foo
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
}
}