Automapper - Map Using the Same Source and Destination Object Types

Automapper Mapping Objects of Same Type - Overwrite Bools

If you're implementing some logic on mapping, better do it on each member explicitly.

But if you really want to do it via AutoMapper magic, you can add this condition:

options.Condition((source, destination, member) => (member as bool?) != false);

Automapper - Multi object source and one destination

Map has an overload that takes a source and destination object:

d = AutoMapper.Mapper.Map<sourceone, destination>(sourceone);

/* Pass the created destination to the second map call: */
AutoMapper.Mapper.Map<sourcetwo, destination>(sourcetwo, d);

Automapper one source to multiple destination

AutoMapper can map from as many sources to as many destinations as you would like, assuming you configure the mapping. For example, your requested scenario:

var configuration = new MapperConfiguration(cfg =>
// Mapping Config
cfg.CreateMap<Source1, Dest2>()
.ForMember(dest => dest.prop5, opt => opt.Ignore())
.ForMember(dest => dest.prop6, opt => opt.Ignore());
cfg.CreateMap<Source1, Dest1>()
.ForMember(dest => dest.Dest2, opt => opt.MapFrom(src => src));

// Reverse Mapping Config
cfg.CreateMap<Dest1, Source1>()
.ForMember(dest => dest.prop4,
opt => opt.MapFrom(src => (src?.Dest2 != null) // ?. w/c#6
? src.Dest2.prop4 // map if can
: null)); // otherwise null
);
// Check AutoMapper configuration
configuration.AssertConfigurationIsValid();

Properties with the same name will map automatically. Any destination properties that don’t have a corresponding source property will need to be ignored.

Once your AutoMapper is configured, you can map as needed with the use of the IMapper interface.

public class Foo {
private IMapper _mapper;
public Foo(IMapper mapper) {
_mapper = mapper;
}

// Map Source1 -> Dest1
public Dest1 Bar(Source1 source) {
return _mapper.Map<Dest1>(source);
}

// Map Dest1 -> Source1
public Source1 Baz(Dest1 dest) {
return _mapper.Map<Source1>(dest);
}
}

Do we need to use asp.net Auto Mapper if the source and destination types are the same

You are using source = destination;, that will copy reference of the memory location for destination object only. In the example you have provided, it does not really matter since you are adding object to entities.

If you want a complete clone of object at separate memory location to do other processing with the object, use ICloneable and MemberwiseClone, in case, you do not want to use AutoMapper for stuff where mapping is exactly the same.

public class Staff : ICloneable
{
public string FirstName{get;set;}
public string LastName{get;set;}
public int Age{get;set;}
public string Address{get;set;}

public object Clone()
{
return this.MemberwiseClone();
}
}

Then, you can use source = (Staff)destination.Clone();

This will allow shallow copy only. If you want deep copy, you can serialize and deserialize.

How to map some source properties to a wrapped destination type using AutoMapper?

According to this issue on AutoMapper GitHub page, there is no direct way to do it.

But there is some workarounds. For example - reflection.

In this case you need to know wrapper type and implement converter for desired types. In this example it's MapAndWrapConverter from TSource to Wrap<TDestination>

CreateWrapMap method creates two bindings:

SourceAddress -> Wrap<DestinationAddress> and SourceContact -> Wrap<DestinationContact> which allow you to map SourceContant to wrapped DestinationContact.

internal class Program
{
public static void Main()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<SourceAddress, DestinationAddress>();
cfg.CreateMap<SourceContact, DestinationContact>();

cfg.CreateWrapMap(
//func selecting types to wrap
type => typeof(DestinationModelBase).IsAssignableFrom(type)
&& !type.IsAbstract,
typeof(Wrap<>),
typeof(MapAndWrapConverter<,>));
});

var mapper = config.CreateMapper();

//Using AutoFixture to create complex object
var fixture = new Fixture();
var srcObj = fixture.Create<SourceContact>();

var dstObj = mapper.Map<Wrap<DestinationContact>>(srcObj);
}
}

public static class AutoMapperEx
{
public static IMapperConfigurationExpression CreateWrapMap(
this IMapperConfigurationExpression cfg,
Func<Type, bool> needWrap, Type wrapperGenericType,
Type converterGenericType)
{
var mapperConfiguration =
new MapperConfiguration((MapperConfigurationExpression)cfg);
var types = Assembly.GetExecutingAssembly().GetTypes();

foreach (var dstType in types.Where(needWrap))
{
var srcType = mapperConfiguration.GetAllTypeMaps()
.Single(map => map.DestinationType == dstType).SourceType;
var wrapperDstType = wrapperGenericType.MakeGenericType(dstType);
var converterType = converterGenericType.MakeGenericType(srcType, dstType);
cfg.CreateMap(srcType, wrapperDstType)
.ConvertUsing(converterType);
}
return cfg;
}
}
public class MapAndWrapConverter<TSource, TDestination>
: ITypeConverter<TSource, Wrap<TDestination>>
{
public Wrap<TDestination> Convert(
TSource source, Wrap<TDestination> destination, ResolutionContext context)
{
return new Wrap<TDestination>
{
Payload = context.Mapper.Map<TDestination>(source)
};
}
}

CreateWrapMap method is a little bit messy, especially the part with finding matching types. But it can be refined according to your needs.



Related Topics



Leave a reply



Submit