插入或更新/AddOrUpdate/InsertOrUpdate

简单用例

判断新增还是修改,类似 merge into ,性能比merge into 好 不会死锁 


1、简化写法

新功能 5.0.6.2+ 

优点:代码简洁

缺点:没办法使用insertable updateable 扩展方法

//存在更新 不存在插入 (默认是主键)
Db.Storageable(list2).ExecuteCommand()//新版才支持


//等于0插入否则更新(不验证数据库是否存在)
Db.Storageable(list).SplitUpdate(it =>it.Item.Id>0).SplitInsert(it =>true).ExecuteCommand()


//分表不支持Storageable,可以用设置新表名方式实现
Db.Storageable(list2).As("新表名").ExecuteCommand()

2、功能写法

这种写法后期扩展性强 ,调试也方便,insertable updateable支持扩展方法

 //现实案例: 如果是插入:F_Status=草稿箱,如果是更新:不更新这个字段
 item.F_Status="草稿箱";
 var x= db.Storageable(item).ToStorage();
 x.AsInsertable.ExecuteCommand();//不存在插入
 x.AsUpdateable.IgnoreColumns(z=>z.F_Status).ExecuteCommand();//存在更新
    
 //你可以写成只插入不更新
 x.AsInsertable.ExecuteCommand(); 
  
 //你可以写成只更新不插入
 x.AsUpdateable.ExecuteCommand(); 

 
 //你也可以拿到更新哪几条和插入哪几条
 var insertList=x.InsertList;//如果要转成List<T> 改成 x.InsertList.Select(z=>z.Item).ToList()
 var updateList=x.UpdateList;
 
    
 //原理 
 x.AsInsertable 等于 
 Db.Insertable(x.InsertList.Select(it=>it.Item).ToList())

 x.AsUpdateable  等于  
 Db.Updateable(x.UpdateList.Select(it=>it.Item).ToList())


调试数据

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

image.png


样插入和更新就不会存毫秒

无主键用法

不用主键作为条件有2种情况

1、实体没有设置主键 或者主键值是对的

Db.Storageable(list2) 
      .WhereColumns(it=>it.Id)//指定一个条件,当然支持多个 new {it.id,it.name}
      .ExecuteCommand();//将数据进行分组
      
//注意:实体存在主键并且条件不是主键看下面用法

2.实体有设置主键 并且主键值是错的 (例如id=0)

var x = Db.Storageable(list2) 
      .WhereColumns(it=>it.name)//指定非主键为条件(这一列数据库要唯一,多个new {it.id,it.name})
      .ToStorage();//将数据进行分组 
      
   x.AsInsertable.ExecuteCommand(); 
   //重点看这一行更新要过滤掉实体主键 
   x.AsUpdateable.IgnoreColumns(z=>z.Id).ExecuteCommand();
 
 //实体如下
 public class Test
 {
    [SugarColumn(IsPrimaryKey=true,IsIdentity=true)]
    public int Id {get;set;}
    
    public  string Name{get;set;} //条件列
    
    public  string Context{get;set;}
 }


时间类型问题

新功能:5.0.9.3-preview05 时间格式化 防止时止时间精度引起的失效,针对多元化时间格式进行处理

 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用户会有遇到

 db.CurrentConnectionConfig.MoreSettings = new ConnMoreSettings
 {
       DisableMillisecond=true//插入和更新禁用毫秒
 };

大数据操作

对于性能要求高,数据量大的可以这么操作,适合1万以上数据处理

  var x= db.Storageable<Order>(data).ToStorage();
    x.BulkCopy();
    x.BulkUpdate(); //5.0.4.6
    
//winform写法需要注意 看db.Fastest文档


DataTable保存5.0.4.8 

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

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

image.png 


字典用法

用法区别和DataTable一样,唯一区别是需要设置一下表名

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万就会明显变慢,所以我们需要分页处理,性能有质的提升

//分页处理
db.Utilities.PageEach(list, 2000 ,pageList=> {
      
     Db.Storageable(pageList).ExecuteCommand();//条件列禁止varchar(50)以上,并且是主键或者有索引为佳
     
      //也可以用BulkCopy
      //var x= db.Storageable<Order>(pageList).ToStorage();
           //x.BulkCopy();
           //x.BulkUpdate();  
     
});
//如果这么写出现CPU过高那么,就需要检查条件字段
//varchar设置50以下千万不能用大字段,如果是非重复数据有索引最佳
//数据库可以把varchar换成navarchar测试一下2者性能差距,选取最优的类型

更多功能

Storageable功能非常强大更深层次用法,请看下一篇文档:高级保存 

https://www.donet5.com/Home/Doc?typeId=1208



文档:SqlSugar5.0