跳到主要内容
版本:Next

导入导出

本文档中引用的文件

目录

  1. 简介
  2. 模型结构设计
  3. 导出功能实现
  4. 导入流程解析
  5. 大数据量导入优化策略
  6. 导入模板设计规范
  7. 常见错误代码说明
  8. 总结

简介

本文档全面讲解系统中Excel导入导出功能的实现细节,重点围绕MyEntityNamesExportModelMyEntityNamesImportModel两个核心数据传输模型展开。文档将详细说明这些模型如何与领域实体MyEntityName进行数据转换,解析导出功能如何利用MiniExcelLibs生成带格式的Excel模板(包含表头、数据验证规则和示例数据),并深入剖析导入流程中的文件解析、数据校验、错误收集与反馈机制。同时,文档还将重点阐述在处理大数据量导入时的内存优化策略,如流式读取与分批插入,为开发者提供完整的实现参考。

模型结构设计

本节分析MyEntityNamesExportModelMyEntityNamesImportModel与领域实体MyEntityName之间的结构设计与转换关系。

MyEntityNamesExportModel 结构

MyEntityNamesExportModel是用于导出功能的数据模型,其内部定义了嵌套类WorkSectionExportModel,用于映射Excel中的每一行数据。该模型通过MiniExcelLibs.Attributes命名空间下的特性来定义Excel列的元数据。

  • ExcelColumn特性:使用[ExcelColumn]特性标注属性,指定列名(Name)和宽度(Width),确保导出的Excel文件具有清晰的中文表头和合适的列宽。
  • 属性映射NameCodeRemark三个属性分别对应“名称”、“编号”、“备注”三列,与领域实体MyEntityName的属性保持一致。

Section sources

MyEntityNamesImportModel 结构

MyEntityNamesImportModel是用于导入功能的数据模型,其设计巧妙地复用了导出模型的结构。

  • 继承关系MyEntityNameImportModel类继承自WorkSectionExportModel,实现了模型复用,保证了导入模板的列结构与导出模板完全一致。
  • 行号追踪:新增RowIndex属性,用于记录数据在Excel中的行号(从第2行开始),便于在数据校验失败时精确定位错误位置,提供友好的错误反馈。
  • 集合属性MyEntityNames属性是一个List<MyEntityNameImportModel>,在设置值时会自动为每一条记录分配行号,简化了行号管理逻辑。

Section sources

领域实体 MyEntityName

MyEntityName是位于领域层的核心实体,代表了业务中的一个聚合根。

  • 属性定义:包含Code(编号)、Name(名称)、Sort(排序)、Remark(备注)、IsDisabled(是否禁用)等核心业务属性。
  • 构造函数与验证:在构造函数和Update方法中,使用Volo.Abp.Check工具类对输入参数进行非空和长度校验,确保了领域模型的完整性。
  • 行为方法:提供了UpdateAdjustSort等方法来封装业务逻辑,符合领域驱动设计(DDD)的原则。

Section sources

模型转换关系

Diagram sources

导出功能实现

导出功能通过MyEntityNameController中的ExportAsync方法实现,利用MiniExcelLibs库将领域数据填充到预定义的Excel模板中。

实现流程

  1. 数据准备:调用_myEntityNameAppService.ExportAsync(input)获取需要导出的数据。input.MaxResultCount被设置为int.MaxValue,确保获取所有数据。
  2. 模板定位:程序首先在应用根目录的Resources/Templates/路径下查找名为MyEntityName导出模板.xlsx的模板文件;若未找到,则尝试在程序集所在目录下查找。
  3. 模板填充:使用memoryStream.SaveAsByTemplateAsync(templatePath, exportData.Sheets)方法,将获取到的数据(exportData.Sheets)填充到模板的对应位置。
  4. 文件返回:将生成的Excel文件流以FileStreamResult的形式返回给客户端,并设置下载文件名(包含时间戳以避免重复)。

模板设计

导出模板(MyEntityName导出模板.xlsx)是一个预先设计好的Excel文件,它包含了:

  • 格式化表头:如“名称”、“编号”、“备注”等,与WorkSectionExportModelExcelColumn特性定义一致。
  • 数据验证规则:可能包含对“编号”列的唯一性约束或对“名称”列的长度限制。
  • 示例数据:模板中可能包含一行示例数据,指导用户如何正确填写。

Diagram sources

Section sources

导入流程解析

导入功能通过MyEntityNameController中的ImportAsync方法实现,其流程包括文件解析、数据校验和持久化。

