EF Core实现同ID多条码商品的高效批量插入方案
问题场景
我们定义了如下两个实体类:
public class Article{ public int Id {get; set;} public double price {get; set;} public ICollection<Barcode> barcodes {get; set;} } public class Barcode { public int Id {get; set;} public long Value{get; set;} public int ArticleId {get; set;} public Article Article {get; set;} }
解析.csv文件时,会出现同一商品ID对应多行不同数据的情况,示例如下:
- 行1:
1234 | 591111111111111 | 13.49 - 行2:
1234 | 591111111111112 | 13.49
即两个不同的EAN条码可对应同一个Article商品实体。
待导入的CSV文件包含超过10万行数据,解析CSV后已有如下代码:
List<Article> importedArticles = _csvParseFile(filePath); // 应如何遍历该集合,最终实现单次调用AddRange完成数据库批量插入?
核心要求:
- 完全规避O(n*m)时间复杂度的嵌套遍历逻辑
- 首次遍历到某商品ID时创建对应商品记录,同时添加关联条码
- 后续遍历到相同商品ID但不同EAN条码时,仅追加关联条码
- 最终可通过批量插入完成数据落库
实现方案
核心思路是用字典做商品ID到实体实例的O(1)映射,单次线性遍历即可完成去重和关联数据聚合,全程无嵌套循环,时间复杂度严格为O(n)。
注意:默认_csvParseFile返回的集合是逐行解析的原始结果——即每一行CSV对应一个Article实例,同ID的商品会重复出现在列表中,每个实例仅携带当前行对应的单个条码。如果解析方法已经做了不完整的分组,先调整解析逻辑输出逐行的扁平结构即可。
具体实现代码
// 存储商品ID与对应去重后的Article实体,查找/插入时间复杂度O(1) var articleDict = new Dictionary<int, Article>(); // 存储所有需要插入的条码记录 var allBarcodes = new List<Barcode>(); // 单次遍历所有解析结果 foreach (var rowItem in importedArticles) { // 尝试从字典中获取已创建的商品实例 if (!articleDict.TryGetValue(rowItem.Id, out var existingArticle)) { // 首次遇到该商品ID,新建实体 existingArticle = new Article { Id = rowItem.Id, price = rowItem.price, barcodes = new List<Barcode>() }; articleDict.Add(rowItem.Id, existingArticle); } // 提取当前行对应的条码,取值逻辑按你实际的_csvParseFile输出结构调整 var currentBarcode = rowItem.barcodes.First(); currentBarcode.ArticleId = existingArticle.Id; currentBarcode.Article = existingArticle; // 关联条码到商品,加入总条码列表 existingArticle.barcodes.Add(currentBarcode); allBarcodes.Add(currentBarcode); } // 提取所有去重后的商品 var articlesToInsert = articleDict.Values.ToList(); // 批量插入,两次AddRange即可完成 _dbContext.Articles.AddRange(articlesToInsert); _dbContext.Barcodes.AddRange(allBarcodes); _dbContext.SaveChanges();
方案说明
- 整个流程仅做一次线性遍历,字典操作均为O(1),10万行数据处理耗时通常在百毫秒以内
- 无需提前对数据做排序、全量分组操作,内存占用仅和去重后的商品数、总条码数正相关
- 如果业务要求条码值全局唯一,可额外增加一个
HashSet<long>存储已处理的条码值,遍历过程中做重复校验,避免脏数据入库 - 如果使用支持批量插入的ORM(比如SqlBulkCopy、EFCore.BulkExtensions),可以直接将两个列表传入做高性能bulk insert,10万行数据导入耗时可控制在1秒内
内容的提问来源于stack exchange,提问作者Alex Ivan
相关产品推荐
相关产品推荐

