C# SqlBulkTools的BulkInsertOrUpdate是否支持Where子句?如何过滤更新记录?
解决SqlBulkTools批量合并时按updatedAt过滤更新的问题
SqlBulkTools的BulkInsertOrUpdate确实没有内置Where子句来控制更新条件,不过可以通过以下两种方案实现你的需求:
方案一:本地提前筛选符合条件的记录
先从服务器查询目标表中匹配Id的记录的updatedAt值,在本地筛选出新增记录(Id不存在于服务器)或本地更新时间晚于服务器的记录,再用BulkInsertOrUpdate处理筛选后的集合:
// 从服务器获取现有记录的Id与updatedAt映射 var existingUpdatedAtMap = conn.Query<(Guid Id, DateTime UpdatedAt)>("SELECT id, updatedAt FROM TABLENAME WHERE id IN @Ids", new { Ids = records.Select(r => r.Id) }) .ToDictionary(item => item.Id, item => item.UpdatedAt); // 筛选要处理的记录 var filteredRecords = records.Where(r => !existingUpdatedAtMap.ContainsKey(r.Id) || r.UpdatedAt > existingUpdatedAtMap[r.Id] ).ToList(); // 执行批量操作 result += new BulkOperations() .Setup<TABLENAME>() .ForCollection(filteredRecords) .WithTable("TABLENAME") .AddAllColumns() .CustomColumnMapping(a => a.UpdatedAt, "updatedAt") .CustomColumnMapping(a => a.CreatedAt, "createdAt") .CustomColumnMapping(a => a.Deleted, "deleted") .CustomColumnMapping(a => a.Id, "id") .BulkInsertOrUpdate() .MatchTargetOn(x => x.Id) .Commit(conn);
这种方式逻辑直观,适合数据量中等的场景,缺点是需要额外查询服务器数据。
方案二:自定义MERGE语句(底层级控制)
SqlBulkTools的批量更新底层依赖SQL的MERGE语句,你可以手动构建MERGE逻辑,先将数据批量导入临时表,再执行带条件的MERGE:
// 1. 将数据批量导入临时表 var bulkSetup = new BulkOperations() .Setup<TABLENAME>() .ForCollection(records) .WithTable("#TempTABLENAME") .AddAllColumns() .CustomColumnMapping(a => a.UpdatedAt, "updatedAt") .CustomColumnMapping(a => a.CreatedAt, "createdAt") .CustomColumnMapping(a => a.Deleted, "deleted") .CustomColumnMapping(a => a.Id, "id") .BulkInsert() .WithTempTable(); // 启用临时表模式 bulkSetup.Commit(conn); // 2. 执行自定义MERGE,仅当服务器updatedAt小于本地时更新 var mergeCommand = @" MERGE INTO TABLENAME AS target USING #TempTABLENAME AS source ON target.id = source.id WHEN NOT MATCHED THEN INSERT (id, updatedAt, createdAt, deleted) VALUES (source.id, source.updatedAt, source.createdAt, source.deleted) WHEN MATCHED AND target.updatedAt < source.updatedAt THEN UPDATE SET updatedAt = source.updatedAt, createdAt = source.createdAt, deleted = source.deleted; "; conn.Execute(mergeCommand); // 3. 清理临时表 conn.Execute("DROP TABLE #TempTABLENAME");
这种方式直接在数据库层面处理过滤逻辑,避免本地数据传输开销,适合大数据量场景。
内容的提问来源于stack exchange,提问作者xhedgepigx
相关产品推荐
相关产品推荐

