DDD架构下EF Core结合MongoDB:保持抽象同时生成实体ObjectId
解决方案:在DDD架构下实现MongoDB自动生成ObjectId且不耦合领域层
针对你在DDD架构中遇到的「领域层用string类型Id、基础设施层对接MongoDB ObjectId,且创建时自动生成Id」的问题,以下是两种不破坏领域层与基础设施层分离的可行方案:
方案一:利用EF Core拦截器自动生成Id
通过EF Core的SaveChangesInterceptor,在基础设施层拦截实体保存操作,为新增的Customer自动生成MongoDB ObjectId并转换为string类型赋值,领域层无需感知任何数据库细节。
步骤1:在基础设施层实现拦截器
using Microsoft.EntityFrameworkCore.Diagnostics; using MongoDB.Bson; public class MongoIdGenerationInterceptor : SaveChangesInterceptor { public override ValueTask<InterceptionResult<int>> SavingChangesAsync( DbContextEventData eventData, InterceptionResult<int> result, CancellationToken cancellationToken = default) { if (eventData.Context == null) return base.SavingChangesAsync(eventData, result, cancellationToken); // 遍历所有新增状态的实体 foreach (var entry in eventData.Context.ChangeTracker.Entries()) { if (entry.State == EntityState.Added && entry.Entity is Customer customer && string.IsNullOrEmpty(customer.Id)) { // 生成MongoDB ObjectId并转为string赋值 customer.Id = ObjectId.GenerateNewId().ToString(); } } return base.SavingChangesAsync(eventData, result, cancellationToken); } }
步骤2:在MongoDbContext中注册拦截器
修改MongoDbContext的创建方法,添加拦截器到EF Core选项中:
public static MongoDbContext Create(IMongoDatabase database) => new(new DbContextOptionsBuilder<MongoDbContext>() .UseMongoDB(database.Client, database.DatabaseNamespace.DatabaseName) .AddInterceptors(new MongoIdGenerationInterceptor()) // 注册拦截器 .Options);
优点:无需修改领域层任何代码,侵入性极低;缺点:依赖EF Core的拦截机制,需确保使用的EF Core版本支持该功能。
方案二:基于DDD工厂模式分离对象创建职责
在领域层定义抽象工厂接口,基础设施层实现该接口来生成带自动Id的Customer实体,严格遵循DDD的依赖倒置原则。
步骤1:在领域层定义抽象工厂
public interface ICustomerFactory { Customer CreateNewCustomer(); }
步骤2:修改领域层的CustomerService依赖工厂
public class CustomerService { private readonly MyDbContext _mydbContext; private readonly ICustomerFactory _customerFactory; public CustomerService(MyDbContext mydbContext, ICustomerFactory customerFactory) { _mydbContext = mydbContext; _customerFactory = customerFactory; } public Customer Get(string id) { return _mydbContext.Customers.Find(id); } public Customer Create() { var customer = _customerFactory.CreateNewCustomer(); _mydbContext.Customers.Add(customer); _mydbContext.SaveChanges(); return customer; } }
步骤3:在基础设施层实现工厂
using MongoDB.Bson; public class MongoCustomerFactory : ICustomerFactory { public Customer CreateNewCustomer() { return new Customer { Id = ObjectId.GenerateNewId().ToString() }; } }
优点:符合DDD设计原则,明确分离实体创建的职责;缺点:需要在领域层新增抽象接口,并修改服务的依赖注入配置。
总结
- 若不想改动现有领域层代码,优先选择方案一;
- 若希望严格遵循DDD的架构规范,优先选择方案二。
两种方案都能保证领域层完全不依赖MongoDB相关组件,保持清晰的架构分离。
内容的提问来源于stack exchange,提问作者LP13
相关产品推荐
相关产品推荐

