Clean Architecture中通用实体的数据库适配实现方案问询
Clean Architecture下多数据库实体适配的正确方案
核心问题分析
你当前的矛盾在于:数据库特定的IMongoEntity接口放在Infrastructure层,但Domain实体需要实现它才能被MongoRepository调用,导致Domain层反向依赖外层的Infrastructure层,直接违反了Clean Architecture依赖向内的核心原则(内层Domain不应依赖外层基础设施)。
正确实现方式
1. 重构Domain层的核心实体接口
在Domain层定义完全脱离数据库依赖的通用实体标识接口,让所有Domain实体仅实现这个纯业务导向的接口:
// Domain层 public interface IEntity<out TId> { TId Id { get; } } // 示例Domain实体(仅包含业务属性) public class User : IEntity<Guid> { public Guid Id { get; init; } public string Username { get; set; } // 其他业务属性... }
这里的泛型TId支持不同数据库的ID类型(SQL用int/long、Mongo用ObjectId/Guid、键值库用string等),彻底实现业务与数据库解耦。
2. 移除数据库特定的实体接口(IMongoEntity)
不需要让Domain实体继承任何数据库相关的接口,所有MongoDB的映射规则都放在Infrastructure层,通过类映射配置完成实体到Mongo文档的转换:
// Infrastructure层 - MongoDB模块 public static class MongoDbMappingConfigurator { public static void RegisterMappings() { // 为User实体配置Mongo序列化规则 BsonClassMap.RegisterClassMap<User>(map => { map.AutoMap(); // 配置Id字段的Mongo序列化逻辑 map.MapIdProperty(u => u.Id) .SetIdGenerator(StringObjectIdGenerator.Instance) // 自动生成字符串格式的ObjectId .SetSerializer(new GuidSerializer(BsonType.String)); // 将Guid序列化为Mongo字符串类型 }); // 其他Domain实体的映射配置... } }
在应用启动阶段(比如Program.cs)调用该配置方法,MongoDB驱动会自动按照规则处理实体序列化/反序列化。
3. 调整MongoRepository的泛型约束
修改MongoRepository,让它依赖Domain层的IEntity<TId>,而非数据库特定接口:
// Infrastructure层 public class MongoRepository<TEntity, TId> : ICrudRepository<TEntity, TId> where TEntity : class, IEntity<TId> { private readonly IMongoCollection<TEntity> _collection; public MongoRepository(IMongoCollection<TEntity> collection) { _collection = collection; } public void InsertOne(TEntity entity) => _collection.InsertOne(entity); public async Task InsertOneAsync(TEntity entity) => await _collection.InsertOneAsync(entity); // 直接使用Domain层的TId类型实现DeleteById public void DeleteById(TId id) { _collection.FindOneAndDelete(Builders<TEntity>.Filter.Eq(e => e.Id, id)); } public async Task DeleteByIdAsync(TId id) { await _collection.FindOneAndDeleteAsync(Builders<TEntity>.Filter.Eq(e => e.Id, id)); } // 其他CRUD方法同理调整... }
4. 多数据库扩展逻辑
如果需要支持SQL、键值库等其他数据库,仅需在Infrastructure层为对应数据库实现ICrudRepository<TEntity, TId>即可,Domain层完全不需要修改——完美符合Clean Architecture的架构隔离要求。
方案合理性说明
- 依赖方向合规:所有外层(Infrastructure)依赖内层(Domain),Domain层完全不感知任何数据库实现细节。
- 实体纯度高:Domain实体仅包含业务属性和行为,没有任何数据库相关注解或接口,保持业务核心的独立性。
- 扩展性强:新增数据库类型时,仅需在Infrastructure层添加对应的Repository实现和映射配置,不影响Domain和Application层的代码。
内容的提问来源于stack exchange,提问作者Memordei
相关产品推荐
相关产品推荐

