Automapper map one field differently - automapper

I have a class that I want to map to another. All the fields have the same name in both classes, except one.
Is there a quick way to do that, without having to use ForMember for all fields?
Thank you.

Found a solution :
cfg.CreateMap<MasterA, MasterB>().ForMember
(dest => dest.IdOld, opt => opt.MapFrom(src => src.Id));

Related

How to bind IReadonlyReactiveList to ReactiveCollectionView

I have a view model that retrieve a list of data from rest service, and store inside a property.
private readonly ObservableAsPropertyHelper<IReadOnlyReactiveList<Customer>> _searchResultCustomer;
public IReadOnlyReactiveList<Customer> SearchResultCustomer => _searchResultCustomer.Value;
I am trying to do a binding between SearchResultCustomer to ReactiveCollectionView like this this.OneWayBind(ViewModel, vm => vm.SearchResultCustomer, v => v.cvResult.DataSource);.
Without surprise it doesn't work, and the type expected from v.cvResult.DataSource is IUICollectionViewDataSource.
How do I solve this, is there any available example for Xamarin.IOS? Thanks :)
Binding to a UI collection, such as UITableView or UICollectionView, works a bit differently. Conveniently, you don't even need to create your own UICollectionViewSource. Just create a custom cell with an initialize method and bind like this:
ViewModel.WhenAnyValue(vm => vm.SearchResultCustomer).BindTo<Customer, CustomerCell>(collectionView, cell => cell.Initialize());
Credit to Paul Reichelt at this thread who answered a similar question, except for UITableView.
I forked his example project and added a working example for UICollectionView. I use IReactiveList instead of IReadOnlyReactiveList, but you should be able to modify it to fit your needs. Here's the source. Hope it helps.

Tell AutoMapper that a field is a top-level member

