PocoEmit遥遥领先于AutoMapper之打通充血模型的任督二脉

news/2025/10/4 9:41:29/文章来源:https://www.cnblogs.com/xiangji/p/19125327

PocoEmit遥遥领先于AutoMapper之打通充血模型的任督二脉

一、充血模型和失血模型

1. 充血模型的优势

  • 充血模型更加OOP
  • 充血模型代码可读性更好

1.1 充血模型伪代码

var messageDto = controller.ReadDto();
var message = messageDto.ToEntity();
message.Save();

1.2 失血模型伪代码

var messageDto = controller.ReadDto();
var message = messageDto.ToEntity();
var messageService = controller.GetMessageService();
messageService.Save(message);

2. 充血模型爱你不容易

  • 大部分程序员都知道充血模型好,想实现却很难
  • 大部分业务逻辑都需要依赖外部服务
  • 充血模型需要用到外部服务,又不想依赖外部服务的具体实现
  • 很容易想到使用IOC的依赖注入来解决
  • 我们给DTO注入服务还行,因为IOC参与了controller过程
  • 当DTO发生转化时,新增的服务IOC还是有点力不从心
  • 这个任督二脉PocoEmit可以帮你打通

二、首先来个Case演示一下

  • Dto转化为实体
  • 但是实体有更多逻辑依赖外部服务,这些外部服务Dto不见得提供的了
  • 这就需要注入
  • PocoEmit支持构造函数参数注入和属性注入
  • IMapper对象是默认支持注入的服务

1. Entity比Dto多出来的Mapper可以注入

class MessageDto
{public string Message { get; set; }
}
class MessageEntity
{public IMapper Mapper { get; set; }public string Message { get; set; }
}

2. 转化并注入的代码

var mapper = Mapper.Create();
var dto = new MessageDto { Message = "Hello UseMapper" };
MessageEntity message = mapper.Convert<MessageDto, MessageEntity>(dto);
Assert.NotNull(message.Mapper);

三、再演示注入自定义的服务

1. UserDomain比Dto多出来的Repository可以注入

public record UserDTO
{public int Id { get; set; }public string Name { get; set; }
}
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;// ...
}
class UserRepository
{void Add(UserDomain user) { }void Update(UserDomain entity) { }void Remove(UserDomain entity) { }public static readonly UserRepository Instance = new();
}

2. 注册、转化并注入的代码

  • 通过UseDefault可以注入服务
IMapper mapper = Mapper.Create().UseDefault(UserRepository.Instance);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain>(dto);
Assert.NotNull(user.Repository);

四、注入IOC容器的Case

  • 注入IOC容器需要安装nuget包PocoEmit.ServiceProvider

1. 包含IOC容器的实体

class UserWithServiceProvider
{public int Id { get; set; }public string Name { get; set; }public IServiceProvider ServiceProvider { get; set; }
}

2. 注册、转化并注入的代码

  • UseSingleton是把容器作为唯一容器注入
  • UseScope是使用当前Scope的子容器
  • UseContext是在Mvc下,使用当前HttpContext的RequestServices子容器
var services = new ServiceCollection();
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseSingleton(serviceProvider);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserWithServiceProvider user = mapper.Convert<UserDTO, UserWithServiceProvider>(dto);
Assert.NotNull(user.ServiceProvider);

五、当然还可以注入容器内的服务

1. UserDomain多出来的UserDomain需要注入

  • 这次我们用IOC来管理UserRepository
  • 这样才能更好的利用依赖注入
  • UserRepository可能还会依赖其他的
  • 手动维护对象可能会很麻烦,IOC容器擅长维护这些复杂关系
    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;// ...}class UserRepository{void Add(UserDomain user) { }void Update(UserDomain entity) { }void Remove(UserDomain entity) { }}

2. 注册、转化并注入的代码

  • 通过UseScope注入IOC容器
  • 通过UseDefault告知这个类型从IOC容器中注入
var services = new ServiceCollection().AddScoped<UserRepository>();
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseScope(serviceProvider).UseDefault<UserRepository>();
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain>(dto);
Assert.NotNull(user.Repository);

六、支持IOC容器的特性

  • 支持FromKeyedServices
  • 支持FromServices

1. FromKeyedServices标记注入点和服务键

