导航更新、级联保存

与EF CORE区别

SqlSugar不依赖数据库外键,只要配置实体导航就能使用

注意事项

long的主键会用雪花ID自动填充,可以用外部雪花ID标题8,  一定要设置WORKID , 只要静态变量不能共享的情况都要有独的WorkId

比如我本地插入和服务上插入那么在同一时间可能会有重复

比如我负载多个服务器时候

SnowFlakeSingle.WorkId= 唯一数字; //从配置文件读取一定要不一样
//在程序启动时设置一次就行

1、导航更新语法(多层级)

设计参考于EF Core查询,只要配置好实体就可以随意使用导航进行插入操作

    //说明: 一对一 、一对多和多对多都可以混合使用
     
    //list里面是多层级的对象  
    List<Student> list=new List<Student>();
    list.Add(new Student(){ 
                 Id=1,
                 Name="jack",
                 SchoolId=2,
                 SchoolA=new SchoolA(){...RoomList=new List<Room>{...}}, 
                 Books=new List<Books> {...} })
    
    db.UpdateNav(list)
    .Include(z1 => z1.SchoolA).ThenInclude(z1 => z1.RoomList)//更新2层 Root->ShoolA-RoomList
    .Include(z1 => z1.Books)//更新第1层 Root->Books
    .ExecuteCommand();
    
    //这种表示多层级
    //Include(..).ThenInclude(..).ThenInclude(..)

2、性能介绍

主键自增性能最差,因为自增需要循环才能拿到(多对多中间表除外

如果是自增建议小数据更新

3、一对一

 3.1 逻辑

逻辑更新主表 ,子表存在更新,不存在插入

//实体
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int StudentId { get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
    //标准配置 推荐
    [Navigate(NavigateType.OneToOne, nameof(SchoolId))]//一对一 SchoolId是StudentA类里面的
    public SchoolA SchoolA { get; set; } //不能赋值只能是null
     
    //非主键模式 需要手动赋值防止插入0这种默认值
    //[Navigate(NavigateType.OneToOne, nameof(SchoolId),nameof(SchoolA.Id))] 

 
}
public class SchoolA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id{ get; set; }
    public string SchoolName { get; set; }
}

 //逻辑更新主表 ,子表存在更新,不存在插入
 var List<StudentA> list=new List<StudentA>(){....};
 db.UpdateNav(List<StudentA>)
            .Include(z1 => z1.SchoolA)
            .ExecuteCommand();

 3.2 脏数据兼容 

请升级到:5.1.4.111-preview15+才支持

更新的时候SchoolId =0只给SchoolA中主键赋值

var StudentA=new StudentA()
{
   Id=1,
   Name="张三",
   SchoolId =4,//如果这个ID=4数据库中不存在只要有这可能性 全部强制改成默认值0 (int默认值是0)
   SchoolA=new SchoolA()
   {
      Id=1 //这边赋值正确值就行,存在更新不存在插入
      Name="北大"
   }
}
//需要升级到:5.1.4.111-preview15 才支持这种兼容错误数据

注意:这种一般发生在带有脏数据的情况,比如删掉了子表中的记录,而主表还存在这个记录,并且又UI操作,UI可能会强制让你选

3.2  非主键一对一

先用默认的,不满足需求在看这个

 db.UpdateNav(data, new UpdateNavRootOptions()
 {
     IsInsertRoot = true//主表启用插入或者更新
 })
.ThenInclude(n => n.SchoolA, new UpdateNavOptions()
 {
     //强制按主键实现插入或者更新
     //5.1.4.157-preview11+
     OneToOneSaveByPrimaryKey = true  
 })
.ExecuteCommand()

4、一对多

 4.1 模式1:子表先删后加

先更新主表然后 删除子表 在 插入子表 

