稳【Java开发300个实用技巧】219.调用链SkyWalkingh

、获取Mapper实例

1. 获取Mapper默认实例

Default是一个静态延迟初始化的默认实例

IMapper mapper = PocoEmit.Mapper.Default;

2. 构造Mapper新实例

除了测试,不建议每次转化调用Create

Create的实例建议定义为静态字段或属性

或者注入IOC容器内重复使用

IMapper mapper = PocoEmit.Mapper.Create();

二、简单类型转化无需配置

什么样的类型转化对PocoEmit来说是简单的呢

1. 基础类型、枚举互转

基础类型、枚举互转无需配置

int intValue = PocoEmit.Mapper.Default.Convert("123");

long longValue = PocoEmit.Mapper.Default.Convert(123);

strting stringValue = PocoEmit.Mapper.Default.Convert(123);

public enum MyColor

{

None = 0,

Red = 1,

Green = 2,

Blue = 3,

}

ConsoleColor color = ConsoleColor.DarkBlue;

// Red

MyColor redColor = PocoEmit.Mapper.Default.Convert(ConsoleColor.Red);

string colorName = PocoEmit.Mapper.Default.Convert(ConsoleColor.Red);

// 1

long colorValue = PocoEmit.Mapper.Default.Convert(MyColor.Red);

/ None

MyColor noneColor = PocoEmit.Mapper.Default.Convert(ConsoleColor.DarkBlue);

2. 可空类型转化

可空类型转化无需配置

int intValue = PocoEmit.Mapper.Default.Convert("123");

long? longValue = PocoEmit.Mapper.Default.Convert(123);

strting stringValue = PocoEmit.Mapper.Default.Convert(123);

User user = PocoEmit.Mapper.Default.Convert(null);

3. 构造函数和属性互转

构造函数和属性互转无需配置

class MyId(int id)

{

public int Id { get; } = id;

}

class MyId2(int? id)

{

public int? Id { get; } = id;

}

3.1 构造函数转化

var myId = PocoEmit.Mapper.Default.Convert(1);

var myId2 = PocoEmit.Mapper.Default.Convert(2);

var myId3 = PocoEmit.Mapper.Default.Convert(3);

var myId4 = PocoEmit.Mapper.Default.Convert(4);

3.2 属性转化

var id = PocoEmit.Mapper.Default.Convert(new MyId(1));

var id2 = PocoEmit.Mapper.Default.Convert(new MyId2(2));

var id3 = PocoEmit.Mapper.Default.Convert(new MyId(3));

var id4 = PocoEmit.Mapper.Default.Convert(new MyId2(4));

4. 复合类型同名属性互转

复合类型同名属性互转无需配置

var dto = PocoEmit.Mapper.Default.Convert(new User { Id = 1, Name = "Jxj1" });

var user = PocoEmit.Mapper.Default.Convert(new UserDTO { Id = 2, Name = "Jxj2" });

var user3 = PocoEmit.Mapper.Default.Convert(new UserDTO { Id = "3", Name = "张三" });

三、一键开启集合类型转化配置

通过UseCollection扩展方法给PocoEmit.Mapper增加集合功能

扩展后PocoEmit.Mapper支持集合(含数组、列表及字典)的转化和复制

支持实体类型包含集合成员的转化和复制

1. 启用集合配置

1.2 开启全局集合配置

对所有Mapper启用集合

应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效

CollectionContainer.GlobalUseCollection();

1.1 对单个Mapper启用集合

PocoEmit.Mapper.UseCollection();

2.启用集合后集合互转无需配置

User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];

UserDTO[] result = PocoEmit.Mapper.Default.Convert(source);

IEnumerable source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];

UserDTO[] result = PocoEmit.Mapper.Default.Convert, UserDTO[]>(source);

User[] source = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }];

IEnumerable result = PocoEmit.Mapper.Default.Convert>(source);

Dictionary source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };

UserDTO[] result = PocoEmit.Mapper.Default.Convert, UserDTO[]>(source);

Dictionary source = new() { { 1, new User { Id = 1, Name = "Jxj" } } };

Dictionary result = PocoEmit.Mapper.Default.Convert, Dictionary>(source);

3.启用集合后集合成员互转无需配置

var source = new UserArray { Name = "VIP", Users = [new User { Id = 1, Name = "Jxj" }, new User { Id = 2, Name = "张三" }] };

