【问题标题】:Automapper unmapped properties error with simple objects mappings简单对象映射的 Automapper 未映射属性错误
【发布时间】:2019-06-23 10:10:47
【问题描述】:

我需要将来自 API 的模型对象映射到 DbContext 上的实际实体对象。它在使用 POST 操作创建新机器对象时使用。

与往常一样,我为源/目标对象创建了一个简单的地图。 在这种情况下,我们将源对象视为 API 模型,将目标对象视为实体。此外,模型只有实体属性的一个子集。

来源/目的地类型

// Destination (entity on DbContext)
public class Machine
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string MnmConfiguration { get; set; }
    public MachineBootStatus Status { get; set; }
    public long MachineDriverId { get; set; }
    public MachineDriver MachineDriver { get; set; }
    public string DriverConfiguration { get; set; }
    public string DriverStatus { get; set; }
}

// Source (from API controller)
public class MachineCreateModel
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string MnmConfiguration { get; set; }
    public long MachineDriverId { get; set; }
}

映射配置

public class DomainProfile : Profile
{
    public DomainProfile()
    {
        //CreateMap<MachineCreateModel, Machine>();
        // Update 2019/01/30 with proposed solution
        CreateMap<MachineCreateModel, Machine>(MemberList.Source);
    }
}

我正在使用 Unity DI 容器,AutoMapper 的配置是这样的:

container = new UnityContainer();
// ... some other configurations...
container.RegisterType<IMapper, Mapper>(new InjectionConstructor(new MapperConfiguration(cfg => cfg.AddProfile<DomainProfile>())));

版本

使用 AutoMapper v8.0.0。

预期行为

我希望获得一个没有错误的简单自动映射,因为我的源模型只是目标模型属性的子集,具有相同的名称。

实际行为

当我点击这行代码时,我收到关于未映射属性的错误:

Machine entity = Mapper.Map<Machine>(request.Machine);
[14:08:34.363 8 2e62361a INF] Creating new machine: TEST M1
[14:08:36.205 8 bd577466 ERR] An unhandled exception has occurred while executing the request.
AutoMapper.AutoMapperConfigurationException:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
=================================================================================================
AutoMapper created this type map for you, but your types cannot be mapped using the current configuration.
MachineCreateModel -> Machine (Destination member list)
MyApplication.Dcs.Application.Models.MachineCreateModel -> MyApplication.Dcs.Domain.Entities.Machine (Destination member list)

Unmapped properties:
Id
Status
MachineDriver
DriverConfiguration
DriverStatus

   at AutoMapper.ConfigurationValidator.AssertConfigurationIsValid(IEnumerable`1 typeMaps)
   at lambda_method(Closure , MachineCreateModel , Machine , ResolutionContext )
   at lambda_method(Closure , Object , Object , ResolutionContext )
   at AutoMapper.Mapper.AutoMapper.IMapper.Map[TDestination](Object source)
   at MyApplication.Dcs.Application.Commands.MachineCreateCommandHandler.Handle(MachineCreateCommand request, CancellationToken cancellationToken) ..Commands\MachineCreateCommand.cs:line 28

注意

在我的解决方案中,我有很多项目,其中 3 个正在使用 AutoMapper(所有人的版本相同)。有 3 个不同的 DomainProfile.cs 文件(每个项目 1 个)具有所需的映射。 在其他 2 个 DomainProfile 类中,我有一些手动映射(参见下面的示例),因为我需要将具有意大利属性名称的对象“翻译”为另一个具有英文属性名称的对象。所以每个对象映射有很多行,比如:

CreateMap<ArticleCreateUpdateModel, Articoli>()
    .ForMember(d => d.Categoria, opt => opt.MapFrom(src => src.Category))
    .ForMember(d => d.CodiceArticolo, opt => opt.MapFrom(src => src.Code))
    .ForMember(d => d.Descrizione, opt => opt.MapFrom(src => src.Description))
    .ForMember(d => d.Famiglia, opt => opt.MapFrom(src => src.Family))
    .ForMember(d => d.Note, opt => opt.MapFrom(src => src.Note))
    ...

我不知道这些手动成员映射到一个或多个 DomainProfile 类上的使用是否会以某种方式迫使我始终解释所有后续映射,即使它们应该像本示例中的那样简单。

【问题讨论】:

标签: c# .net-core mapping entity-framework-core automapper


【解决方案1】:

默认情况下,AutoMapper 会验证目标属性。由于您的目标类型中的一堆属性既没有匹配的属性,也没有 ForMember 构造,因此您会遇到上述异常。

尝试验证源属性:

CreateMap<ArticleCreateUpdateModel, Articoli>(MemberList.Source)
    .ForMember(d => d.Categoria, opt => opt.MapFrom(src => src.Category))
    // ...

备注: 另一方面,我不得不提一下,这是 AutoMapper 大材小用的典型案例。除了琐碎的案例,我再也不会使用它了。

我不得不在一个项目中使用它一年多,但实际上它只有助于使简单的事情变得比必要的复杂。一些FromDtoToDto [extension] 方法只是更简单、更快、更容易调试并且对代码更改更具反应性。不同类布局或属性名称之间的映射通常会产生与手动编写映射一样多的代码(甚至更多的 lambda)。另见this link

【讨论】:

  • LINQ to Entities 查询投影怎么样? ToDto 作为自定义方法无法转换为 SQL,会导致客户评估/不必要的实体跟踪。
  • @IvanStoev:我更喜欢 Entity with code first,其中没有额外的生成模型类层和庞大的 EDMX xml 文件。但即使您拥有它们,您也可以通过显式执行任何查询之前调用ToDto 来避免完整的客户端评估。意思是,某些Repository 类中的所有查询纯粹使用实体模型类。有人可能会争辩说 AutoMapper 的 .ProjectTo 更好,因为不需要从外部进行显式映射,但我认为在我的 Repository 中根本不能引用更高级别的类。
  • @taffer 我已经尝试使用MemberList.Source,使用我的模型(DTO)作为源,实体作为目标,但它没有用。无论如何,这是我第一次遇到这种问题。我在其他项目中使用过 AutoMapper(以前的版本),从来没有发生过这样的事情。
  • @CheshireCat:您甚至可以尝试MemberList.None 完全禁用验证。你提到你使用以前的版本。另请注意,AutoMapper 喜欢在其新版本中进行重大更改(我不喜欢它的另一个原因)。我不确定您的CreateMap 示例是否是片段,但请务必使用Mapper.Initialize(cfg =&gt; cfg.CreateMap(...)); 的最新配置方式。
  • 还有一点需要注意:异常来自Machine,而不是Articoli,因此请务必使用MemberList.Source/None 进行映射。
猜你喜欢
  • 1970-01-01
  • 2017-08-29
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 2019-01-04
  • 2017-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多