3

我有一个 .Net 5 Web Api 项目并想使用

Mapster v7.2.0

以避免手动映射对象。以下代码显示了一个示例场景

  • 设置映射配置
  • 来自多个来源的地图
  • 映射到不同名称的字段

.

[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
    [HttpGet]
    public ActionResult<UsernameWithTodoTitle> Get()
    {
        TypeAdapterConfig<(User, Todo), UsernameWithTodoTitle>
            .NewConfig()
            .Map(dest => dest, src => src.Item1) // map everything from user
            .Map(dest => dest, src => src.Item2) // map everything from todo
            .Map(dest => dest.TodoTitle, src => src.Item2.Title); // map the special fields from todo
        
        var user = new User { Username = "foo", FieldFromUser = "x" };
        var todo = new Todo { Title = "bar", FieldFromTodo = "y" };
        
        var usernameWithTodoTitle = (user, todo).Adapt<(User, Todo), UsernameWithTodoTitle>();
        
        return Ok(usernameWithTodoTitle);
    }
}

public class User
{
    public string Username { get; set; }
    public string FieldFromUser { get; set; }
}

public class Todo
{
    public string Title { get; set; } // !! map this one to the TodoTitle field !!
    public string FieldFromTodo { get; set; }
}

public class UsernameWithTodoTitle
{
    public string Username { get; set; }
    public string TodoTitle { get; set; } // !! this one is special, is has a different name !!
    public string FieldFromUser { get; set; }
    public string FieldFromTodo { get; set; }
}

运行应用程序时,映射似乎以这种方式工作正常

在此处输入图像描述

我必须以这种方式设置配置,其他方式对我不起作用。但是还有3件事需要解决

  • 配置对我来说看起来不对。它映射待办事项中的所有内容并再次映射特殊字段......所以它可能会循环多次?如果有多个名称不同的字段,这可能会很昂贵
  • 我在控制器内部创建了配置。如何创建一个全局注册一次的可重用映射配置文件类?
  • 当有一个映射配置文件时,这条线var usernameWithTodoTitle = (user, todo).Adapt<(User, Todo), UsernameWithTodoTitle>();对我来说看起来很乱。更好的是var usernameWithTodoTitle = UsernameWithTodoTitle.Adapt((user, todo)) /* pass in as a tuple */因为它根据参数类型选择正确的映射配置文件

你们对如何创建这样的映射配置文件有任何想法吗?

4

3 回答 3

2

更新:无法找到使用 Mapster 执行您尝试执行的操作的方法,但这里有一个使用 Automapper 的示例。

using AutoMapper;
using System;

namespace ConsoleApp5
{
    class A { public string FirstName { get; set; } }

    public class B { public string Address1 { get; set; } }

    public class C
    {
        public string FirstName { get; set; }
        public string Address1 { get; set; }
    }

    public class DemoProfile : Profile
    {
        public DemoProfile()
        {
            CreateMap<(A, B), C>()
                .ForMember(dest=> dest.FirstName, opts => opts.MapFrom(src => src.Item1.FirstName))
                .ForMember(dest => dest.Address1, opts => opts.MapFrom(src => src.Item2.Address1));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var config = new MapperConfiguration(cfg => {
                cfg.AddProfile<DemoProfile>();
            });

            var mapper = config.CreateMapper();
            var destination = mapper.Map<C>((new A {  FirstName = "Test" }, new B { Address1 = "Addr" }));

            Console.ReadKey();
        }
    }
}

嘿,直到现在我还没有使用过 Mapster,但这是我收集的。Tuple<T1,T2>它对您使用的元组类型非常具体,(T1,T2)但除了那件小事之外,我能够让它运行和映射而没有问题。这是一个小控制台示例作为示例。

using Mapster;
using System;

namespace ConsoleApp5
{
    class A { public string FirstName { get; set; } }

    public class B { public string Address1 { get; set; } }