UserDTOArray result = PocoEmit.Mapper.Default.Convert(source);

四、自定义配置

1. Mapper全局配置

全局配置对所有Mapper适用

全局配置应在使用所有Mapper实例之前配置,对已经完成初始化的Mapper实例无效

1.1 全局配置映射规则

PocoEmit.Mapper.GlobalConfigure(mapper => {

mapper.ConfigureMap()

.Source

.Ignore(nameof(User.Name));

});

1.2 全局配置内部缓存字典大小

配置适当大小可以减少内存占用和扩容

PocoEmit.Mapper.GlobalOptions(options => {

// 转化器数量

options.ConverterCapacity = 100;

});

2. 配置单个Mapper

PocoEmit.Mapper.Default.ConfigureMap()

.Source

.Ignore(nameof(User.Name));

3. 哪些需要配置

3.1 属性名前、后缀

AddPrefix设置前缀

AddSuffix设置后缀

ClearPrefix清空前缀

public class UserCustomDTO(string userName)

{

public int? UId { get; set; }

public string UName { get; } = userName;

}

3.1.1 源类型设置前缀

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Source

.AddPrefix("U");

var source = new UserCustomDTO("Jxj2") { UId = 222 };

var converter = mapper.GetConverter();

User result = converter.Convert(source);

3.1.2 目标类型设置前缀

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Dest

.AddPrefix("U");

var source = new User { Id = 222, Name = "Jxj2" };

var result = mapper.Convert(source);

3.1.3 默认前缀

ConfigureMap会默认把源类型名作为目标类型前缀

ConfigureMap会默认把目标类型名作为源类型前缀

如果默认前缀干扰到正常匹配,可以调用ClearPrefix清空前缀

public class AutoUserDTO

{

public string UserId { get; set; }

public string UserName { get; set; }

}

IMapper mapper = Mapper.Create();

mapper.ConfigureMap();

var source = new AutoUserDTO{ UserId = "222", UserName = "Jxj" };

var converter = mapper.GetConverter();

User result = converter.Convert(source);

3.2 属性一对一配置

3.2.1 通过Source配置

直接MapTo或ForMember

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Source

.MapTo(nameof(User.Id), nameof(UserCustomDTO.UId))

.MapTo(nameof(User.Name), nameof(UserCustomDTO.UName));

var source = new User { Id = 222, Name = "Jxj2" };

var converter = mapper.GetConverter();

UserCustomDTO result = converter.Convert(source);

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Source

.ForMember(nameof(User.Id)).MapTo(nameof(UserCustomDTO.UId))

.ForMember(nameof(User.Name)).MapTo(nameof(UserCustomDTO.UName));

var source = new User { Id = 222, Name = "Jxj2" };

var converter = mapper.GetConverter();

UserCustomDTO result = converter.Convert(source);

3.2.2 通过Dest配置

直接MapFrom或ForMember

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Dest

.MapFrom(nameof(User.Id), nameof(UserCustomDTO.UId))

.MapFrom(nameof(User.Name), nameof(UserCustomDTO.UName));

var source = new UserCustomDTO("Jxj2") { UId = 222 };

var converter = mapper.GetConverter();

User result = converter.Convert(source);

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Dest

.ForMember(nameof(User.Id)).MapFrom(nameof(UserCustomDTO.UId))

.ForMember(nameof(User.Name)).MapFrom(nameof(UserCustomDTO.UName));

var source = new UserCustomDTO("Jxj2") { UId = 222 };

var converter = mapper.GetConverter();

User result = converter.Convert(source);

3.3 忽略成员

3.3.1 被忽略的源类型成员不参与映射

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Source

.Ignore(nameof(User.Name));

var source = new User { Id = 111, Name = "Jxj" };

var converter = mapper.GetConverter();

// result.Name == null

UserDTO result = converter.Convert(source);

3.3.2 被忽略的目标类型成员不会被匹配

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.Dest

.Ignore(nameof(UserDTO.Name));

var source = new User { Id = 111, Name = "Jxj" };

var converter = mapper.GetConverter();

// result.Name == null

UserDTO result = converter.Convert(source);

3.4 指定转化函数

通过UseConvertFunc指定函数直接转化

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.UseConvertFunc(source => new User { Id= source.Id, Name = source.Name });

var source = new UserDTO { Id = 111, Name = "Jxj" };

var converter = mapper.GetConverter();

var result = converter.Convert(source);

