该功能是 增、删、改的一个升级版本,可以说是非常有实用价值,如果你们把SqlSugar的增、删、改都学习完了,可以学习一下该功能,主要适用于:
1、大数据通用保存
2、大数据EXCEL数据导入
3、大数据数据验证
4、可以编辑的表格 保存
将数据进行分组,然后可以针对分组进行批量操作(高性能)
一条记录同时Update=true和 Insert=true 那就看优先级哪个高
Ignore> Other(预留)>Error>Delete> Update> Insert
总结:哪个为true就进哪个分组,如果2个true就看优先级,分好组之后可以操作你分组的数据,也可以不操作
进了哪个分组,我们可以通过断点进行调试
性能优化:图中的 Insert NotAny可以改成 it=>true (因为Insert优先级最低不是其他分类就肯定是插入)
分组后去核对你的数据,是不是正确
TotalList=InsertList+UpdateList+ErrorList+IgnoreList+OtherList+DeleteList
比如 InsertList 有一条值那么 x.AsInsertable.Execommand()就插入1条
我们装备4条测试数据
List<UinitBlukTable> list2 = new List<UinitBlukTable>(); list2.Add(new UinitBlukTable() { Id = 1, Name = "a",Sex=1 ,Create = DateTime.Now }); list2.Add(new UinitBlukTable() { Id = 2, Name = "a",Sex=0,Create = DateTime.Now }); list2.Add(new UinitBlukTable() { Id = 3, Name = "a",Sex=0,Create = DateTime.Now.AddYears(-2) }); list2.Add(new UinitBlukTable() { Id = 4, Name ="",Sex=0,Create = DateTime.Now.AddYears(-2) });
将错误数据、可插入数据、可更新数据等进行分类
var sexList=查询字典Sex;//像这种字典或者多表验证一次查出来(不要超过1万条为佳想办法太多想办法拆分) var x = Db.Storageable(list2) //不要超过2万,超过2万用页 (标题5) //性能Ok:内存过滤不会循环读库 .SplitError(it =>!sexList.Any(z=>z.Name==it.Item.Sex),"性别不存在字典中") //性能差: 适合非批量的验证操作 .SplitError(it => db.Queryable<UinitBlukTable>().Any(s=>s.Id==it.Item.Phone),"手机已存在") //性能OK:无操作数据库,只内存验证非空 .SplitError(it => string.IsNullOrEmpty(it.Item.Name), "名称不能为空") .SplitError(it => it.Item.Create<DateTime.Now.AddYears(-1),"不是今年的数据") .SplitError(it => string.IsNullOrEmpty(it.Item.Name), "名称不能为空") .SplitDelete(it =>it.Item.Create<DateTime.Now.AddYears(-10))//删除10年前数据 .SplitInsert(it => true )//其余插入(因为插入优先级最低不满其他条件就是插入) .SplitUpdate(it => it.Any())//数据库存在更新 根据主键 .ToStorage(); //输出统计 Console.WriteLine(" 插入 {0} 更新{1} 错误数据{2} 不计算数据{3} 删除数据{4},总共{5}" , x.InsertList.Count, x.UpdateList.Count, x.ErrorList.Count, x.IgnoreList.Count, x.DeleteList.Count, x.TotalList.Count //输出错误信息 ); foreach (var item in x.ErrorList) { Console.WriteLine("id等于"+item.Item.Id+" : "+item.StorageMessage); } x.AsInsertable.ExecuteCommand(); //执行插入 x.AsUpdateable.ExecuteCommand(); //执行更新 x.AsDeleteable.ExecuteCommand(); //执行删除
执行代码输出结果:
统计:
错误信息:
我们可以看到输出id3和id4是错误的,并且可以输出具体的错误明细
Ignore> Other>Error>Delete> Update> Insert, 就是说 同时满足 Ignore和 Delete那么这条数据将会属于Ignore,
当前的顺序是非常科学合理的,所以如果遇到几个都成立的时候可以看一下优先级关系
var x=Db.Storageable(list2) .SplitInsert(it => true) .SplitUpdate(it => it.Any()) //SplitInsert和SplitUpdate可以用Saveble替换 .SplitDelete(it=>it.Item.Id>10) .SplitIgnore(it=>it.Item.Id==1) .SplitError(it => it.Item.Id == 3,"id不能等于3") .SplitError(it => it.Item.Id == 4, "id不能等于4") .SplitError(it => it.Item.Id == 5, "id不能等于5") .SplitError(it => it.Item.Name==null, "name不能等于") .WhereColumns(it=> new { it.Id }) .ToStorage();
上面虽然Insert是true,只要进Error或者Ignore或者Update都轮不到Insert
我们可以将分组后的数据直接进行数据操作转换,并且转换后的功能是100% 增、删、改 功能
AsInsertable
AsUpdateable
AsDeleteable
x.AsInsertable.IgnoreColumns(it => new { it.Name, it.TestId }).ExecuteReturnIdentity();
数据据量超过2万最好进行分页处理,性能会大大提升
//分页能起到不错的性能提升 db.Utilities.PageEach(list, 2000 ,pageList=> { var x = Db.Storageable(pageList) .SplitUpdate(it => it.Any())//数据库存在更新 根据主键 .SplitInsert(it => true )//其余插入 .ToStorage();//将数据进行分组 x.BulkCopy(); x.BulkUpdate(); //5.0.4.6 }); //如果这么写出现CPU过高那么,就需要检查条件字段 //varchar设置50以下千万不能用大字段,如果是非重复数据有索引最佳 //数据库可以把varchar换成navarchar测试一下2者性能差距,选取最优的类型
我们需要对Any的原理深一步理解,把存在数据库的数据全部查询出来然后在进行.Any筛选
it.Any()//等于下面 it.Any(y=>y.id==it.Item.Id)//等于下面 (select * from table where id in list).ToList().Any(y=>y.id==it.Item.Id)//多次Any也只会读取一次数所库 //所以Any只是在现有存在的主键里面过滤,并没有全库处理
错误写法:
var x=Db.Storageable(saveObject) .SplitError(i => i.Any(it => it.Name== i.Item.Name), "名称已存在")//编辑验证 .SplitInsert(i=>true)//其余插入 .ToStorage(); //因为it只是根据主键存在数据, 主键不存在的数据无法过滤
正确写法:
var x=db.Storageable(list) .SplitError(it => it.Any(), "名称已存在") .SplitInsert(it => true) .WhereColumns(it => it.Name)//这里用name作为数据库查找条件 .ToStorage() x.AsInsertable.ExecuteCommand();//插入可插入部分 if(x.ErrorList.Any())//输出所有错误部分 { foreach (var item in x.ErrorList) { Console.WriteLine(item.StorageMessage); } }
上面都是实体操作,新版本支持了DataTable
var x = db.Storageable(dt) .SplitUpdate(it=>it.Any()) .SplitInsert(it => true) .SplitDelete(it=>Convert.ToInt32( it["id"])==100) .WhereColumns("id").ToStorage(); //分组优先级是 删除>更新>插入 x.AsDeleteable.ExecuteCommand(); x.AsInsertable.IgnoreColumns("id").ExecuteCommand();//如果是自增要添加IgnoreColumns x.AsUpdateable.ExecuteCommand();
新功能:5.0.9.3-preview05 时间格式化防止时间精度引起的失效 ,针对多元化时间格式进行处理
var x=Db.Storageable(list2) .SplitUpdate(it=>it.Any()) .SplitInsert(it => true) .WhereColumns(it=>it.CreateTime, date=>date.ToString("yyyy-MM-dd HH:mm:ss.fff")) .ToStorage(); x.AsInsertable.ExecuteCommand(); //执行插入 x.AsUpdateable.ExecuteCommand(); //执行更新 //完美解决时间匹配不到问题
2016 © donet5.comApache Licence 2.0