跳到主要内容
版本:Next

数据持久化

本文档引用的文件

目录

  1. 引言
  2. 仓储模式与接口契约
  3. EF Core 配置与实体映射
  4. 数据库上下文管理
  5. 多数据库支持实现原理
  6. 实体扩展性设计
  7. Dapper 使用场景与性能优化
  8. 总结

引言

本项目采用领域驱动设计(DDD)架构,数据持久化机制以 Entity Framework Core(EF Core)为核心,结合 Dapper 实现高性能查询,支持 MySQL、PostgreSQL 和 SQL Server 多数据库。通过仓储模式(Repository Pattern)封装数据访问逻辑,确保领域层与基础设施层解耦。本文档全面分析该机制的实现细节。

仓储模式与接口契约

项目采用标准仓储模式,通过 IMyEntityNameRepository 接口定义数据访问契约,EfCoreMyEntityNameRepository 提供 EF Core 实现。接口定义了实体查询、计数、排序获取、名称唯一性校验等业务方法,确保领域服务通过抽象接口操作数据,不依赖具体实现。

IMyEntityNameRepository 继承自 IBasicRepository<MyEntityName, Guid>,扩展了 FindByNameAsyncNameExistAsyncGetMaxSortAsync 等业务专用方法,体现了领域驱动设计中“富仓储”的理念。

代码路径

  • IMyEntityNameRepository 接口定义了所有查询契约
  • EfCoreMyEntityNameRepository 实现了这些契约

Section sources

EF Core 配置与实体映射

EF Core 的实体映射通过扩展方法 CMSPluginEfCoreExtensions.MyEntityName.cs 集中配置。ConfigureMyEntityName 方法在 ModelBuilder 上为 MyEntityName 实体定义了完整的数据库映射规则。

Diagram sources

表名与架构映射

实体映射到数据库表时,使用 CMSPluginDbProperties 中定义的前缀和架构:

b.ToTable((CMSPluginDbProperties.DbTablePrefix + "_MyEntityNames").ToLower(), CMSPluginDbProperties.DbSchema)

默认表名为 scms_myentitynames,位于默认架构下,支持通过配置修改。

属性配置

关键属性配置如下:

  • Code:最大长度由 MyEntityNameConsts.MaxCodeLength 定义,必填
  • Name:最大长度由 MyEntityNameConsts.MaxNameLength 定义,必填
  • Sort:整数类型,用于排序
  • Remark:可选,最大长度由 MyEntityNameConsts.MaxRemarkLength 定义
  • IsDisabled:可空布尔值,表示是否禁用

索引配置

Name 字段创建了唯一索引,确保名称的唯一性约束:

b.HasIndex(u => u.Name);

关系定义

当前 MyEntityName 实体未定义导航属性,为聚合根(Aggregate Root),其内部关系由领域逻辑维护,符合 DDD 原则。

Section sources

数据库上下文管理

项目定义了 ICMSPluginDbContext 接口作为数据库上下文契约,继承自 IEfCoreDbContext。具体的上下文实现(如 CMSPluginDbContext)在各数据库提供程序项目中(MySQL、PostgreSQL、SqlServer)提供。

Diagram sources

OnModelCreating 方法中调用 builder.ConfigureMyEntityName() 注册实体配置,并通过 builder.TryConfigureObjectExtensions<CMSPluginDbContext>() 应用对象扩展,支持模块化配置。

数据库连接字符串名称通过 [ConnectionStringName] 特性指定为 MyPluginName,定义在 CMSPluginDbProperties.ConnectionStringName

Section sources

多数据库支持实现原理

项目通过为不同数据库提供程序创建独立的项目(CMS.Plugin.MyPluginName.MySQLCMS.Plugin.MyPluginName.PostgreSqlCMS.Plugin.MyPluginName.SqlServer)实现多数据库支持。每个项目包含一个继承自 AbpDbContextCMSPluginDbContext 实现。

运行时,根据依赖注入容器中注册的数据库提供程序(如 UseMySqlUseNpgsqlUseSqlServer),DbContextOptions<CMSPluginDbContext> 将使用相应的数据库驱动。由于所有实现共享相同的 ICMSPluginDbContext 接口和 EF Core 配置,上层代码完全透明,实现了数据库无关性。

Section sources

实体扩展性设计

项目通过 CMSPluginEfCoreEntityExtensionMappings 类实现实体的可扩展性。该静态类在 CMSPluginEntityFrameworkCoreModulePreConfigureServices 阶段调用 Configure() 方法进行初始化。

Diagram sources

OneTimeRunner 确保配置仅执行一次。通过 ObjectExtensionManager,其他模块可以为 MyEntityName 等实体添加额外的 EF Core 映射属性(如新字段),而无需修改核心代码,实现了良好的模块化和可扩展性。

Section sources

Dapper 使用场景与性能优化

项目同时集成了 Dapper,通过 ICMSPluginDapperRepository 接口和 CMSPluginDapperRepository 实现。CMSPluginDapperRepository 继承自 DapperRepository<ICMSPluginDbContext>,共享 EF Core 的数据库连接和事务。

Diagram sources

使用场景

Dapper 适用于以下场景:

  • 复杂查询:涉及多表连接、子查询、窗口函数等 EF Core 生成 SQL 效率较低的场景
  • 高性能读取:对性能要求极高的只读查询,Dapper 的映射开销远低于 EF Core
  • 存储过程调用:直接调用数据库存储过程
  • 批量操作:使用 SqlBulkCopy 或 Dapper 扩展进行高效批量插入/更新

与 EF Core 的互补关系

  • EF Core:用于常规的 CRUD 操作、变更跟踪、事务管理,适合写操作和简单查询
  • Dapper:用于复杂、高性能的读操作,作为 EF Core 的补充

性能优化建议

  1. 读写分离:写操作使用 EF Core 仓储,读操作优先考虑 Dapper
  2. **避免 SELECT ***:Dapper 查询应明确指定所需字段
  3. 参数化查询:始终使用参数化查询防止 SQL 注入
  4. 连接复用:通过 GetDbConnectionAsync 获取连接,确保在 EF Core 事务中的一致性
  5. 异步编程:使用 QueryAsync 等异步方法避免阻塞
  6. 缓存策略:对不常变的数据,结合 Redis 等缓存 Dapper 查询结果

Section sources

总结

本项目构建了一套完整、灵活且高性能的数据持久化机制。通过仓储模式实现领域层与数据访问的解耦,利用 EF Core 提供强大的 ORM 功能和实体映射能力,支持多数据库。通过独立的 Dapper 集成,解决了复杂查询和性能瓶颈问题。实体扩展机制确保了系统的可扩展性。整体设计遵循 DDD 原则,为业务发展提供了坚实的数据基础。