C#教程

关注公众号 jb51net

关闭
首页 > 软件编程 > C#教程 > C# sqlSugar操作mysql数据库

C#使用sqlSugar操作mysql数据库的完整教程

作者:水痕01

这篇文章主要为大家详细介绍了使用C# sqlSugar进行MySQL数据库操作的基本配置流程,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

一、基本配置

1、安装依赖包

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

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

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "MySqlConnection": "Server=localhost;Database=net_demo;Uid=root;Pwd=123456;Port=3306;SslMode=None;"
  }
}

3、在入口文件中创建连接

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、手动创建一个数据库表文件及手动创建一个数据模型

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;
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来对数据库的操作

/// <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、创建一个工具类

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;
    }
}

2、在入口文件里面配置这个

...
  // 配置数据库生成模型的
  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; 
  }
...

3、配置Makefile文件方便一件来操作

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

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

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

...
  // 配置数据库连接
  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、配置代码生成器中创建和更新时间字段

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、重新生成的数据模型

/// <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、定义一个接口

public interface ISoftDelete
{
    DateTime? DeletedAt { get; set; }
}

2、自己定义的实体类都实现这个接口

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、在入口文件中使用过滤器

// 配置逻辑删除
db.QueryFilter.AddTableFilter<ISoftDelete>(it => it.DeletedAt == null);

4、验证查询数据的时候,查看执行的sql,自动加上了逻辑删除的字段

[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、如果想要查询逻辑删除的数据

[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、使用逻辑删除数据(这里要使用更新操作)

[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 });
}

到此这篇关于C#使用sqlSugar操作mysql数据库的完整教程的文章就介绍到这了,更多相关C# sqlSugar操作mysql数据库内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文