3.5 指定构造函数

通过UseActivator指定构造函数

执行完构造函数还会尝试匹配与UseConvertFunc是不同的

IMapper mapper = Mapper.Create();

mapper.ConfigureMap()

.UseActivator(u => new UserCustomDTO(u.Name) { UId = u.Id })

.Source

.MapTo(nameof(User.Id), nameof(UserCustomDTO.UId));

var source = new User { Id = userId, Name = "Jxj2" };

var converter = mapper.GetConverter();

var result = converter.Convert(source);

3.6 指定默认值

3.6.1 指定固定默认值

IMapper mapper = Mapper.Create()

.UseDefault(Repository);

var dto = new UserDTO { Id = 1, Name = "Jxj" };

UserDomain user = mapper.Convert(dto);

class UserDomain(UserRepository repository, int id, string name)

{

private readonly UserRepository _repository = repository;

public UserRepository Repository

=> _repository;

public int Id { get; } = id;

public string Name { get; } = name;

// ...

}

static readonly UserRepository Repository = new();

class UserRepository

{

void Add(UserDomain user) { }

void Update(UserDomain entity) { }

void Remove(UserDomain entity) { }

}

注: 如果不指定UserRepository的默认值,以上转化会报异常

注: 以上例子示例给领域模型注入仓储

3.6.2 默认值指定工厂方法

IMapper mapper = Mapper.Create()

.UseDefault(() => MessageId.NewId());

var dto = new MessageDto { Message = "Hello UseDefault" };

MessageDomain message = mapper.Convert(dto);

class MessageDto

{

public string Message { get; set; }

}

class MessageDomain(MessageId id, string message)

{

public MessageId Id { get; } = id;

public string Message { get; } = message;

// ...

}

class MessageId(int id)

{

private static int seed = 1;

public int Id { get; } = id;

public static MessageId NewId()

=> new(seed++);

}

注: 以上例子示例给领域模型注入自增Id

注: 实际项目这里建议调用雪花Id

3.7 转化后补刀

使用UseCheckAction配置转化检查逻辑用来补刀

对于实在不方便配置映射规则的遗留属性进行补刀

static void ConvertAddressCity(Customer customer, CustomerDTO dto)

{

dto.AddressCity = customer.Address.City;

}

var mapper = PocoEmit.Mapper.Default;

mapper.ConfigureMap()

.UseCheckAction(ConvertAddressCity);

CustomerDTO result = mapper.Convert(source);

五、PocoEmit的“继承”和“多态”

1. PocoEmit的“继承”

通过全局配置实现类似继承的效果

前面已经介绍了PocoEmit的全局配置

2. PocoEmit的“多态”

对某些Mapper对象覆盖配置实现与其他Mapper不同的效果

可以用不同的serviceKey注入容器,使用的时候就可以做到无感

2.1 举个发布平台需要“多态”的例子

需要发布时间字段,平台内时间格式很好统一

如果需要接入第三方数据,特别是国外的数据,格式很可能不一样

牺牲性能用复杂逻辑去兼容也不是不可以

这里建议提供多个Mapper的方案,不同渠道用不同的Mapper,每个Mapper只有极少的配置不同

这就是PocoEmit“多态”的应用

2.2 再举个VIP的例子更明显

VIP客户提出各种格式化无关痛痒的问题

一般就写if特殊处理了

这类情况也适用PocoEmit“多态”

六、PocoEmit配合容器使用

1、容器注册转化器

1.1 默认注册

通过容器中默认的IMapper对象或Mapper.Global构造转化器

services.UseConverter();

1.2 指定IPoco对象注册

services.UseConverter(PocoEmit.Mapper.Global);

注: PocoEmit.Mapper.Global继承IPoco接口

1.3 隔离注册

指定IPoco和serviceKey注册

IPoco poco = specialMapper;

services.UseConverter(poco, "special");

1.4 通过IPocoConverter注入

通过构造函数参数、属性等方式注入

public sealed class Mapper(IPocoConverter converter)

: Mapper>

{

// ...

}

2、容器注册复制器

2.1 默认注册

通过容器中默认的IMapper对象或Mapper.Global构造复制器

services.UseCopier();

2.2 指定IMapper对象注册

services.UseCopier(PocoEmit.Mapper.Global);

注: PocoEmit.Mapper.Global继承IMapper接口

2.3 隔离注册

指定IPoco和serviceKey注册

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值