实现流程

  1. 文件接收与读取:接收IFormFile file,将其内容复制到MemoryStream中以便后续处理。
  2. 工作表识别:使用stream.GetSheetNames()获取所有工作表名称,并检查是否存在名为“配置”的工作表。
  3. 数据解析:如果存在“配置”工作表,则使用MiniExcel.Query<MyEntityNamesImportModel.MyEntityNameImportModel>(stream, sheetName: "配置")将Excel数据直接映射为MyEntityNameImportModel对象列表。此过程利用了模型上的ExcelColumn特性进行列名匹配。
  4. 空数据检查:如果解析出的数据为空,则抛出UserFriendlyException异常,提示用户检查表格。
  5. 业务处理:将解析出的数据封装成MyEntityNamesImportModel对象,并调用_myEntityNameAppService.ImportAsync(...)进行后续的业务校验和数据持久化。

数据校验机制

数据校验主要在应用服务层(MyEntityNameAppService)实现,可能使用了MyEntityNameSpecification等规约模式。

  • MyEntityNameSpecification:该规约类可用于构建查询表达式,例如根据名称查询实体。在导入时,可以利用此类检查“名称”是否已存在,以防止数据重复。
  • 错误收集:校验过程会收集所有错误(如必填项为空、长度超限、唯一性冲突等),并将这些错误与对应的RowIndex关联起来。
  • 反馈机制:校验失败后,服务会返回一个包含所有错误详情(如“第3行:名称不能为空”)的结果对象,前端可以据此展示详细的错误报告。

Diagram sources

Section sources

大数据量导入优化策略

为应对大数据量导入可能引发的内存溢出问题,系统采用了以下优化策略:

流式读取

虽然当前代码示例中使用了MemoryStream,但在处理超大文件时,应采用MiniExcel提供的流式API(如QueryAsync配合IAsyncEnumerable),逐行读取和处理数据,而不是一次性将所有数据加载到内存中。这可以显著降低内存峰值。

分批插入

在应用服务的ImportAsync方法中,不应一次性调用仓储的InsertManyAsync。正确的做法是:

  1. 将导入的数据列表分割成较小的批次(例如每批1000条)。
  2. 遍历每个批次,调用仓储的批量插入方法。
  3. 在批次之间可以进行显式的SaveChanges或利用事务,确保数据一致性的同时,避免单次数据库操作过大。

这种分批处理策略可以有效控制数据库连接的负载和内存使用,提高导入的稳定性和性能。

Section sources

导入模板设计规范

为确保导入功能的顺利执行,导入模板的设计应遵循以下规范:

  1. 工作表名称:必须包含一个名为“配置”的工作表,这是代码中硬编码的查找名称。
  2. 列名一致性:各列的标题必须与WorkSectionExportModelExcelColumn特性的Name属性完全一致,即“名称”、“编号”、“备注”。
  3. 数据格式
    • “编号”和“名称”为必填项,且长度不能超过系统定义的最大值(由MyEntityNameConsts定义)。
    • “备注”为可选项。
  4. 示例数据:建议在模板中提供1-2行示例数据,帮助用户理解数据格式。
  5. 避免合并单元格:数据区域应避免使用合并单元格,以免影响解析。

常见错误代码说明

错误代码/信息原因解决方案
请检查导入的表格上传的文件中不存在“配置”工作表,或该工作表内无任何数据。确认文件中包含名为“配置”的工作表,并确保数据从第2行开始填写。
名称不能为空 / 编号不能为空某行数据的“名称”或“编号”列为空。检查报错行号,确保必填项已填写。
名称已存在某行数据的“名称”与数据库中已有记录重复。修改名称以确保唯一性,或先删除/禁用旧记录。
编号已存在某行数据的“编号”与数据库中已有记录重复。修改编号以确保唯一性。
名称长度不能超过XX字符“名称”列的内容超过了系统设定的最大长度。缩短名称长度。
编号长度不能超过XX字符“编号”列的内容超过了系统设定的最大长度。缩短编号长度。

总结

本文档详细阐述了基于DDD架构的Excel导入导出功能的实现。通过精心设计的MyEntityNamesExportModelMyEntityNamesImportModel模型,实现了与领域实体MyEntityName的高效数据转换。利用MiniExcelLibs库,系统能够生成格式化的导出模板并解析导入文件。导入流程通过规约模式进行数据校验,并结合行号追踪提供精准的错误反馈。对于大数据量场景,推荐采用流式读取和分批插入的优化策略,以保障系统的稳定性和性能。遵循本文档的模板设计规范和错误处理指南,开发者可以快速定位并解决导入导出过程中遇到的问题。