优点:这种性能好在乎性能的推荐这种 (推荐

 db.UpdateNav(list) 
  .Include(x => x.Persons)//默认
  .ExecuteCommand();

 4.2 模式2:子表插入、更新或删除

请升级到:5.1.4.113-preview+

先更新主表  子表存在更新 、不存在插入 同时 也支持前端删掉子表

优点:减少了删除操作

缺点:因为前端本身就有删除操作所以存在插入、改和删3种逻辑 性能比4.1要差一点

 db.UpdateNav(list2)
 .Include(x => x.Persons,new SqlSugar.UpdateNavOptions()
                { 
                   OneToManyInsertOrUpdate = true,//配置启用 插入、更新或删除模式
                })
 .ExecuteCommand();
//请升级到:5.1.4.113-preview+

注意:想走更新逻辑需要主键 ,如果没主键就当作前端删掉在加

4.3  详细教程

//实体
public class StudentA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id{ get; set; }
    public string Name { get; set; }
    public int SchoolId { get; set; }
    [Navigate(NavigateType.OneToMany, nameof(BookA.studenId))]//BookA表中的studenId
    public List<BookA> Books { get; set; }//注意禁止给books手动赋值
     
    //非主键模式 需要手动赋值防止插入0这种默认值
     //[Navigate(NavigateType.OneToMany, nameof(BookA.studenId),nameof(Id))] 
     //与一对一相反 第一个 从表字段,第二个主表字段
 
}
public class BookA
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int BookId { get; set; }
    public string Name { get; set; }
    public int studenId { get; set; }
}

 //先更新主表然后 删除子表 在 插入子表
 var List<StudentA> list=new List<StudentA>(){....};
 db.UpdateNav(list)
            .Include(z1 => z1.Books)
            .ExecuteCommand();
            
            
 //强制删除下级一对多脏数据(5.0.2.3-preview04)
 db.UpdateNav(list)
  .Include(z1 => z1.Books,new UpdateNavOptions(){OneToManyDeleteAll=true})//强制删除下级一对多的脏数据
  .ThenInclude(z1 => z1.RoomList)
  .ExecuteCommand();
  
  //只更新子表  
  db.UpdateNav(list,new UpdateNavRootOptions(){ IsDisableUpdateRoot= true})
  .Include(x => x.datas).ExecuteCommand();
  
  //假删除(5.1.4.86)
  db.QueryFilter.AddTableFilter<Province>(it => it.IsDeleted == false);//配合查询过滤器    
  db.UpdateNav(country)
     .Include(it => it.Provinces,new UpdateNavOptions() { OneToManyEnableLogicDelete=true }) 
     .ExecuteCommand();//

  //null列不更新5.1.144-preview13+     
  db.UpdateNav(list)
        .Include(x => x.Books, new SqlSugar.UpdateNavOptions()
        {
            OneToManyInsertOrUpdate = true, 
            IgnoreNullColumns=true
        }).ExecuteCommand();
        
  //忽略列不更新
  db.UpdateNav(list)
        .Include(x => x.Books, new SqlSugar.UpdateNavOptions()
        {
            OneToManyInsertOrUpdate = true, 
            IgnoreColumns =new string[] { "Name" }
        }).ExecuteCommand();

5、多对多

 5.1 逻辑

有4种模式 ,A表代表主表,B表代表从表

1、只更新关系表 

2、更新A表+关系表 

3、更新B表+关系表,

4、更新A表、B表和关系表

 5.2 用例

//实体
public class ABMapping1
{
    [SugarColumn(IsPrimaryKey = true)]//中间表可以不是主键
    public int AId { get; set; }
    [SugarColumn(IsPrimaryKey = true)]//中间表可以不是主键
    public int BId { get; set; }
}
public class A1
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; }
    [Navigate(typeof(ABMapping1), nameof(ABMapping1.AId), nameof(ABMapping1.BId))]//注意顺序
    public List<B1> BList { get; set; }//只能是null不能赋默认值
}
public class B1
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    public string Name { get; set; }
    [Navigat(typeof(ABMapping1), nameof(ABMapping1.BId), nameof(ABMapping1.AId))]//注意顺序
    public List<A1> AList { get; set; }//只能是null不能赋默认值
}


 List<A1> List=new List<A1>{ new A1(){  Id=1,BList=new List<B1>{...}} };
 
 //默认模式:只更新关系表 (删除添加)
 db.UpdateNav(list)
            .Include(z1 => z1.BList)
            .ExecuteCommand();//技巧:只更新中间表可以只传A和B表的主键其他不用赋值
            
            
 //更新A表+更新关系表
 db.UpdateNav(list)
            .Include(z1 => z1.BList,new UpdateNavOptions { 
                         ManyToManyIsUpdateA=true
                       })
            .ExecuteCommand();
            
            
 //不存在添加B表,存在更新B表 + 更新关系
 db.UpdateNav(list)
            .Include(z1 => z1.BList,new UpdateNavOptions { 
                         ManyToManyIsUpdateB=true
                       })
            .ExecuteCommand();
 
 //更新A表  + 不存在添加B表,存在更新B表 + 更新关系
 db.UpdateNav(list)
            .Include(z1 => z1.BList,new UpdateNavOptions { 
                         ManyToManyIsUpdateA=true
                         ManyToManyIsUpdateB=true
                       })
            .ExecuteCommand();

 5.3 中间额外字段赋值

假设Opt 为A表  ,Roles为B表 ,OptRole为中间表   请升级:5.1.4.86 

