一、基本配置
-
1、安装依赖包
需要安装3个依赖包,分别为
mysqlConnector、sqlSugar、autofac -
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、手动创建一个数据库表文件及手动创建一个数据模型
sqlCREATE 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 }); }