使用sqlSugar来操作mysql数据库

一、基本配置

  • 1、安装依赖包

    需要安装3个依赖包,分别为mysqlConnectorsqlSugarautofac

  • 2、在appsettings.json中配置mysql的连接信息

    json 复制代码
    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "MySqlConnection": "Server=localhost;Database=net_demo;Uid=root;Pwd=123456;Port=3306;SslMode=None;"
      }
    }
  • 3、在入口文件中创建连接

    参考官网地址,官网地址

    c# 复制代码
    using System.Text.Json;
    using Autofac;
    using Autofac.Extensions.DependencyInjection;
    using SqlSugar;
    using study_demo10_orm.Utils;
    
    namespace study_demo10_orm;
    
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);
    
            // 配置 JSON 序列化:long 类型序列化为字符串,避免 JavaScript 精度丢失
            builder.Services.AddControllers()
                .AddJsonOptions(options =>
                {
                    options.JsonSerializerOptions.NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.WriteAsString;
                });
            // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
            builder.Services.AddOpenApi();
            // 配置swagger
            builder.Services.AddEndpointsApiExplorer();
            builder.Services.AddSwaggerGen();
    
            // 配置数据库连接
            builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
            builder.Host.ConfigureContainer<ContainerBuilder>(container =>
            {
                // 使用Autofac 容器注册一个对象
                container.Register(_ =>
                {
                    var connectionString = builder.Configuration.GetConnectionString("MySqlConnection")
                        ?? "Server=localhost;Database=test;Uid=root;Pwd=123456;Port=3306;";
                    var db = new SqlSugarClient(new ConnectionConfig()
                    {
                        ConnectionString = connectionString, // 数据库地址字符串
                        DbType = DbType.MySql, // 指定数据库是mysql
                        IsAutoCloseConnection = true, // 自动关闭连接
                        InitKeyType = InitKeyType.Attribute,
                        MoreSettings = new ConnMoreSettings()
                        {
                            IsAutoRemoveDataCache = true // 数据变更时自动清理缓存
                        }
                    });
                    return db;
                }).As<ISqlSugarClient>().InstancePerLifetimeScope();
            });
    
            var app = builder.Build();
    
            // Configure the HTTP request pipeline.
            if (app.Environment.IsDevelopment())
            {
                app.MapOpenApi();
                // 配置swagger
                app.UseSwagger().UseSwaggerUI();
            }
    
            app.UseHttpsRedirection();
    
            app.UseAuthorization();
    
            app.MapControllers();
            // 配置打印日志
            app.Logger.LogInformation("程序已经启动,swagger地址:localhost:5179/swagger/index.html");
            app.Run();
        }
    }
  • 4、手动创建一个数据库表文件及手动创建一个数据模型

    sql 复制代码
    CREATE TABLE `account` (
      `id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',
      `username` varchar(50)  NOT NULL COMMENT '用户名',
      `password` varchar(255)  NOT NULL COMMENT '密码',
      `nickname` varchar(50)  DEFAULT NULL COMMENT '昵称',
      `avatar` varchar(255)  DEFAULT NULL COMMENT '头像',
      `email` varchar(100)  DEFAULT NULL COMMENT '邮箱',
      `phone` varchar(20)  DEFAULT NULL COMMENT '手机号',
      `status` bigint DEFAULT '1' COMMENT '状态 1正常 2禁用',
      `created_at` bigint DEFAULT NULL COMMENT '创建时间',
      `updated_at` bigint DEFAULT NULL COMMENT '更新时间',
      `deleted_at` datetime(3) DEFAULT NULL COMMENT '软删除',
      PRIMARY KEY (`id`),
      KEY `idx_account_deleted_at` (`deleted_at`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
    c# 复制代码
    using System;
    using SqlSugar;
    
    namespace Model.Entity
    {
        [SugarTable("account")]
        public class AccountEntity
        {
            /// <summary>
            /// 主键
            /// </summary>
            [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)]
            public long Id { get; set; }
    
            /// <summary>
            /// 用户名
            /// </summary>
            [SugarColumn(ColumnName = "username")]
            public string Username { get; set; }
    
            /// <summary>
            /// 密码
            /// </summary>
            [SugarColumn(ColumnName = "password")]
            public string Password { get; set; }
    
            /// <summary>
            /// 昵称
            /// </summary>
            [SugarColumn(ColumnName = "nickname")]
            public string Nickname { get; set; }
    
            /// <summary>
            /// 头像
            /// </summary>
            [SugarColumn(ColumnName = "avatar")]
            public string Avatar { get; set; }
    
            /// <summary>
            /// 邮箱
            /// </summary>
            [SugarColumn(ColumnName = "email")]
            public string Email { get; set; }
    
            /// <summary>
            /// 手机号
            /// </summary>
            [SugarColumn(ColumnName = "phone")]
            public string Phone { get; set; }
    
            /// <summary>
            /// 状态 1正常 2禁用
            /// </summary>
            [SugarColumn(ColumnName = "status")]
            public int? Status { get; set; }
    
            /// <summary>
            /// 创建时间
            /// </summary>
            [SugarColumn(ColumnName = "created_at")]
            public long? CreatedAt { get; set; }
    
            /// <summary>
            /// 更新时间
            /// </summary>
            [SugarColumn(ColumnName = "updated_at")]
            public long? UpdatedAt { get; set; }
    
            /// <summary>
            /// 软删除
            /// </summary>
            [SugarColumn(ColumnName = "deleted_at")]
            public DateTime? DeletedAt { get; set; }
    
        }
    }
  • 5、在控制器中使用SqlSugar来对数据库的操作

    c# 复制代码
    /// <summary>
    /// 账户管理接口
    /// </summary>
    [ApiController]
    [Route("api/[controller]")]
    [Produces("application/json")]
    public class AccountController : ControllerBase
    {
        private readonly ISqlSugarClient _db;
    
        /// <summary>
        /// 依赖注入
        /// </summary>
        public AccountController(ISqlSugarClient db)
        {
            _db = db;
        }
      
        /// <summary>
        /// 创建账户
        /// </summary>
        /// <param name="dto">创建账户的信息</param>
        /// <returns>新创建的账户ID</returns>
        /// <remarks>
        /// 示例请求:
        /// POST /api/account
        /// {
        ///     "username": "testuser",
        ///     "password": "123456",
        ///     "nickname": "测试用户",
        ///     "email": "test@example.com",
        ///     "phone": "13800138000",
        ///     "status": 1
        /// }
        /// </remarks>
        [HttpPost]
        [ProducesResponseType(typeof(ApiResult), StatusCodes.Status200OK)]
        [ProducesResponseType(typeof(ApiResult), StatusCodes.Status400BadRequest)]
        public async Task<ApiResult> Create([FromBody] CreateAccountDTO dto)
        {
            // 参数校验
            if (string.IsNullOrWhiteSpace(dto.Username))
            {
                return ResultHelper.Error("用户名不能为空");
            }
            if (string.IsNullOrWhiteSpace(dto.Password))
            {
                return ResultHelper.Error("密码不能为空");
            }
    
            // 检查用户名是否已存在
            var exists = await _db.Queryable<AccountEntity>()
                .Where(x => x.Username == dto.Username && x.DeletedAt == null)
                .AnyAsync();
            if (exists)
            {
                return ResultHelper.Error("用户名已存在");
            }
    
            // 创建实体
            var entity = new AccountEntity
            {
                Username = dto.Username,
                Password = dto.Password,
                Nickname = dto.Nickname,
                Avatar = dto.Avatar,
                Email = dto.Email,
                Phone = dto.Phone,
                Status = dto.Status ?? 1,
                CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds(),
                UpdatedAt = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
            };
    
            // 插入并获取返回的ID(雪花ID)
            var insertResult = await _db.Insertable(entity).ExecuteReturnEntityAsync();
            var id = insertResult.Id;
    
            return ResultHelper.Success(new { Id = id });
        }
    }

二、配置由数据库文件来生成对应的数据模型

  • 1、官网地址

  • 2、创建一个工具类

    c# 复制代码
    using System.Text;
    using SqlSugar;
    
    namespace study_demo10_orm.Utils;
    
    /// <summary>
    /// 代码生成器工具类
    /// 用于根据数据库表结构自动生成对应的实体类
    /// </summary>
    public class Generator
    {
        /// <summary>
        /// 生成实体类文件
        /// </summary>
        /// <param name="db">SqlSugar数据库实例</param>
        /// <param name="outputPath">输出目录路径</param>
        /// <param name="namespaceName">命名空间名称</param>
        /// <param name="tables">指定要生成的表名数组,为空则生成所有表</param>
        public static void GenerateEntities(ISqlSugarClient db, string outputPath, string namespaceName, params string[] tables)
        {
            // 确保输出目录存在,不存在则创建
            Directory.CreateDirectory(outputPath);
    
            // 获取要生成的表列表:如果指定了表名则使用指定表,否则获取所有表
            var tableList = tables?.Length > 0
                ? tables.ToList()
                : db.DbMaintenance.GetTableInfoList().Select(t => t.Name).ToList();
    
            // 遍历每个表生成对应的实体类
            foreach (var table in tableList)
            {
                // 获取表的所有列信息
                var columns = db.DbMaintenance.GetColumnInfosByTableName(table, false);
                // 将表名转换为PascalCase作为类名(如下划线转驼峰)
                var className = ToPascalCase(table) + "Entity";
    
                var sb = new StringBuilder();
    
                // 生成文件头部的警告注释(表示是自动生成的)
                sb.AppendLine("// <auto-generated />");
                sb.AppendLine("// 此文件由代码生成器自动创建,请勿手动修改!");
                sb.AppendLine();
                sb.AppendLine("using System;");
                sb.AppendLine("using SqlSugar;");
                sb.AppendLine();
                sb.AppendLine($"namespace {namespaceName}");
                sb.AppendLine("{");
    
                // 生成类声明和SugarTable特性
                sb.AppendLine($"    [SugarTable(\"{table}\")]");
                sb.AppendLine($"    public class {className}");
                sb.AppendLine("    {");
    
                // 遍历每列生成属性
                foreach (var col in columns)
                {
                    // 获取CLR类型和属性名
                    var clrType = GetClrType(col.DataType, col.IsNullable, col.DbColumnName);
                    var propertyName = ToPascalCase(col.DbColumnName);
    
                    // 添加XML文档注释(字段描述)
                    sb.AppendLine("        /// <summary>");
                    sb.AppendLine($"        /// {col.ColumnDescription}");
                    sb.AppendLine("        /// </summary>");
    
                    // 构建SugarColumn特性参数
                    var attrParts = new List<string>
                    {
                        $"ColumnName = \"{col.DbColumnName}\""
                    };
                    // 主键标记
                    if (col.IsPrimarykey) attrParts.Add("IsPrimaryKey = true");
    
                    // 注意:MySQL AUTO_INCREMENT 不需要 IsIdentity(那是雪花ID用的)
                    // 如果需要雪花ID,请在业务代码中手动设置
                    if (col.IsIdentity) attrParts.Add("IsIdentity = true");
    
                    // 输出SugarColumn特性
                    var attrStr = $"[SugarColumn({string.Join(", ", attrParts)})]";
                    sb.AppendLine($"        {attrStr}");
                    sb.AppendLine($"        public {clrType} {propertyName} {{ get; set; }}");
                    sb.AppendLine();
                }
    
                sb.AppendLine("    }");
                sb.AppendLine("}");
    
                // 写入文件
                var filePath = Path.Combine(outputPath, $"{className}.cs");
                File.WriteAllText(filePath, sb.ToString(), Encoding.UTF8);
    
                Console.WriteLine($"Generated: {className}.cs");
            }
    
            Console.WriteLine($"Total generated: {tableList.Count} files");
        }
    
        /// <summary>
        /// 将下划线/连字符命名转换为PascalCase命名
        /// 例如: user_info -> UserInfo, hello-world -> HelloWorld
        /// </summary>
        /// <param name="name">原始名称</param>
        /// <returns>转换后的PascalCase名称</returns>
        private static string ToPascalCase(string name)
        {
            if (string.IsNullOrWhiteSpace(name)) return name;
    
            // 按下划线和连字符分割
            var parts = name.Split(new[] { '_', '-' }, StringSplitOptions.RemoveEmptyEntries);
            // 将每部分首字母大写后拼接
            return string.Join("", parts.Select(p => char.ToUpper(p[0]) + p.Substring(1)));
        }
    
        /// <summary>
        /// 将数据库类型转换为C# CLR类型
        /// </summary>
        /// <param name="dbType">数据库中的数据类型</param>
        /// <param name="isNullable">是否可为空</param>
        /// <returns>C#类型名称</returns>
        private static string GetClrType(string dbType, bool isNullable, string columnName = "")
        {
            dbType = dbType.ToLower();
    
            // 根据数据库类型映射到CLR类型
            string result = dbType switch
            {
                "int" or "int unsigned" or "integer" => "int",
                "bigint" or "bigint unsigned" => "long",
                "tinyint" or "tinyint unsigned" => "int",
                "smallint" or "smallint unsigned" => "short",
                "bit" => "bool",
                "float" or "float unsigned" => "float",
                "double" or "double unsigned" => "double",
                "decimal" or "numeric" or "dec" or "fixed" => "decimal",
                "date" or "datetime" or "timestamp" or "time" => "DateTime",
                "char" or "varchar" or "text" or "longtext" or "mediumtext" or "tinytext" or "nchar" or "nvarchar" => "string",
                "blob" or "longblob" or "mediumblob" or "tinyblob" or "varbinary" or "binary" => "byte[]",
                _ => "string"
            };
    
            // 根据字段名推断类型(当数据库类型不准确时)
            var lowerName = columnName.ToLower();
            if (result == "long" && lowerName.Contains("status"))
            {
                result = "int";
            }
            // 注意:不再强制 id 为 long,使用数据库实际类型
    
            // 判断是否为值类型(值类型才能加可空标记?)
            var isValueType = result != "string" && result != "byte[]";
    
            // 值类型可空时加?后缀(如 int?)
            if (isNullable && isValueType) result += "?";
    
            return result;
        }
    }
  • 3、在入口文件里面配置这个

    C# 复制代码
    ...
      // 配置数据库生成模型的
      if (args.Contains("gen-model"))
      {
          using var scope = app.Services.CreateScope();
          var db = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
    
          // 获取项目根目录的相对路径 (从 bin/Debug/net10.0 回退3级)
          var projectRoot = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, "..", "..", ".."));
          var modelPath = Path.Combine(projectRoot, "Model", "Entity");
    
          Generator.GenerateEntities(
              db,
              outputPath: modelPath,
              namespaceName: "Model.Entity",
              tables: Array.Empty<string>()
          );
          return; 
      }
    ...
  • 4、配置Makefile文件方便一件来操作

    makefile 复制代码
    .PHONY: gen-model run
    
    # 生成数据库模型
    gen-model:
    	dotnet run --project . -- gen-model
    
    # 运行项目
    run:
    	dotnet run --project .

三、配置直接的时候输出打印的sql方便排查错误

  • 1、直接在入库配置地方配置

    c# 复制代码
    ...
      // 配置数据库连接
      builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
      builder.Host.ConfigureContainer<ContainerBuilder>(container =>
      {
          // 使用Autofac 容器注册一个对象
          container.Register(_ =>
          {
              var connectionString = builder.Configuration.GetConnectionString("MySqlConnection")
                  ?? "Server=localhost;Database=test;Uid=root;Pwd=123456;Port=3306;";
              var db = new SqlSugarClient(new ConnectionConfig()
              {
                  ConnectionString = connectionString, // 数据库地址字符串
                  DbType = DbType.MySql, // 指定数据库是mysql
                  IsAutoCloseConnection = true, // 自动关闭连接
                  InitKeyType = InitKeyType.Attribute,
                  MoreSettings = new ConnMoreSettings()
                  {
                      IsAutoRemoveDataCache = true // 数据变更时自动清理缓存
                  }
              });
    
              // 配置SQL日志打印(点击可跳转到执行文件)
              db.Aop.OnLogExecuting = (sql, pars) =>
              {
                  // 获取调用栈信息
                  var stackTrace = new System.Diagnostics.StackTrace(true);
                  var frames = stackTrace.GetFrames();
                  string? filePath = null;
                  int lineNumber = 0;
                  string? methodName = null;
    
                  if (frames.Length > 0)
                  {
                      // 打印所有帧用于调试(注释掉正常后)
                      // for (int i = 0; i < Math.Min(frames.Length, 15); i++)
                      // {
                      //     var frame = frames[i];
                      //     Console.WriteLine($"  Frame[{i}]: {frame.GetMethod()?.DeclaringType}.{frame.GetMethod()?.Name} at {frame.GetFileName()}:{frame.GetFileLineNumber()}");
                      // }
    
                      // 遍历找到第一个有文件信息的非 SqlSugar/Microsoft 帧
                      // 通常在 5-15 帧范围内能找到业务代码
                      for (int i = 0; i < frames.Length; i++)
                      {
                          var frame = frames[i];
                          var method = frame.GetMethod();
                          if (method == null) continue;
    
                          var declaringType = method.DeclaringType?.FullName ?? "";
                          var name = method.Name;
    
                          // 跳过内部框架类
                          if (declaringType.StartsWith("SqlSugar") ||
                              declaringType.StartsWith("Microsoft") ||
                              declaringType.StartsWith("System") ||
                              declaringType.StartsWith("Autofac"))
                          {
                              continue;
                          }
    
                          // 跳过编译器生成的匿名类和方法(如 lambda)
                          // 匿名方法通常名称包含 <> 或开头是 <
                          if (name.Contains('<') || name.Contains("<>"))
                          {
                              continue;
                          }
    
                          var fileName = frame.GetFileName();
                          var line = frame.GetFileLineNumber();
    
                          // 找到第一个有有效文件信息的帧
                          if (!string.IsNullOrEmpty(fileName))
                          {
                              filePath = fileName;
                              lineNumber = line > 0 ? line : 0;
                              methodName = $"{declaringType}.{name}";
                              break;
                          }
                      }
                  }
    
                  // Rider 格式输出: --> file.cs(line)
                  if (filePath != null && lineNumber > 0)
                  {
                      Console.WriteLine($" --> {filePath}({lineNumber}) [{methodName}]");
                  }
                  else if (filePath != null)
                  {
                      Console.WriteLine($" --> {filePath} [no line info] [{methodName}]");
                  }
    
                  // 打印可直接执行的SQL(将参数值替换到SQL中)
                  var executableSql = sql;
                  if (pars != null && pars.Length > 0)
                  {
                      foreach (var p in pars)
                      {
                          var value = p.Value;
                          if (value == null)
                          {
                              executableSql = executableSql.Replace(p.ParameterName, "NULL");
                          }
                          else if (value is string || value is DateTime)
                          {
                              executableSql = executableSql.Replace(p.ParameterName, $"'{value}'");
                          }
                          else
                          {
                              executableSql = executableSql.Replace(p.ParameterName, value.ToString() ?? "NULL");
                          }
                      }
                  }
                  Console.WriteLine($"SQL: {executableSql}");
                  Console.WriteLine();
              };
    
              // 错误日志
              db.Aop.OnError = (exp) =>
              {
                  Console.WriteLine($"SQL Error: {exp.Message}");
                  Console.WriteLine($"SQL: {exp.Sql}");
              };
    
              return db;
          }).As<ISqlSugarClient>().InstancePerLifetimeScope();
      });
    ...

四、设置创建时间和更新时间

  • 1、配置代码生成器中创建和更新时间字段

    c# 复制代码
    if (col.IsIdentity) attrParts.Add("IsIdentity = true");
    // 自动时间戳字段处理
    var lowerColName = col.DbColumnName.ToLower();
    if (lowerColName == "created_at")
    {
        // 创建时间:插入时自动填充
        attrParts.Add("InsertServerTime = true");
    }
    else if (lowerColName == "updated_at")
    {
        // 更新时间:插入和更新时自动填充
        attrParts.Add("InsertServerTime = true");
        attrParts.Add("UpdateServerTime = true");
    }
  • 2、重新生成的数据模型

    c# 复制代码
    /// <summary>
    /// 创建时间
    /// </summary>
    [SugarColumn(ColumnName = "created_at", InsertServerTime = true)]
    public DateTime CreatedAt { get; set; }
    
    /// <summary>
    /// 更新时间
    /// </summary>
    [SugarColumn(ColumnName = "updated_at", InsertServerTime = true, UpdateServerTime = true)]
    public DateTime UpdatedAt { get; set; }

五、配置逻辑删除字段

  • 1、定义一个接口

    c# 复制代码
    public interface ISoftDelete
    {
        DateTime? DeletedAt { get; set; }
    }
  • 2、自己定义的实体类都实现这个接口

    c# 复制代码
    namespace Model.Entity
    {
        [SugarTable("user")]
        public class UserEntity:ISoftDelete
        {
            /// <summary>
            /// 主键id
            /// </summary>
            [SugarColumn(ColumnName = "id", IsPrimaryKey = true, IsIdentity = true)]
            public int Id { get; set; }
        }
    }
  • 3、在入口文件中使用过滤器

    C# 复制代码
    // 配置逻辑删除
    db.QueryFilter.AddTableFilter<ISoftDelete>(it => it.DeletedAt == null);
  • 4、验证查询数据的时候,查看执行的sql,自动加上了逻辑删除的字段

    c# 复制代码
    [HttpGet("{id}")]
    public async Task<ApiResult> GetById(int id)
    {
        var task = await _db.Queryable<UserEntity>().Where(x=>x.Id==id).FirstAsync();
        return ResultHelper.Success(task);
    }
  • 5、如果想要查询逻辑删除的数据

    C# 复制代码
    [HttpGet("{id}")]
    public async Task<ApiResult> GetById(int id)
    {
        // var task = await _db.Queryable<UserEntity>().Where(x=>x.Id==id).FirstAsync();
        var task = await _db.Queryable<UserEntity>()
            .Filter(null,true)
            .Where(x=>x.Id==id)
            .FirstAsync();
        return ResultHelper.Success(task);
    }
  • 6、使用逻辑删除数据(这里要使用更新操作)

    c# 复制代码
    [HttpDelete("{id}")]
    public async Task<ApiResult> Delete(int id)
    {
        await _db.Updateable<UserEntity>()
            .SetColumns(it => it.DeletedAt == DateTime.Now)
            .Where(x => x.Id == id)
            .ExecuteCommandAsync();
    
        return ResultHelper.Success(new { Id = id });
    }
相关推荐
zandy10112 小时前
衡石科技 HENGSHI SENSE:一站式智能分析平台,让企业数据价值“所见即所得”
大数据·数据库·科技
fly spider2 小时前
MySQL日志篇
数据库·mysql
QC·Rex2 小时前
向量数据库对比与实战:从原理到生产落地
数据库·人工智能·向量数据库
Database_Cool_2 小时前
PolarDB分布式版 AI 助手正式上线:你的“数字DBA”已入职
数据库·阿里云·ai
一叶飘零_sweeeet2 小时前
MySQL 生产级备份与恢复全攻略:全量 / 增量 / 逻辑 / 物理备份深度拆解 + 误删数据秒级恢复实战
数据库·mysql·数据安全·数据备份
薛定谔的悦3 小时前
BMS Modbus RTU实现:从帧结构到寄存器映射的完整工程
linux·数据库·bms
The_Second_Coming3 小时前
MySQL 5.7 学习笔记
笔记·学习·mysql
light blue bird3 小时前
主从执行端动机模块工序协同组件
jvm·数据库·.net·桌面端
SPC的存折3 小时前
(自用)LNMP-Redis-Discuz5.0部署指南-openEuler24.03-测试环境
linux·运维·服务器·数据库·redis·缓存