• EF Core 7.0 新特性之批量修改


    概要

    EF Core 7.0 提供了一个可以将LINQ查询和批量修改相结合的方法ExecuteUpdate。由于数据修改是以批量更新的方式完成,所以可以减少数据库的往返次数。

    本文将主要介绍ExecuteUpdate的使用方法。

    代码和实现

    基本案例

    本文我们使用银行分行,ATM机和分行经理三张数据表,关系如下,类定义请见附录:

    1. 一个分行拥有若干台ATM机
    2. 一台ATM机只能隶属于一个分行
    3. 一个分行只拥有一名分行经理
    4. 一个人只能做一个分行的经理

    批量更新之单表操作

    我们在所有IsDeleted 为true,即已经关闭的分行, 将它们的名称前面加上字符串 Decommissioned

    EF CORE代码如下:

    public async Task<int> UpdateBranchSingleTable()
    {
        return await _context.Set<Branch>()
                .Where(b => b.IsDeleted == true)
                .ExecuteUpdateAsync(b => b.SetProperty(p => p.Name, m => "Decommissioned" +  m.Name + "!"));    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    生成的SQL代码如下:

    UPDATE [t]
    	SET [t].[Name] = (N'Decommissioned' + [t].[Name]) + N'!'
    	FROM [tt_branch] AS [t]
    WHERE [t].[IsDeleted] = CAST(1 AS bit)
    
    • 1
    • 2
    • 3
    • 4

    生成的是批量更新的SQL语句。

    批量更新之多表操作

    Case 1 查询拥有支持外币操作ATM机的分行,并将分行名称前面标注支持外币业务。

     public async Task<int> UpdateBranchFormMultipleTable()
     {
         return await _context.Set<Branch>()
                  .Where(b => b.IsDeleted == false && b.Atms.Any(a => a.SupportForeignCurrency == true))
                  .ExecuteUpdateAsync(b => b.SetProperty(p => p.Name, m => "Global Service " + m.Name));    
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    Case 2 查询分行经理title是BranchManager的分行,并将这些分行的名称前面增加Level 2。

     public async Task<int> UpdateBranchMultipleTables() {
         return await _context.Set<Branch>()
                 .Where(b => b.IsDeleted == false && b.Manager.Title == "BranchManager")
                 .ExecuteUpdateAsync(b => b.SetProperty(p => p.Name, m => "Level 2" + m.Name));
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    生成的SQL代码如下:

    UPDATE [t]
     	SET [t].[Name] = N'Level 2' + [t].[Name]
     	FROM [tt_branch] AS [t]
     	INNER JOIN [tt_user] AS [t0] ON [t].[Id] = [t0].[Id]
    WHERE [t].[IsDeleted] = CAST(0 AS bit) AND [t0].[Title] = N'BranchManager'
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们看到,SQL是基于联表操作以后再进行的过滤和更新。这样看,通过Dapple等半自动ORM框架,自己完成的SQL语句和通过EF Core生成的SQL没有任何区别。

    附录

    实体类定义

    public class Entity
    {
    	 [Key]
    	 [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    	 public int Id { get; set; }
    	 [Timestamp]
    	 public byte[]? Rowversion { get; set; }
    	 public bool IsDeleted { get; set; }
    }
    
     [Table("tt_branch")]
      public class Branch : Entity
      {
         [Required]
         public string Name { get; set; } = string.Empty;
         [Required]
         public string Address { get; set; } = string.Empty;
         [Required]
         public bool hasCreditCardService { get; set; } = false;
         [Required]
         public bool hasChequeService { get; set; } = false;
         public ICollection<ATM> Atms { get; } = new List<ATM>();
         public User Manager { get; set; } = null!;
    }
    public abstract class BankDevice : Entity
    {
    	 [Required]
    	 public string Name { get; set; } = string.Empty;
    	 [Required]
    	 public DeviceStatus DeviceStatus { get; set; } = DeviceStatus.Running;
     }
     [Table("tt_atm")]
     public class ATM : BankDevice
     {
         [Required]
         public bool SupportForeignCurrency { get; set; } = false;
     }
    public enum DeviceStatus
    {
        Running = 1,
        Standby,
        Maintance
    }
    
    [Table("tt_user")]
    public class User:Entity
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Title { get; set; }
        public Branch Branch { get; set; } = null!;
    }
    
    • 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
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52

    实体关系定义

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
          modelBuilder.Entity<Branch>()
              .HasMany(x => x.Atms)
              .WithOne()
              .HasForeignKey("BranchId")
              .IsRequired();
          modelBuilder.Entity<Branch>()
              .HasMany(x => x.Cdms)
              .WithOne()
              .HasForeignKey("BranchId")
              .IsRequired();
          modelBuilder.Entity<Branch>()
             .HasMany(x => x.MCAtms)
             .WithOne()
             .HasForeignKey("BranchId")
             .IsRequired();
    
          modelBuilder.Entity<Branch>()
           .HasOne(x => x.Manager)
           .WithOne(x => x.Branch)
           .HasForeignKey<Branch>();
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
  • 相关阅读:
    CSS 中的变量
    ROS机械臂 Movelt 学习笔记3 | kinect360相机(v1)相关配置
    常见数据库介绍对比之NoSQL非关系型数据库
    thinkphp6 入门教程合集(更新中)
    网络超时检测-11.9
    java selenium使用总结
    连小白都在用的电子期刊制作网站
    Talk | 香港科技大学博士生叶汉荣:面向2D/3D场景理解的多任务学习
    软件设计师_操作系统基本原理_学习笔记
    7-2 图着色问题
  • 原文地址:https://blog.csdn.net/weixin_43263355/article/details/133858509