2

All my domain models have field public CurrencyId CurrencyId {get; set;}. All my view models have filed public CurrencyVm Currency {get; set;}. Automapper knows how to Map<CurrencyVm>(CurrencyId). How can I setup automatic convention, so I do not have to .ForMember(n => n.Currency, opt => opt.MapFrom(n => n.CurrencyId));?

Shadow
  • 2,089
  • 2
  • 23
  • 45

1 Answers1

2

ForAllMaps is the answer, thanks @LucianBargaoanu. This code kinda works, but hasn't been tested in all cases. Also I do not know how to check if exists mapping between choosen properties.

        configuration.ForAllMaps((map, expression) =>
        {
            if (map.IsValid != null)
            {
                return; // type is already mapped (or not)
            }

            const string currencySuffix = "Id";
            var currencyPropertyNames = map.SourceType
                .GetProperties()
                .Where(n => n.PropertyType == typeof(CurrencyId) && n.Name.EndsWith(currencySuffix))
                .Select(n => n.Name.Substring(0, n.Name.Length - currencySuffix.Length))
                .ToArray();
            expression.ForAllOtherMembers(n =>
            {
                if (currencyPropertyNames.Contains(n.DestinationMember.Name, StringComparer.OrdinalIgnoreCase))
                {
                    n.MapFrom(n.DestinationMember.Name + currencySuffix);
                }
            });
        });
Shadow
  • 2,089
  • 2
  • 23
  • 45
  • This is way too complicated. Try ForAllMaps with ForAllMembers and the string based MapFrom. – Lucian Bargaoanu Jun 04 '18 at 09:47
  • @LucianBargaoanu but my problem is complex - I want to map CurrencyId to currency, but also SummaryCurrencyId to SummaryCurrency etc. – Shadow Jun 04 '18 at 10:13
  • Yes, and in ForAllMembers you can check that for each member. – Lucian Bargaoanu Jun 04 '18 at 10:15
  • @LucianBargaoanu in ForAllOtherMembers I do not have access to sourcemember, only destination, so I cannot compare names, and check if mapping is valid, etc. – Shadow Jun 04 '18 at 10:29
  • You also don't have access to the source member your way. I still think ForAllMembers would be better. – Lucian Bargaoanu Jun 04 '18 at 10:50
  • I do - `currencyProperties = map.SourceType.GetProperties()` there is check if source member is `CurrencyId`, and if it ends with `Id`. – Shadow Jun 04 '18 at 11:12
  • OK, and you can pass that into ForAllMembers, right? :) – Lucian Bargaoanu Jun 04 '18 at 11:29
  • Yes, but without the outer for each. – Lucian Bargaoanu Jun 04 '18 at 12:58
  • @LucianBargaoanu edited answer to reflect this, but I kinda dislike this solution because of that id reconstruction and all that collections captured in lambdas. Also I dislike using automapper apis, because they like to mess it in new versions :/ – Shadow Jun 04 '18 at 14:55
  • I forgot about [this](http://docs.automapper.org/en/stable/Configuration.html#recognizing-pre-postfixes). – Lucian Bargaoanu Jun 05 '18 at 18:56
  • @LucianBargaoanu I saw that, but it is not that good IMO. Generally I feel that automapper has tendency to create huge mess and unexpected errors, that's why I want my mapping to be precise. Automatically mapping StuffId to Stuff feels too overwhelming for me. – Shadow Jun 07 '18 at 10:51