EF Core新增或编辑实体时同步复制数据到MongoDB的实现问题
EF Core变更自动同步到MongoDB实现方案
1. 从ChangeTracker获取变更实体
EF Core内置的ChangeTracker会跟踪所有实体的状态,你可以直接在OnSaveChangesAsync中读取到所有新增、修改、删除的实体,无需额外配置。
2. 重写SaveChangesAsync的核心代码
首先在你的自定义DbContext中注入MongoDB同步服务,示例如下:
public class AppDbContext : DbContext { private readonly IMongoSyncService _mongoSyncService; public AppDbContext(DbContextOptions<AppDbContext> options, IMongoSyncService mongoSyncService) : base(options) { _mongoSyncService = mongoSyncService; } public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default) { // 强制检测所有实体变更,确保跟踪状态最新 ChangeTracker.DetectChanges(); // 提前捕获所有变更实体及其原始状态,避免保存后状态被重置 var entityChanges = ChangeTracker.Entries() .Where(e => e.State is EntityState.Added or EntityState.Modified or EntityState.Deleted) // 可在此处添加过滤条件,排除不需要同步的实体 .Select(e => new { e.Entity, e.State }) .ToList(); // 先执行SQL Server保存操作,确保数据库生成字段(如自增ID、默认值)已回写到实体 var saveResult = await base.SaveChangesAsync(cancellationToken); // 同步变更到MongoDB foreach (var change in entityChanges) { switch (change.State) { case EntityState.Added: await _mongoSyncService.InsertAsync(change.Entity); break; case EntityState.Modified: await _mongoSyncService.UpdateAsync(change.Entity); break; case EntityState.Deleted: await _mongoSyncService.DeleteAsync(change.Entity); break; } } return saveResult; } }
3. MongoDB同步服务示例
你可以基于实体主键实现通用的Upsert逻辑,无需区分新增/更新:
public class MongoSyncService : IMongoSyncService { private readonly IMongoDatabase _mongoDb; public MongoSyncService(IMongoDatabase mongoDb) { _mongoDb = mongoDb; } public async Task UpsertAsync<T>(T entity) where T : class { // 假设所有需要同步的实体都有Id属性作为主键 var primaryKey = typeof(T).GetProperty("Id")?.GetValue(entity); if (primaryKey == null) return; var collection = _mongoDb.GetCollection<T>(typeof(T).Name); var filter = Builders<T>.Filter.Eq("Id", primaryKey); // IsUpsert=true 表示匹配到就更新,没匹配到就插入 await collection.ReplaceOneAsync(filter, entity, new ReplaceOptions { IsUpsert = true }); } // Insert、Update、Delete方法可按需实现,也可直接用Upsert替代新增+更新逻辑 }
4. 核心注意事项
- 保存顺序:必须先执行
base.SaveChangesAsync再同步MongoDB,否则EF生成的数据库字段(如自增ID、计算列)还未赋值,同步到MongoDB的数据会缺失关键信息。 - 性能优化:如果同步逻辑耗时较高,可将变更实体写入内存队列或消息队列,异步消费同步,避免阻塞主保存流程。
- 事务一致性:如果需要强一致性,可将SQL Server和MongoDB的操作纳入分布式事务,注意MongoDB事务需要副本集/分片集群支持。
内容的提问来源于stack exchange,提问作者Sein Gerivani
相关产品推荐
相关产品推荐