class UserDomain1([FromKeyedServices("User1")]UserRepository repository, int id, string name): UserDomain(repository, id, name)
{
}
class UserDomain2([FromKeyedServices("User2")] UserRepository repository, int id, string name): UserDomain(repository, id, name)
{
}
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;// ...
}
class UserRepository(string tableName)
{private readonly string _tableName = tableName;public string TableName => _tableName;void Add(UserDomain user) { }void Update(UserDomain entity) { }void Remove(UserDomain entity) { }
}

2. 注册、转化并注入的代码

  • 由于识别出FromKeyedServices,就不需要UseDefault
  • 这样简洁由优雅
string table1 = "User1";
string table2 = "User2";
var services = new ServiceCollection().AddKeyedScoped(table1, (_, _) => new UserRepository(table1)).AddKeyedScoped(table2, (_, _) => new UserRepository(table2));
var serviceProvider = services.BuildServiceProvider();
var mapper = Mapper.Create();
mapper.UseScope(serviceProvider);
var dto = new UserDTO { Id = 1, Name = "Jxj" };
UserDomain user = mapper.Convert<UserDTO, UserDomain1>(dto);
Assert.NotNull(user.Repository);
UserDomain user2 = mapper.Convert<UserDTO, UserDomain2>(dto);
Assert.NotNull(user2.Repository);

七、竞品类似的功能

1. AutoMapper不支持

  • AutoMapper的NullSubstitute用来指定源属性为null时的默认值
  • 用AutoMapper实现类似功能需要复杂的自定义IValueResolver来实现
  • PocoEmit在源无法匹配或源字段为null都可能触发依赖注入

2. EF有类似功能

  • 不过貌似只支持EF内部某些服务
  • 请参阅 EF Core实体类的依赖注入

八、总结

1. OOM映射需要依赖注入

  • DTO、实体、领域模型如果有业务逻辑就需要依赖外部服务
  • 支持按类型注入,也支持按指定的参数或属性注入
  • 支持FromKeyedServices和FromServices
  • 需要外部服务就需要依赖注入

2. IOC容器使用需要注意

  • 简单作业单容器,使用UseSingleton即可
  • 多线程需要使用UseScope
  • Mvc(含WebApi)逻辑处理使用UseContext
  • UseContext需要引用nuget包PocoEmit.Mvc
  • 如果是Mvc异步处理或Quartz类似作业不要用UseContext
  • 就怕异步中获取到了HttpContext,但执行中途被释放了,后面就可能异常了

另外源码托管地址: https://github.com/donetsoftwork/MyEmit ,欢迎大家直接查看源码。
gitee同步更新:https://gitee.com/donetsoftwork/MyEmit

如果大家喜欢请动动您发财的小手手帮忙点一下Star,谢谢!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/926981.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

hslenc.c 代码提纲挈领分析 - 指南

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

Solar9月赛wp - 场

水一篇Solar9月赛 Wireshark 哥斯拉流量,webshell的密码一直变,neta可以梭到一个zip,里面是key.txt,直接追踪到最后一个返回包,拿key.txt进行爆破解密拿到flagflag{ccebdb78-4b5c-4252-b20a-0039913c5c94} HAPPY …

做电商网站商标wordpress导航栏的文件在哪里

http://www.cnblogs.com/ccblogs/p/5260949.html 一. 效果图 二. 功能介绍 支持滚动和点击选择年月。&#xff08;目前只支持设置年月的最大最小值&#xff0c;不支持整体的最大最小值&#xff09; 三. 代码 1. 在你的html中添加如下代码&#xff1a; 直接加载<body>里面…

昆明网站建设教学视频wordpress判断是否是子分类

1.遇到的问题 服务网关 | RuoYi 最近调试若依的微服务版本需要用到Sentinel这个组件&#xff0c;若依内部继承了这个组件连上即用。 Sentinel是阿里巴巴开源的限流器熔断器&#xff0c;并且带有可视化操作界面。 在日常开发中&#xff0c;限流功能时常被使用&#xff0c;用…

wordpress 网站维护wordpress的设置网址导航

概率基础——极大似然估计 引言 极大似然估计&#xff08;Maximum Likelihood Estimation&#xff0c;简称MLE&#xff09;是统计学中最常用的参数估计方法之一&#xff0c;它通过最大化样本的似然函数来估计参数值&#xff0c;以使得样本出现的概率最大化。极大似然估计在各…

网站建设开发费用预算泉州做网站优化的公司

