跳到主要内容
版本: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>,扩展了 FindByNameAsync、NameExistAsync、GetMaxSortAsync 等业务专用方法,体现了领域驱动设计中“富仓储”的理念。

代码路径

  • 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.MySQL、CMS.Plugin.MyPluginName.PostgreSql、CMS.Plugin.MyPluginName.SqlServer)实现多数据库支持。每个项目包含一个继承自 AbpDbContext 的 CMSPluginDbContext 实现。

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

Section sources

实体扩展性设计​

项目通过 CMSPluginEfCoreEntityExtensionMappings 类实现实体的可扩展性。该静态类在 CMSPluginEntityFrameworkCoreModule 的 PreConfigureServices 阶段调用 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 原则,为业务发展提供了坚实的数据基础。