There are several ways of configuring a custom data source for a target member.
A source member:
Mapper.WhenMapping
.From<ProductDto>() // Apply to ProductDto mappings
.To<Product>() // Apply to Product creation, updates and merges
.Map(ctx => ctx.Source.Spec) // ctx.Source is the ProductDto
.To(p => p.Specification); // p is the Product
// Or, more tersely:
Mapper.WhenMapping
.From<ProductDto>().To<Product>()
.Map(dto => dto.Spec, p => p.Specification);
A source expression (in this example, supplied inline):
// Source, target and mapping types are implicit from the mapping:
Mapper.Map(productDto).ToANew<Product>(cfg => cfg
.Map(ctx => "$" + ctx.Source.Price) // ctx.Source is the ProductDto
.To(p => p.Price)); // p is the Product
A constant value:
Mapper.WhenMapping
.From<ProductDto>() // Apply to ProductDto mappings
.OnTo<Product>() // Apply to Product merges only
.Map("Company ABC") // Always the same value
.To(p => p.CompanyName); // p is the Product
// Or, more tersely:
Mapper.WhenMapping
.From<ProductDto>().OnTo<Product>()
.Map("Company ABC", p => p.CompanyName);
A value from an injected service:
// Retrieve an IDateTimeProvider instance from a configured
// service provider, and use its UtcNow value:
Mapper.WhenMapping
.From<OrderDto>() // Apply to OrderDto mappings
.ToANew<Order>() // Apply to Order creation
.Map(ctx => ctx.GetService<IDateTimeProvider>().UtcNow)
.To(o => o.DateCreated); // o is the Order
The result of a function call (inline):
Func<ProductDto, Product, string> companyNameFactory =
(dto, p) => dto.ManufaturerName + " Ltd";
// Source, target and mapping types are implicit from the mapping:
Mapper.Map(productDto).ToANew<Product>(cfg => cfg
.Map(companyNameFactory) // Map the factory function result
.To(p => p.CompanyName)); // p is the Product
A sequence of data sources
// Map the Customer Home Address, Work Address
// then Address History to the CustomerViewModel
// AllAddresses property:
Mapper.WhenMapping
.From<Customer>() // Apply to Customer mappings
.ToANew<CustomerViewModel>() // Apply to CustomerViewModel creation
.Map((c, vm) => new[] { c.HomeAddress })
.Then.Map((c, vm) => new[] { c.WorkAddress })
.Then.Map((c, vm) => c.AddressHistory)
.To(vm => vm.AllAddresses); // vm is the CustomerViewModel
Conditional Data Sources:
Any of these methods can be made conditional:
Mapper.WhenMapping
.From<ProductDto>() // Apply to ProductDto mappings
.ToANew<Product>() // Apply to Product creation only
.If((dto, p) => dto.CompanyId == 0) // Apply only if CompanyId is 0
.Map("No-one") // Always the same value
.To(p => p.CompanyName); // p is the Product
// Only include WorkAddress if it's different to HomeAddress:
Mapper.WhenMapping
.From<Customer>() // Apply to Customer mappings
.ToANew<CustomerViewModel>() // Apply to CustomerViewModel creation
.Map((c, vm) => new[] { c.HomeAddress })
.Then.If((c, vm) => c.WorkAddress != c.HomeAddress )
.Map((c, vm) => new[] { c.WorkAddress })
.Then.Map((c, vm) => c.AddressHistory)
.To(vm => vm.AllAddresses); // vm is the CustomerViewModel
And in an inline example:
Mapper.Map(productDto).ToANew<Product>(cfg => cfg
.If((dto, p) => dto.CompanyId == 0) // Apply only if CompanyId is 0
.Map("No-one") // Always the same value
.To(p => p.CompanyName); // p is the Product
Auto-Reversing Configured Data Sources
By default, configured data sources only apply in the direction configured - configuring ProductDto.Spec
-> Product.Specification
doesn't make Product.Specification
map to ProductDto.Spec
when the reverse mapping is performed.
To make every source- to target-member pairing you configure apply to mappings in either direction, use:
Mapper.WhenMapping.AutoReverseConfiguredDataSources();
To make every source- to target-member pairing you configure for a particular pair of Types apply to mappings in either direction, use:
Mapper.WhenMapping
.From<Product>().To<ProductDto>()
.AutoReverseConfiguredDataSources();
To make a source- to target-member pairing you configure apply to mappings in either direction, use:
Mapper.WhenMapping
.From<Product>().To<ProductDto>()
.Map(p => p.Specification, dto => dtp.Spec)
.AndViceVersa();
Opting Out of Auto-Reversal
If you use the mapper-level AutoReverseConfiguredDataSources()
to set the default behaviour, source- to target-member pairings you configure for a particular pair of Types can opt out using:
// Set the default behaviour:
Mapper.WhenMapping.AutoReverseConfiguredDataSources();
// Opt out for ProductDto -> Product:
Mapper.WhenMapping
.From<Product>().To<ProductDto>()
.DoNotAutoReverseConfiguredDataSources();
...and individual source- to target-member pairings can opt out with:
Mapper.WhenMapping
.From<Product>().To<ProductDto>()
.Map(p => p.Specification, dto => dtp.Spec)
.ButNotViceVersa();
Mapping Nested Data Sources to the Target
To map a nested member to the target object, use, e.g:
// Source class - has a nested member 'Statistics':
class Video
{
public string Title { get; set; }
public int LengthInSeconds { get; set; }
public VideoStatistics Statistics { get; set; }
}
class VideoStatistics
{
public int ViewCount { get; set; }
}
// Target class:
class VideoDto
{
public string Title { get; set; }
public int LengthInSeconds { get; set; }
public int ViewCount { get; set; }
}
Mapper.WhenMapping
.From<Video>() // Apply to Video mappings
.To<VideoDto>() // Apply to all VideoDto mappings
.Map((v, dto) => v.Statistics)
.ToTarget(); // The VideoDto is the target
In this example, the ToTarget()
configuration causes Video.Statistics.ViewCount
to be mapped to
VideoDto.ViewCount
. Video.Title
is mapped to VideoDto.Title
as expected.
Switching Data Sources
To switch a mapping data source to a different value, use, e.g:
class VideoLibrary
{
public Dictionary<int, Video> VideosById { get; set; }
}
class VideoLibraryDto
{
public IList<VideoDto> Videos { get; set; }
}
Mapper.WhenMapping
.FromDictionariesWithValueType<Video>()
.To<IList<VideoDto>>()
.Map((d, l) => d.Values)
.ToTargetInstead();
In this example, in any mapping where Dictionary<string, Video>
is matched to an IList<VideoDto>
,
the Dictionary's Values
collection is used as the source instead of the Dictionary.