db.UpdateNav(Opt).Include(z => z.Roles, new UpdateNavOptions()
                      {      
                           //设置中间表其他字段 (5.1.4.86)
                          ManyToManySaveMappingTemplate = new OptRole()
                          {
                              CreateTime = "1010",//除了主键和Aid和Bid外的字段赋值
                              OrgId = "1x"

                           }
                        })
         .ExecuteCommand();

 5.4 多对多假删除

 5.1.4.89-preview10

 db.UpdateNav(list)
    .Include(z1 => z1.BList,new UpdateNavOptions { 
            ManyToManyEnableLogicDelete=true //需要结合过滤器实现假删
             })
            .ExecuteCommand();
            //一对多用:OneToManyEnableLogicDelete

6、主表通用功能

public class UpdateNavRootOptions
{
     public string[] IgnoreColumns { get; set; }//主表更新忽略列(实体配置特性也可以方便的实现)
     public string[] UpdateColumns { get; set; }//只更新哪几列
     public bool IsInsertRoot { get; set; }//强制插入主表 可以实现 更新或者插入效果
     public string[] IgnoreInsertColumns { get; set; }//主表启用插入忽略列 5.1.3.58
     public bool  IsIgnoreAllNullColumns  {get;set;} //不更新null列 5.1.4.112
     public bool IsDiffLogEvent { get; set; }//启用主表差异日志
     public object  DiffLogBizData { get; set; }//差异日志参数
     public bool IsDisableUpdateRoot { get; set; }//禁更新主表5.1.3.33-preview05  
     public bool IsOptLock{get;set;}//主表乐观锁  5.1.4.90
 }
    
//使用示例    
db.UpdateNav(list,new UpdateNavRootOptions()
{
    IgnoreColumns = new string[] { "Id" }
})
.Include(x => x.Roles).ExecuteCommand();

 6.1 IgnoreColumns    忽略更新列

db.UpdateNav(list,new UpdateNavRootOptions()
{
   IgnoreColumns    =  new string[] {"Name","CreateTime"}// 主表这2列不更新
})
.Include(x => x.Roles).ExecuteCommand();

 6.2  UpdateColumns 只更新列

db.UpdateNav(list,new UpdateNavRootOptions()
{
    UpdateColumns = new string[]{"Name","CreateTime"}//主表只更新2列
})
.Include(x => x.Roles).ExecuteCommand();

 6.3  可以插入主表 (插或更新)

配置IsInsertRoot那么主表不存在就插入存在更新

db.UpdateNav(list,new UpdateNavRootOptions()
{
    IsInsertRoot = true
})
.Include(x => x.Roles).ExecuteCommand();

 6.4 IsDiffLogEvent 差异日志

db.UpdateNav(list,new UpdateNavRootOptions()
{ 
    IsDiffLogEvent = true 主表启用差异日志
    //DiffLogBizData 
})
.Include(x => x.Roles).ExecuteCommand();

 6.5  禁止更新主表 

db.UpdateNav(list,new UpdateNavRootOptions()
{
   IsDisableUpdateRoot=true //主表不更新
})
.Include(x => x.Roles).ExecuteCommand();

 6.7 IsOptLock  乐观锁

db.UpdateNav(list,new UpdateNavRootOptions()
{
    IsOptLock = true//主表启用乐观锁
})
.Include(x => x.Roles).ExecuteCommand();

 6.8  不更新null列

db.UpdateNav(list,new UpdateNavRootOptions()
{
    IsIgnoreAllNullColumns=true//主表null列不更新
})
.Include(x => x.Roles).ExecuteCommand();

7、自动导航更新

新功能:5.1.4.108

支持第2层级的所有导航自动Includes (超过2层的需要用手动导航更新)

db.UpdateNav(list).IncludesAllFirstLayer().ExecuteCommand();
db.UpdateNav(list).IncludesAllFirstLayer(nameof(类.导航),nameof(类.导航2)).ExecuteCommand();//排除不需要的导航

//3级+自动
db.UpdateNav(list)
          .IncludesAllFirstLayer()//自动2级
          .IncludeByNameString(nameof(类.导航)).ThenIncludeByNameString(nameof(类.导航2))//3级
          .ExecuteCommand();

自动导航 这个看不懂?可以看导航插入 有详细的例子原理一样

8、雪花ID冲突

导航更新默认是自带的雪花ID,如果和你的代码中的雪花ID冲突了可以全部替换成你的雪花ID

  //程序启动时执行一次就行
  StaticConfig.CustomSnowFlakeFunc = () =>
  {
      return 你的雪花ID方法();
  };

9、更多导航操作

导航更新: https://www.donet5.com/home/Doc?typeId=2432

导航删除: https://www.donet5.com/home/Doc?typeId=2431

导航插入: https://www.donet5.com/home/Doc?typeId=2430

导航查询: https://www.donet5.com/home/Doc?typeId=1188


关闭
果糖网