I am trying to take some of the pain out of creating mapping expressions in AutoMapper, using AutoMapper.QueryableExtensions
I have the following, which gives a critical performance gain:
private MapperConfiguration CreateConfiguration() {
return new MapperConfiguration(cfg => cfg.CreateMap<Widget, WidgetNameDto>()
.ForMember(dto => dto.Name,
conf => conf.MapFrom(w => w.Name)));
}
To understand the performance gain, see here: https://github.com/AutoMapper/AutoMapper/blob/master/docs/Queryable-Extensions.md The key is that the query is limited by field at the database level.
It's terrific that this works. But I anticipate needing to do a lot of this kind of projecting. I am trying to take some of the pain out of the syntax in the ForMember clause above.
For example, I've tried this:
public static IMappingExpression<TFrom, TTo> AddProjection<TFrom, TTo, TField>(this IMappingExpression<TFrom, TTo> expression,
Func<TFrom, TField> from,
Func<TTo, TField> to
)
=> expression.ForMember(t => to(t), conf => conf.MapFrom(f => from(f)));
The problem is that everything I do runs into an error:
AutoMapper.AutoMapperConfigurationException : Custom configuration for members is only supported for top-level individual members on a type.
Even if the passed in Funcs are top-level individual members, that fact is lost in the passing, so I hit the error. I've also tried changing Func<Whatever> to Expression<Func<Whatever>>. It doesn't help.
Is there any way I can simplify the syntax of the ForMember clause? Ideally, I would just pass in the two relevant fields.
First, there is no need to add mapping for the fields/properties that match by name - AutoMapper maps them automatically by convention (that's why it is called convention-based object-object mapper). And for including just some of the properties in the projection you could use the Explicit expansion feature.
Second, what you call a pain in the ForMember syntax is in fact a flexibility. For instance, the explicit expansion and other behaviors can be controlled by conf argument, so it's not only for specifying the source.
With that being said, what you ask is possible. You have to change the from/ to type to Expression:
Expression<Func<TFrom, TField>> from,
Expression<Func<TTo, TField>> to
and the implementation simply as follows:
=> expression.ForMember(to, conf => conf.MapFrom(from));

automapper mapping a indexer

I am trying to write a mapping to map between two classes using automapper. Most of it is pretty straight forward, direct mappings between 2 fields of the same type. However, I have an indexer on each class that may that need to map to each other. It probably isn't relevant that the source type has an indexer, so essentially what I am trying to do is something like:
mappingExpression.ForMember(d => d["Text"], opt => opt.MapFrom(s => s.Text));
Which gives me the error:
Custom configuration for members is only supported for top-level individual members on a type.
Is there any way of achieving this?

Automapping Lists

I'm starting to learn AutoMapper and coming up against a couple of minor problems.
Essentially I'm getting null reference exceptions when trying to bind to ILists produced by AutoMapper.
My boot strapping method looks like this:
Mapper.CreateMap<Claimant, ClaimantViewModel>()
.ForMember(
vm => vm.Check,
opt => opt.Ignore());
Mapper.CreateMap<IList<Claimant>, IList<ClaimantViewModel>>();
Mapper.AssertConfigurationIsValid();
Which doesn't look to fancy to me. I then try to call:
dlWAMs.DataSource = Mapper.Map<IList<Claimant>, IList<ClaimantViewModel>(someilist);
dlWAMs.DataBind();
With that I'm getting a null reference exception. If I code my own loop and map the models to a view model one at a time the code runs fine.
What am I doing wrong?
First of all you don't need that second map that creates map from IList to IList, remove it. Than if it does not work, show us your classes.

Issue with ignoring base class property in child classes mappings using Automapper

I have a scenario where I would like to ignore some properties of classes defined in base class.
I have an initial mapping like this
Mapper.CreateMap<Node, NodeDto>()
.Include<Place, PlaceDto>()
.Include<Asset, AssetDto>();
Then I customised it more like this to ignore one of the properties defined in base class NodeDto
Mapper.CreateMap<Node, NodeDto>()
.ForMember(dest => dest.ChildNodes, opt => opt.Ignore());
However when I try to map, Place to PlaceDto or Asset to AssetDto, the ChildNodes property does not get ignored. So I ended up doing soething like this
Mapper.CreateMap<Node, NodeDto>()
.ForMember(dest => dest.ChildNodes, opt => opt.Ignore());
Mapper.CreateMap<Place, PlaceDto>()
.ForMember(dest => dest.ChildNodes, opt => opt.Ignore());
Mapper.CreateMap<Asset, AssetDto>()
.ForMember(dest => dest.ChildNodes, opt => opt.Ignore());
Since I have lots of child classes for NodeDto, the above process is cumbersome, and I would like to know if there is a better approach?
Thanks
Nabeel
It gets even more cumbersome if you then decide that you want to ignore not just 1, but 2, 3 or maybe even more properties from the base class. It might not help you much in this case and I'm sure 9 months on you've probably found a solution already, but for the benefit of anyone else stumbling across this question an extension method could reduce some of the complexity.
public static class MappingExtensions
{
public static IMappingExpression<Node, NodeDto> MapNodeBase<Node, NodeDto>(
this IMappingExpression<Node, NodeDto> mappingExpression)
{
// Add your additional automapper configuration here
return mappingExpression.ForMember(
dest => dest.ChildNodes,
opt => opt.Ignore()
);
}
}
Which you would then call thus:
Mapper.CreateMap<Node, NodeDto>()
.MapNodeBase()
.Include<Place, PlaceDto>()
.Include<Asset, AssetDto>();
sorry but, no, there isn't any other way, that's how automapper works
There is a better way. For our project we created mappings.xml file with following structure.
<mappings>
<mapping name="EntityOne">
<configuration name="Flat">
<ignore name="ChildCollectionOne"/>
<ignore name="ChildCollectionTwo"/>
<ignore name="ChildCollectionThree"/>
</configuration>
<configuration name="Full">
<include name="ChildCollectionOne" configuration="Flat" type="One"/>
<include name="ChildCollectionTwo" configuration="Flat" type="Two"/>
<include name="ChildCollectionThree" configuration="Flat" type="Three"/>
</configuration>
</mapping>
</mappings>
Special class AutoMapperUtilis is used for parsing data form xml and configuring Automapper according to given rules.
Call is:
AutoMapperUtil.Init(typeof(EntityOne),typeof(EntityOneDto), AutoMapperUtilLoadType.Flat);
After that all required mappings are automatically loaded, and specified ChildCollections are ignored.
With this mappings descriptions we can choose between Flat or Full configuration depending of our Use Case. We are using AutoMapper for mapping between nHibernate entities and Dto`s that are used with Ria Services, and we are very happy with this solution.

Resources