新功能 5.0.6.2+
优点:代码简洁
缺点:没办法使用insertable updateable 扩展方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //功能1:存在数据库更新 不存在插入 (默认是主键) Db.Storageable(list2).ExecuteCommand() //(老版本是Saveable) //分页 5.1.4.103-preview04+ Db.Storageable(list2).PageSize(1000).ExecuteCommand(); Db.Storageable(list2).PageSize(1000,exrows=> { }).ExecuteCommand(); //实体如果没主键可以通过WhereColumn(it=>it.Id)指定虚拟主键 //功能2:主键等于默认值插入否则更新(如果可以满足需求这种性能要好的多) 5.1.4.62 Db.Storageable(list).DefaultAddElseUpdate().ExecuteCommand() //原理: id=0插入 id不等于0更新 //或功能3:大数据插入或者更新 (部分库不支持自增) db.Fastest<Order>().BulkMerge(List); //db.Storageable<Order>(data).ExecuteSqlBulkCopy() //功能4:分表 5.1.4.132+ db.Storageable(data).SplitTable().ExecuteCommand(); db.Storageable<Order>(data).SplitTable().ExecuteSqlBulkCopy() |
这种写法后期扩展性强 ,调试也方便,insertable updateable支持扩展方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | //功能写法可以将插入和更新拆开,然后调用插入和更新独有特性 var x= db.Storageable(item).ToStorage(); x.AsInsertable.ExecuteCommand(); //不存在插入 x.AsUpdateable.ExecuteCommand(); //存在更新 //现实案例: 如果是插入:F_Status=草稿箱,如果是更新:不更新这个字段 item.F_Status= "草稿箱" ; var x= db.Storageable(item).ToStorage(); x.AsInsertable.ExecuteCommand(); //不存在插入 x.AsUpdateable.IgnoreColumns(z=>z.F_Status).ExecuteCommand(); //存在更新 //你可以写成只插入不更新 var x= db.Storageable(item).ToStorage(); x.AsInsertable.ExecuteCommand(); //你可以写成只更新不插入 var x= db.Storageable(item).ToStorage(); x.AsUpdateable.ExecuteCommand(); //你也可以拿到更新哪几条和插入哪几条 var x= db.Storageable(item).ToStorage(); var insertList=x.InsertList.Select(z=>z.Item).ToList(); var updateList=x.UpdateList.Select(z=>z.Item).ToList(); //原理 x.AsInsertable.ExecuteCommand() 等于 Db.Insertable(x.InsertList.Select(it=>it.Item).ToList()).ExecuteCommand() x.AsUpdateable.ExecuteCommand() 等于 Db.Updateable(x.UpdateList.Select(it=>it.Item).ToList()).ExecuteCommand() |
1 2 3 4 | //需要事务才能用这个锁 Db.Storageable(list2).TranLock(DbLockType.Wait).ExecuteCommand() //建议单条保存使用并且用主键这样会走行锁,不锁整表 //DbLockType.Wait 多个并发等待执行 //DbLockType.Error 并发只保留一个其他扔错 |
在执行插入或者更新前打上断点,我们可以看到是走更新还是走插入,具体哪些是更新,哪些是插入
1 | 样插入和更新就不会存毫秒 |
不用主键作为条件有2种情况
实体有主键并且是Sqlite请升级到5.1.4.94以上版本
1 2 3 4 5 | Db.Storageable(list2) .WhereColumns(it=>it.Id) //指定一个条件,当然支持多个 new {it.id,it.name} .ExecuteCommand(); //将数据进行分组 //注意:实体存在主键并且条件不是主键要升级较高版本 |
新功能:5.0.9.3-preview05 时间格式化 防止时止时间精度引起的失效,针对多元化时间格式进行处理
1 2 3 4 5 6 7 8 | var x=Db.Storageable(list2) .WhereColumns(it=>it.CreateTime, date=>date.ToString( "yyyy-MM-dd HH:mm:ss.fff" )) .ToStorage(); x.AsInsertable.ExecuteCommand(); //执行插入 x.AsUpdateable.ExecuteCommand(); //执行更新 //完美解决时间匹配不到问题 |
其它方案:Oracle和Sqlite用户会有遇到
1 2 3 4 | db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings { DisableMillisecond= true //插入和更新禁用毫秒 }; |
object.GetType必须还是类,只是用于弱类型接收,并不是真的Object
1 2 3 4 5 6 7 | //单条 object o= new Order{id=1,name= "a" }; //虽然是object类型必须是真实的类 ,一般于用反射出来的对象 db.StorageableByObject(o).ExecuteCommand(); //API比较简单没有其他功能 //多条 object o= new List<Order>(){...}; //虽然是object类型必须是真实的类 ,一般于用反射出来的对象 db.StorageableByObject(o).ExecuteCommand(); //API比较简单没有其他功能 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | var dt= new DataTable(); dt.TableName = "order" ; //设置表名 var addRow = dt.NewRow(); addRow[ "id" ] = 0; addRow[ "price" ] = 1; addRow[ "Name" ] = "a" ; dt.Rows.Add(addRow); //添加数据 var x= db.Storageable(dt).WhereColumns( "id" ).ToStorage(); //id作为主键 x.AsInsertable.IgnoreColumns( "id" ).ExecuteCommand(); //如果是自增要添加IgnoreColumns x.AsUpdateable.ExecuteCommand(); //DataTable也可以分页 db.Utilities.PageEach(dataTable.Rows.Cast<DataRow>().ToList(),100, it => { var newdt = it.CopyToDataTable(); newdt.TableName=dt.TableName; db.Storageable(newdt )..... //使用分页的dt .... .... } |
调试:我们在执行插入更前打上断点,可以看到插入有哪些数据,更新有哪些数据
用法区别和DataTable一样,唯一区别是需要设置一下表名
1 2 3 4 | List<Dictionary< string , object >> dictionaryList=xxxx; var x= db.Storageable(dictionaryList, "表名" ).WhereColumns( "id" ).ToStorage(); //id作为主键 x.AsInsertable.IgnoreColumns( "id" ).ExecuteCommand(); //如果是自增要添加IgnoreColumns x.AsUpdateable.ExecuteCommand(); |
高级保存一般适用于2万以下数据处理,超过2万就会明显变慢,所以我们需要分页处理,性能有质的提升
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | /********************新版本写法 5.1.4.109 ********************/ //大数据插入或者更新 //原理 merge into //Oracle和SqlServer使用了Merge Into+BulkCopy //其他库底层是 db.Storageable(list).ExecuteSqlBulkCopy() db.Fastest<Order>().BulkMerge(List); db.Fastest<Order>().PageSize(100000).BulkMerge(List); //普通插入或者更新 Db.Storageable(list2).PageSize(1000).ExecuteCommand(); Db.Storageable(list2).PageSize(1000,exrows=> { }).ExecuteCommand(); //如果这么写出现CPU过高那么,就需要检查条件字段 //varchar设置50以下千万不能用大字段,如果是非重复数据有索引最佳 //数据库可以把varchar换成navarchar测试一下2者性能差距,选取最优的类型 /********************分页函数********************/ //异步用 PageEachAsync db.Utilities.PageEach(list, 2000 ,pageList=> { var x= db.Storageable(pageList).ToStorage(); x.AsUpdateable.ExecuteCommand(); }); //异步用 PageEachAsync |
具体用法看导航更新
1 2 | db.UpdateNav(list, new UpdateNavRootOptions(){IsInsertRoot= true }) //IsInsertRoot=true表示不存在插入主表 .Include(x => x.Roles).ExecuteCommand(); |
请升级:5.1.4.100
1 2 3 4 5 6 7 | //分表字段必须要有正确的值才能找对应的表 db.Storageable( new OrderSpliteTest() { Name= "A" ,Time=DateTime.Now }) .SplitTable().ExecuteCommand(); //内部1000条分页一次 //BulkCopy db.Storageable( new Order() { Name = "A" , Time = DateTime.Now }) .SplitTable().ExecuteSqlBulkCopy(); //内部1000条分页一次 |
https://www.donet5.com/Home/Doc?typeId=2568
注意:了解规则后在用这个功能,这个功能一般是特殊规则下使用
1 2 | db.Storageable(list).TableDataRange(it=>it.TypeId==1).ExecuteCommand(); //也就是select * from 表 where typeId=1 里面是不是存在,如果存在更新,不存在插入 |
Storageable功能非常强大更深层次用法,请看下一篇文档:高级保存
https://www.donet5.com/Home/Doc?typeId=1208
2016 © donet5.comApache Licence 2.0