美女姜培琳&#xff1a;传授独家心经 不同职业的面试着装技巧。 一般来说&#xff0c;职场中精英女性的装扮&#xff0c;首要应讲求端庄、稳重。人们对服饰过于花哨怪异者的工作能力、工作作风、敬业精神、生活态度等&#xff0c;都会持怀疑的态度。 其实&#x…

成都营销型网站建设价格网站构建工具

Python2.7.13 安装 说明 以下所有操作都基于centos6.9 1. Issue zlib zlib-devel是安装setuptools依赖的模块&#xff0c;需要在安装python之前先安装这两个模块 2. Install Base #基础依赖 yum -y install gcc gcc-c zlib zlib-devel openssl-devel#删除当前mysql版本 yum rem…

坂田做网站多少钱wordpress怎么建加盟网

动态规划、DFS 和回溯算法&#xff1a;二叉树问题的三种视角 在计算机科学中&#xff0c;算法是解决问题的核心。特别是对于复杂的问题&#xff0c;不同的算法可以提供不同的解决方案。在本篇博客中&#xff0c;我们将探讨三种算法&#xff1a;动态规划、深度优先搜索&#xf…

Elastic Search 安装部署最全教程(Docker)

@@docker es 安装https://blog.csdn.net/Grey_fantasy/article/details/131561847   https://blog.csdn.net/qq_33034733/article/details/130857381     https://blog.csdn.net/yueyue763184/article/details/…

大型网站开发pdf英文网站建设 江门

几个删除重复记录的SQL语句在大的数据库应用中&#xff0c;经常因为各种原因遇到重复的记录&#xff0c;造成数据的冗余和维护上的不便。1.用rowid方法2.用group by方法3.用distinct方法 1。用rowid方法据据oracle带的rowid属性&#xff0c;进行判断&#xff0c;是否存在重复,语…

详细介绍:C#多线程全家桶:从Thread到async/await

详细介绍:C#多线程全家桶:从Thread到async/await2025-10-04 09:18 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; displ…

十堰的网站建设威海建设集团招聘信息网站

要使用Django开发一个抽奖活动的后台&#xff0c;需要进行以下步骤&#xff1a; 安装Django&#xff1a;首先确保已经安装了Python和pip&#xff0c;然后使用pip安装Django库&#xff1a; pip install django 创建Django项目&#xff1a;在命令行中执行以下命令创建一个新的Dja…

详细介绍:图像分割:PyTorch从零开始实现SegFormer语义分割

详细介绍:图像分割:PyTorch从零开始实现SegFormer语义分割pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…

用html5做的静态网站网站wordpress修改首页名称

一、常用的常用的生命周期钩子&#xff1a; mounted: 发送 ajax 请求、启动定时器、绑定自定义事件、订阅消息等【初始化操作】 mounted() {console.log(vm 实例被挂载之后&#xff1a;mounted);this.timer setInterval(() > {...} }beforeDestroy: 清除定时器、解绑自定…

网络营销方案seo入门到精通

考察点 大数&#xff0c;快排知识点 题目 分析 本题目给一个整型数组&#xff0c;要求他能排出来的最小的数字。这道题目我们大可以通过排列的方式枚举出所有的数字然后求一个最小的&#xff0c;只不过这种方式时间复杂度非常高。接下来我们通过举例的方式观察我们的思维和数…

深入解析:Playwright同步、异步、并行、串行执行效率比较

深入解析:Playwright同步、异步、并行、串行执行效率比较pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consola…

怎么用织梦做自己的网站苏州app开发

1 混合出版物 允许传统稿件提交或作者支付的开放获取&#xff08;OA&#xff09;稿件 2 长度 所有页面限制包括参考文献和作者简历。对于常规论文&#xff0c;接受稿件的最终版面设计完成后超出这些限制的页面&#xff0c;将收取强制性超长页面费用&#xff08;MOPC&#xf…

详细介绍:异步日志系统

详细介绍:异步日志系统2025-10-04 09:03 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

Linux基础开发工具 --- vim - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

2025十一集训——Day2模拟赛

赛时: 四个题都很可做的样子, T3好像是原??? OK T1 简单二分,切了。 调 lowerbound 那里 +-1 的细节,8:50 成功过掉大样例。 开 T2。 9:00,想到差分。 诶T2咋是原,就一黄f**k.本文来自博客园,作者:zhangxia…