为什么 Automapper 会自动将 Driver.Name 映射到 DriverName

Why does Automapper map Driver.Name to DriverName automatically

我有以下 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; }

和查看模型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; }
}

我有以下 Automapper 规则:

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

并尝试使用:

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

而且有效!为什么? ScheduledDeductionDetailVM 有 属性 DriverName ,它可以从 ScheduledDeduction.Driver.Name 中得到,它根本没有被描述过。但它映射正确...

这是框架的一个特性。

根据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).

Automapper 使用许多不同的 conventions, and this behaviour is also part of different conventions. On the page about Flattening 据称

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).

但是如果你这样做:

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

它将不再是这种情况,因为您将目标成员命名约定从 PascalCase 更改为 LowerUnderscore。

或者如果你这样做:

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

它还会破坏您观察到的行为,因为您删除了成员命名约定。