1

I have the following classes:

public partial class ScheduledDeduction
{
    public int ID { get; set; }

    public int DriverId { get; set; }

    public string Description { get; set; }

    public DateTime DateTime { get; set; }

    public decimal Amount { get; set; }

    public virtual Driver Driver { get; set; }
}

public partial class Driver
{

    public int ID { get; set; }

    public int CompanyId { get; set; }

    public string Name { get; set; }

and View Model class:

public abstract class ScheduledDeductionDetailVM
{
    public int ID { get; set; }

    [Display(Name = "Driver Name")]
    public string DriverName { get; set; }

    public string Description { get; set; }

    [Display(Name = "Date")]
    [DisplayFormat(DataFormatString = "{0:d}")]
    public System.DateTime DateTime { get; set; }

    [Display(Name = "Amount")]
    [DisplayFormat(DataFormatString = "{0:c}")]
    public decimal Amount { get; set; }
}

I have the following rule of Automapper:

CreateMap<Infrastructure.Asset.ScheduledDeduction, ViewModels.ScheduledDeductionDetailVM>();

and try to use:

ScheduledDeduction scheduledDeduction = db.ScheduledDeductions.Find(id);
ScheduledDeductionDetailVM model = mapper.Map<ScheduledDeductionDetailVM>(scheduledDeduction);

and it works! Why? ScheduledDeductionDetailVM has property DriverName , which can be got from ScheduledDeduction.Driver.Name and it never described at all. But it's mapped correctly...

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Oleg Sh
  • 8,496
  • 17
  • 89
  • 159
  • Haven't you defined any mapping rules? – Christos Jun 11 '17 at 15:47
  • That is too broad a question. That is how the framework was designed. It is mentioned in documentation. It is called [Flattening](https://github.com/AutoMapper/AutoMapper/wiki/Flattening) – Nkosi Jun 11 '17 at 15:47
  • I refere to the configuration that is presented here https://github.com/AutoMapper/AutoMapper/wiki/Configuration? Haven't you done anything similar to the things described there? – Christos Jun 11 '17 at 15:49

2 Answers2

4

That is a feature of the framework.

According to documentation about Flattening

One of the common usages of object-object mapping is to take a complex object model and flatten it to a simpler model.

....

When you configure a source/destination type pair in AutoMapper, the configurator attempts to match properties and methods on the source type to properties on the destination type. If for any property on the destination type a property, method, or a method prefixed with "Get" does not exist on the source type, AutoMapper splits the destination member name into individual words (by PascalCase conventions).

Nkosi
  • 235,767
  • 35
  • 427
  • 472
2

Automapper uses many different conventions, and this behaviour is also part of different conventions. On the page about Flattening it is stated that

If for any property on the destination type a property, method, or a method prefixed with "Get" does not exist on the source type, AutoMapper splits the destination member name into individual words (by PascalCase conventions).

But if you do this:

var config = new MapperConfiguration(cfg => {
    cfg.DestinationMemberNamingConvention = new LowerUnderscoreNamingConvention();                
    cfg.CreateMap<ScheduledDeduction, ScheduledDeductionDetailVM>();
});

It will no longer be the case, because you changed destination member naming convention from PascalCase to LowerUnderscore.

Or if you do this:

var config = new MapperConfiguration(cfg => {
    var profile = (Profile)cfg;
    profile.DefaultMemberConfig.MemberMappers.Clear();
    cfg.CreateMap<ScheduledDeduction, ScheduledDeductionDetailVM>();
});

It will also break behaviour you observe, because you removed member naming conventions.

Evk
  • 98,527
  • 8
  • 141
  • 191