使用OleDB和Entity Framework插入数据时如何避免重复?
Excel导入数据库避免重复插入的实现方案
核心优化思路
- 提前拉取数据库中已存在的唯一标识(此处以
siteIDDatagate作为去重依据,你可以根据实际业务调整为其他唯一字段或组合字段),存入内存集合做校验,避免循环中每次查询数据库导致性能低下 - 去掉循环内的单次
SaveChanges(),改为批量提交,大幅提升导入效率 - 移除无效的
Attach()操作,新创建的实体对象直接执行新增操作即可,不需要提前附加到上下文
修改后的实现代码
DataView ImportarDatosSites(string filename) { // 提前查询数据库中已存在的siteIDDatagate,存入HashSet做O(1)效率的校验 HashSet<string> existSiteIds = new HashSet<string>(db.SitesMtto.Select(x => x.siteIDDatagate).ToList()); string conexion = string.Format("Provider = Microsoft.ACE.OLEDB.12.0; Data Source={0}; Extended Properties= 'Excel 8.0;HDR=YES'" ,filename ); using (OleDbConnection connection = new OleDbConnection(conexion)) { connection.Open(); OleDbCommand command = new OleDbCommand("SELECT * FROM [BaseSitiosTelemetria$]", connection); OleDbDataAdapter adaptador = new OleDbDataAdapter { SelectCommand = command }; DataSet ds = new DataSet(); adaptador.Fill(ds); DataTable dt = ds.Tables[0]; using (OleDbDataReader dr = command.ExecuteReader()) { while (dr.Read()) { var SiteID = dr[1]; var currentSiteId = SiteID.ToString(); // 校验ID是否已存在,存在直接跳过 if (existSiteIds.Contains(currentSiteId)) { continue; } var ID_AA_FB = dr[2]; var Address = dr[3]; var CreateDate = dr[5]; var Tipo = dr[7]; var Measures = dr[9]; var Latitud = dr[10]; var Longitud = dr[11]; SitesMtto s = new SitesMtto(); s.siteIDDatagate = currentSiteId; s.idFieldBeat = ID_AA_FB.ToString(); s.addressDatagate = Address.ToString(); s.createDateDatagate = Convert.ToDateTime(CreateDate); s.typeDevice = Tipo.ToString(); s.MeasuresDevice = Measures.ToString(); if (Latitud.ToString() != "" && Longitud.ToString() != "") { s.latitudeSite = Convert.ToDouble(Latitud); s.longitudeSite = Convert.ToDouble(Longitud); } db.SitesMtto.Add(s); // 把新增的ID也加入校验集合,避免Excel内本身有重复ID的情况 existSiteIds.Add(currentSiteId); } // 批量提交所有新增操作,大幅提升性能 db.SaveChanges(); connection.Close(); return ds.Tables[0].DefaultView; } } }
扩展:如果需要实现「存在则更新、不存在则插入」的逻辑
只需要修改校验部分的代码即可:
// 替换之前的ID校验逻辑 var existSite = db.SitesMtto.FirstOrDefault(x => x.siteIDDatagate == currentSiteId); if (existSite != null) { // 给已存在的实体赋新值 existSite.idFieldBeat = ID_AA_FB.ToString(); existSite.addressDatagate = Address.ToString(); // 其他需要更新的字段依次赋值 } else { // 新增实体逻辑和之前一致 SitesMtto s = new SitesMtto(); // 赋值属性 db.SitesMtto.Add(s); }
内容的提问来源于stack exchange,提问作者Enrico Grez
相关产品推荐
相关产品推荐

