导航插入 、级联插入

与EF CORE区别

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

注意事项

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

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

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

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

1、导航插入语法(多层级)

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

    //说明: 一对一 、一对多和多对多都可以混合使用
     
    //list里面是多层级的对象  
    List<Student> list=new List<Student>();
    list.Add(new Student(){ 
                 Id=0,
                 Name="jack",
                 SchoolId=0,
                 SchoolA=new SchoolA(){...RoomList=new List<Room>{...}}, 
                 Books=new List<Books> {...} })
    
    db.InsertNav(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.InsertNav(List<StudentA>)
            .Include(z1 => z1.SchoolA)
            .ExecuteCommand();

4、一对多

 4.1 实体定义

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

 4.2 用例

逻辑有2种

 //不存在插入主表,强制插入子表 
 var List<StudentA> list=new List<StudentA>(){....};
 db.InsertNav(list)
            .Include(z1 => z1.Books)
            .ExecuteCommand();
  
 //5.1.1 preview13           
 //不存在插入主表,子表存在不插入,不存在插入
 var result = db.InsertNav(country)
         .Include(it =>it.Provinces,new InsertNavOptions()
                 {OneToManyIfExistsNoInsert=true })//配置存在不插入
         .ExecuteCommand();//用例代码
         
         
 //例如Items下面有 lefts和 rights 这个时候第二个Items 需要添加存在不插入,不然插入重复          
 db.InsertNav(main)
           .Include(it => it.Items)
           .ThenInclude(it => it.Lefts)
           .Include(it => it.Items,new  InsertNavOptions(){OneToManyIfExistsNoInsert=true })
           .ThenInclude(it => it.Rights)
           .ExecuteCommand();

5、多对多

 5.1 逻辑

主表不存在插入, 子表不存在插入 ,插入关系表(默认会清空中间表,下面配置支持不清空中间表)

   db.InsertNav(list)
            .Include(x => x.Roles, new InsertNavOptions()
             {
               ManyToManyNoDeleteMap = true//禁止清空中间表 新功能5.1.3.29-preview01
               
              }).ExecuteCommand();

 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.InsertNav(list)
            .Include(z1 => z1.BList)
            .ExecuteCommand();
            
//小技巧: 如果A和B主键存在可以只传主键,存在只用到主键不需要插入操作

 5.3 中间表额外字段赋值

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

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

                           }
                        })
         .ExecuteCommand();

6、主表配置功能:5.1.2.8

忽略列

  db.InsertNav(list,new InsertNavRootOptions()
            {
                IgnoreColumns = new string[] { "Id" }//InsertColumns也可以用只插入哪几列
            })
 .Include(x => x.Roles).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

8、雪花ID冲突

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

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

9、自动导航插入

新功能:5.1.4.108

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

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

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

看不懂吗?写个例子:

db.InsertNav(list)
     .Include(z1 => z1.SchoolA).ThenInclude(z1 => z1.RoomList) //插入2层 Root->ShoolA->RoomList
     .Include(z1 => z1.Books1)//插入1层 Root->Books1
     .Include(z1 => z1.Books2)//插入1层 Root->Books2
     .Include(z1 => z1.Books3)//插入1层 Root->Books3
     .Include(z1 => z1.Books4)//插入1层 Root->Books4
     .Include(z1 => z1.Books5)//插入1层 Root->Books5
     .ExecuteCommand();
     
//可以优化成
db.InsertNav(list)
        .IncludesAllFirstLayer()//自动2级
        .IncludeByNameString(nameof(类.SchoolA)).ThenIncludeByNameString(nameof(类.RoomList3))//3级
        .ExecuteCommand();


关闭
果糖网