如何使用 Mapster 创建可重复使用的映射配置文件?
How to create a reusable mapping profile with Mapster?
我有一个 .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件事需要解决
- 我觉得配置不对。它映射了 todo 中的所有内容并再次映射了特殊字段……所以它可能会循环多次?如果有多个名称不同的字段,这可能会变得很昂贵
- 我在控制器内部创建了配置。如何创建一个可重复使用的映射配置文件 class 全局注册一次?
- 当有一个映射配置文件时,这一行
var usernameWithTodoTitle = (user, todo).Adapt<(User, Todo), UsernameWithTodoTitle>();
对我来说看起来很乱。更好的做法是 var usernameWithTodoTitle = UsernameWithTodoTitle.Adapt((user, todo)) /* pass in as a tuple */
,因为它会根据参数类型选择正确的映射配置文件
你们知道如何创建这样的映射配置文件吗?
已更新:无法找到方法来完成您尝试使用 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,但这是我收集到的。它非常具体地说明了您在 (T1,T2)
上使用 Tuple<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();
}
}
}
根据@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));
}
}
您可以使用下一个:
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
我有一个 .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件事需要解决
- 我觉得配置不对。它映射了 todo 中的所有内容并再次映射了特殊字段……所以它可能会循环多次?如果有多个名称不同的字段,这可能会变得很昂贵
- 我在控制器内部创建了配置。如何创建一个可重复使用的映射配置文件 class 全局注册一次?
- 当有一个映射配置文件时,这一行
var usernameWithTodoTitle = (user, todo).Adapt<(User, Todo), UsernameWithTodoTitle>();
对我来说看起来很乱。更好的做法是var usernameWithTodoTitle = UsernameWithTodoTitle.Adapt((user, todo)) /* pass in as a tuple */
,因为它会根据参数类型选择正确的映射配置文件
你们知道如何创建这样的映射配置文件吗?
已更新:无法找到方法来完成您尝试使用 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,但这是我收集到的。它非常具体地说明了您在 (T1,T2)
上使用 Tuple<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();
}
}
}
根据@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));
}
}
您可以使用下一个:
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