首页 > 解决方案 > 如何从 ViewModel 映射到具有基本属性的模型

问题描述

我想将 ViewModel 映射到具有基类的模型,但不向 ViewModel 添加基类。

我想保持我的班级结构。

我曾尝试使用 Include、IncludeBase、IncludeDerived,但找不到好的配置。

这是我的代码

public class Program
{
    private static void Main(string[] args)
    {
        Console.WriteLine("Hello World!");

        var mapper = new MapperConfiguration(mc => mc.AddProfile(new MappingProfile())).CreateMapper();

        var model = new RegisterViewModel { Name = "TEST" };

        var x = mapper.Map<Register>(model, Guid.NewGuid());
    }
}

public interface ICommand
{
    Guid Id { get; }

    Guid AggregateId { get; }
}

public abstract class Command : ICommand
{
    protected Command() => Id = Guid.NewGuid();

    public Guid Id { get; }

    public Guid AggregateId { get; private set; }
}

public sealed class Register : Command
{
    public string Name { get; private set; }
}

public class RegisterViewModel
{
    public string Name { get; set; }
}

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<RegisterViewModel, Command>()
           .ForMember(x => x.Id, opt => opt.Ignore())
           .AddCommandFields()
           .Include<RegisterViewModel, Register>();

        CreateMap<RegisterViewModel, Register>().IncludeBase<RegisterViewModel, Command>().AddCommandFields();
    }
}

public static class MapperExtensions
{
    private static readonly string AGGREGATE_KEY = "AGGREGATE";

    public static TDestination Map<TDestination>(this IMapper mapper, object source, Guid aggregateId)
    {
        return mapper.Map<TDestination>(source, opt =>
        {
            opt.Items[AGGREGATE_KEY] = aggregateId;
        });
    }

    public static IMappingExpression<TSource, TDestination> AddCommandFields<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression)
        where TDestination : ICommand => expression.ForMember(x => x.AggregateId, opt => opt.MapFromAggregate());

    private static void MapFromAggregate<TSource, TDestination>(this IMemberConfigurationExpression<TSource, TDestination, Guid> expression) => expression.MapFrom((_, __, ___, context) => context.Items[AGGREGATE_KEY]);
}

对于派生属性 Automapper 可以正常工作,但未映射基本属性,尽管调用了 MapFromAggregate。

编辑

正如@Lucian Bargaoanu 建议的那样,我想删除扩展方法,但后来我发现问题出在方法“AddCommandFields”上。

此代码正常工作

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<RegisterViewModel, Command>()
           .ForMember(x => x.Id, opt => opt.Ignore())
           .ForMember(x => x.AggregateId, opt => opt.MapFromAggregate())
           .Include<RegisterViewModel, Register>();

        CreateMap<RegisterViewModel, Register>()
           .IncludeBase<RegisterViewModel, Command>()
          .ForMember(x => x.AggregateId, opt => opt.MapFromAggregate());
    }
}

public static class MapperExtensions
{
    private static readonly string AGGREGATE_KEY = "AGGREGATE";

    public static TDestination Map<TDestination>(this IMapper mapper, object source, Guid aggregateId)
    {
        return mapper.Map<TDestination>(source, opt =>
        {
            opt.Items[AGGREGATE_KEY] = aggregateId;
        });
    }

    public static void MapFromAggregate<TSource, TDestination>(this IMemberConfigurationExpression<TSource, TDestination, Guid> expression) => expression.MapFrom((_, __, ___, context) => context.Items[AGGREGATE_KEY]);
}

我不知道为什么这个扩展方法会破坏我的代码。

标签: c#automapper

解决方案


问题是通用约束是 forICommand并且没有 setter for ICommand.AggregateId。您可以将约束更改为Command或添加设置器ICommand.AggregateId


推荐阅读