导航更新、级联保存

与EF CORE区别

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

注意事项

long的主键会用雪花ID自动填充  一定要设置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 逻辑

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

 3.2 用例

//实体
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();


4、一对多

 4.1 逻辑

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

 4.2 用例

//实体
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();

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



6、通用功能

主表配置功能5.1.3.32

public class UpdateNavRootOptions
{
     public string[] IgnoreColumns { get; set; }//忽略列 需要升级到 5.1.3.32
     public string[] UpdateColumns { get; set; }//只更新哪几列
     public bool IsInsertRoot { get; set; }//强制插入主表 可以实现 更新或者插入效果
     public bool IsDiffLogEvent { get; set; }//启用主表差异日志
     public object  DiffLogBizData { get; set; }//差异日志参数
     public bool IsDisableUpdateRoot { get; set; }//禁更新主表5.1.3.33-preview05  
 }
    
    
db.UpdateNav(list,new UpdateNavRootOptions()
{
    IgnoreColumns = new string[] { "Id" }
})
.Include(x => x.Roles).ExecuteCommand();

插入或者更新

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

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

添加委托

5.1.2.5-preview03

比如我想添加忽略列,想用Updateable的方法

 Expression<Action<IUpdateable<Student_004>>> rootFunc = it => it.IgnoreColumns(x => x.Name);//不更新name委托

 db.UpdateNav(list)
          .Include(x=>x.books,new UpdateNavOptions() { 
                     RootFunc = rootFunc,//给List加委托 ,多个Inclue只要写第一个
                    //CurrentFunc = 当前Include x.Books 加委托,
                }).ExecuteCommand();


7、更多导航操作

导航更新: 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


文档:SqlSugar5.0