应用服务实现逻辑
本文档引用的文件
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs/lmes-template/src/CMS.Plugin.MyPluginName.Application.Contracts/Services/IMyEntityNameAppService.cs/lmes-template/src/CMS.Plugin.MyPluginName.Domain/MyEntityNames/IMyEntityNameRepository.cs/lmes-template/src/CMS.Plugin.MyPluginName.Domain/MyEntityNames/MyEntityName.cs/lmes-template/src/CMS.Plugin.MyPluginName.Application/MapperProfiles/MyEntityNameAutoMapperProfile.cs
目录
简介
MyEntityNameAppService 是 CMS 插件中负责处理 MyEntityName 实体业务逻辑的核心应用服务。该服务遵循领域驱动设计(DDD)原则,通过依赖注入协调领域实体、仓储接口和对象映射器,实现对实体的增删改查及批量操作。本文说明其具体实现机制,帮助开发者理解服务层的职责划分与扩展方式。
Section sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
依赖注入与服务协调
MyEntityNameAppService 类通过构造函数注入 IMyEntityNameRepository 和继承自基类的 ObjectMapper,实现了对领域层服务的解耦访问。
- IMyEntityNameRepository:定义了对
MyEntityName实体的数据访问契约,封装了数据库操作细节。 - IObjectMapper:由基类
CMSPluginAppService提供,用于在领域实体MyEntityName与数据传输对象 DTO 之间进行自动映射。 - GuidGenerator:用于生成唯一标识符,确保新实体 ID 的全局唯一性。
这种设计模式将业务编排逻辑集中于应用服务层,同时保持对基础设施和领域模型的低耦合。
Diagram sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs/lmes-template/src/CMS.Plugin.MyPluginName.Domain/MyEntityNames/IMyEntityNameRepository.cs/lmes-template/src/CMS.Plugin.MyPluginName.Domain/MyEntityNames/MyEntityName.cs
核心方法执行流程
CreateAsync 方法流程
CreateAsync 方法用于创建新的 MyEntityName 实体,执行流程如下:
- 调用
CheckCreateOrUpdateDtoAsync对输入 DTO 进行参数验证。 - 检查名称是否已存在,若存在则抛出用户友好异常。
- 获取当前最大排序值,作为新实体的默认排序。
- 创建新的
MyEntityName实体实例,并映射扩展属性。 - 调用仓储的
InsertAsync方法持久化实体。 - 若指定了排序且与默认值不同,则调用
AdjustSortAsync调整排序。 - 返回映射后的 DTO。
Diagram sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
UpdateAsync 方法流程
UpdateAsync 方法用于更新现有实体:
- 执行 DTO 参数验证。
- 从仓储获取现有实体。
- 检查新名称是否与其他实体冲突(排除自身)。
- 更新实体的并发戳(ConcurrencyStamp)和扩展属性。
- 调用实体的
Update方法设置业务字段。 - 持久化更新后的实体。
- 返回 DTO。
Diagram sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
DeleteAsync 与 GetListAsync 方法
- DeleteAsync:直接委托给仓储的
DeleteAsync方法,实现逻辑删除或物理删除。 - GetListAsync:接收分页和过滤参数,构建查询规范(Specification),调用仓储获取数据总数和列表,并通过
ObjectMapper映射为 DTO 列表返回。
Section sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
批量操作实现策略
CloneAsync 批量克隆
CloneAsync 方法支持批量克隆多个实体:
- 遍历输入的 ID 列表,逐个获取原实体。
- 为克隆体生成新名称(添加“副本”标签),并确保名称唯一。
- 调用实体的
Clone方法创建副本,并插入数据库。 - 收集所有成功克隆的实体并返回其 DTO 列表。
该方法在循环内执行数据库插入,未使用批量操作,可能影响性能。
DeleteManyAsync 批量删除
DeleteManyAsync 通过遍历 ID 列表并逐个调用 DeleteAsync 实现。此实现方式简单但效率较低,建议在仓储层实现真正的批量删除以提升性能。
ImportAsync 与 ExportAsync
- ImportAsync:支持从 Excel 导入数据。先进行行级校验(如名称重复),然后分批执行创建或更新操作,具备良好的错误反馈机制。
- ExportAsync:根据查询条件导出数据,返回字典格式的 Sheet 数据和文件名,便于前端生成 Excel 文件。
Diagram sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
错误处理与验证机制
服务层实现了多层次的错误处理与验证:
- 参数验证:使用
Check.NotNull、Check.NotNullOrWhiteSpace等方法进行前置校验。 - 业务规则验证:如名称唯一性检查,通过
NameExistAsync方法实现。 - 用户友好异常:使用
UserFriendlyException向前端传递可读性高的错误信息。 - 异常包装:在
ImportAsync中捕获底层异常并包装为带行号信息的用户友好异常。
Section sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
事务边界与性能考量
- 事务边界:当前实现依赖于仓储层或数据库上下文的默认事务行为。建议在必要时显式使用
ICurrentUnitOfWork控制事务。 - 性能优化:
GetListAsync使用分页和过滤,避免全表扫描。AdjustSortAsync一次性加载所有实体进行排序调整,减少数据库交互次数。- 批量操作(如
DeleteManyAsync)存在性能瓶颈,建议在仓储层优化为单次数据库调用。
Section sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs
扩展性与职责边界
MyEntityNameAppService 清晰地划分了应用层的职责:
- 职责:协调领域对象、执行应用级业务逻辑、处理 DTO 转换、管理事务边界。
- 非职责:不包含复杂领域规则(由实体方法处理),不直接访问数据库(通过仓储)。
- 扩展方式:可通过继承或添加新方法实现定制逻辑,DTO 和仓储接口支持灵活扩展。
Section sources
/lmes-template/src/CMS.Plugin.MyPluginName.Application/Implements/MyEntityNameAppService.cs