插入或更新/AddOrUpdate/InsertOrUpdate

简单用例

1、简化写法

新功能 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()

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
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()

3、添加事务锁

1
2
3
4
//需要事务才能用这个锁
Db.Storageable(list2).TranLock(DbLockType.Wait).ExecuteCommand()//建议单条保存使用并且用主键这样会走行锁,不锁整表
//DbLockType.Wait 多个并发等待执行
//DbLockType.Error 并发只保留一个其他扔错

调试数据

在执行插入或者更新前打上断点,我们可以看到是走更新还是走插入,具体哪些是更新,哪些是插入

image.png

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、接口、抽象类保存

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比较简单没有其他功能

DataTable类型:保存5.0.4.8 

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
    ....
    ....
}

调试:我们在执行插入更前打上断点,可以看到插入有哪些数据,更新有哪些数据

image.png 

字典类型:保存

用法区别和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();

大数据:性能优化  merge into

高级保存一般适用于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



关闭
果糖网