    public class C
    {
        public string FirstName { get; set; }
        public string Address1 { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Option 1
            TypeAdapterConfig<Tuple<A, B>, C>.NewConfig()
                .Map(dest => dest.FirstName, src => src.Item1.FirstName)
                .Map(dest => dest.Address1, src => src.Item2.Address1);

            var destObject = new Tuple<A, B>(new A { FirstName = "Test" }, new B { Address1 = "Address 1" })
                .Adapt<Tuple<A, B>, C>();

            // Option 2
            TypeAdapterConfig<(A, B), C>.NewConfig()
                .Map(dest => dest.FirstName, src => src.Item1.FirstName)
                .Map(dest => dest.Address1, src => src.Item2.Address1);

            var destObject2 = (new A { FirstName = "Test" }, new B { Address1 = "Address 1" })
                .Adapt<(A, B), C>();

            Console.ReadKey();
        }
    }
}
于 2021-08-28T05:58:40.667 回答
0

你可以使用下一个:

    var config = new TypeAdapterConfig()
    {
        RequireExplicitMapping = true,
        RequireDestinationMemberSource = true,
        Compiler = exp => exp.CompileFast()
    };

    config.Scan("Your assembly");

    services.AddSingleton(config);
    services.AddTransient<IMapper, ServiceMapper>();

    public class RegisterConfig : IRegister
    {
        public void Register(TypeAdapterConfig config)
        {
            config.NewConfig<TSource, TDestination>();
        }
    }

服务在哪里 IServiceCollection

于 2021-12-24T15:49:51.383 回答
0

基于@Felipe Ramos 的回答,我无法使用 Mapster 解决它,而是使用 Automapper。为了完整起见,这是我的解决方案。如果 Mapster 有解决方案,请告诉我!

我安装了软件包

AutoMapper v10.1.1

AutoMapper.Extensions.Microsoft.DependencyInjection v8.1.1

在方法内Startup.ConfigureServices我添加了行services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

整个代码看起来像

[ApiController]
[Route("[controller]")]
public class MyController : ControllerBase
{
    private readonly IMapper _mapper;
    
    public MyController(IMapper mapper)
    {
        _mapper = mapper;
    }
    
    [HttpGet]
    public ActionResult<UsernameWithTodoTitle> Get()
    {
        var user = new User { Username = "foo", FieldFromUser = "x" };
        var todo = new Todo { Title = "bar", FieldFromTodo = "y" };
        var usernameWithTodoTitle = _mapper.Map<UsernameWithTodoTitle>((user, todo));
    
        return Ok(usernameWithTodoTitle);
    }
}

public class User
{
    public string Username { get; set; }
    public string FieldFromUser { get; set; }
}

public class Todo
{
    public string Title { get; set; } // !! map this one to the TodoTitle field !!
    public string FieldFromTodo { get; set; }
}

public class UsernameWithTodoTitle
{
    public string Username { get; set; }
    public string TodoTitle { get; set; } // !! this one is special, is has a different name !!
    public string FieldFromUser { get; set; }
    public string FieldFromTodo { get; set; }
}

public class UsernameWithTodoTitleMappingProfile : Profile
{
    public UsernameWithTodoTitleMappingProfile()
    {
        CreateMap<(User, Todo), UsernameWithTodoTitle>()
            .ForMember(
                destination => destination.Username,
                memberOptions => memberOptions.MapFrom(source => source.Item1.Username))
            .ForMember(
                destination => destination.TodoTitle,
                memberOptions => memberOptions.MapFrom(source => source.Item2.Title))
            .ForMember(
                destination => destination.FieldFromUser,
                memberOptions => memberOptions.MapFrom(source => source.Item1.FieldFromUser))
            .ForMember(
                destination => destination.FieldFromTodo,
                memberOptions => memberOptions.MapFrom(source => source.Item2.FieldFromTodo));
    }
}
于 2021-08-29T13:55:07.417 回答