znlgis 博客

GIS开发与技术分享

第十五章:高级特性与最佳实践

目录


15.1 批量操作

15.1.1 Fastest批量插入

SqlSugar提供了极速批量插入功能:

public class FastestBulkInsert
{
    // Fastest模式:最快的批量插入
    public static void BulkInsertFastest()
    {
        var db = GetSqlSugarClient();
        
        // 准备大量数据
        var students = new List<Student>();
        for (int i = 0; i < 100000; i++)
        {
            students.Add(new Student
            {
                Name = $"Student{i}",
                Age = 18 + (i % 10),
                Email = $"student{i}@test.com",
                CreateTime = DateTime.Now
            });
        }
        
        var sw = Stopwatch.StartNew();
        
        // 使用Fastest模式(最快)
        db.Fastest<Student>().BulkCopy(students);
        
        sw.Stop();
        Console.WriteLine($"插入10万条数据耗时: {sw.ElapsedMilliseconds}ms");
    }
    
    // Fastest与普通插入性能对比
    public static void PerformanceComparison()
    {
        var db = GetSqlSugarClient();
        var students = GenerateTestData(10000);
        
        // 方式1:循环插入(最慢)
        var sw1 = Stopwatch.StartNew();
        foreach (var student in students)
        {
            db.Insertable(student).ExecuteCommand();
        }
        sw1.Stop();
        Console.WriteLine($"循环插入耗时: {sw1.ElapsedMilliseconds}ms");
        
        // 方式2:批量插入(较快)
        var sw2 = Stopwatch.StartNew();
        db.Insertable(students).ExecuteCommand();
        sw2.Stop();
        Console.WriteLine($"批量插入耗时: {sw2.ElapsedMilliseconds}ms");
        
        // 方式3:Fastest模式(最快)
        var sw3 = Stopwatch.StartNew();
        db.Fastest<Student>().BulkCopy(students);
        sw3.Stop();
        Console.WriteLine($"Fastest插入耗时: {sw3.ElapsedMilliseconds}ms");
    }
    
    // Fastest高级配置
    public static void FastestAdvancedConfig()
    {
        var db = GetSqlSugarClient();
        var students = GenerateTestData(50000);
        
        db.Fastest<Student>()
            .PageSize(10000)              // 每次处理10000条
            .AS("student_backup")         // 插入到备份表
            .BulkCopy(students);
    }
    
    // Fastest更新
    public static void FastestBulkUpdate()
    {
        var db = GetSqlSugarClient();
        
        // 先查询需要更新的数据
        var students = db.Queryable<Student>()
            .Where(s => s.Age < 20)
            .ToList();
        
        // 修改数据
        foreach (var student in students)
        {
            student.Age += 1;
        }
        
        // 批量更新
        db.Fastest<Student>().BulkUpdate(students);
    }
}

15.1.2 批量更新删除

public class BulkOperations
{
    // 批量更新
    public static void BulkUpdate()
    {
        var db = GetSqlSugarClient();
        
        // 方式1:根据条件批量更新
        db.Updateable<Student>()
            .SetColumns(s => new Student { Age = s.Age + 1 })
            .Where(s => s.ClassId == 1)
            .ExecuteCommand();
        
        // 方式2:批量更新实体列表
        var students = db.Queryable<Student>()
            .Where(s => s.Age < 18)
            .ToList();
        
        foreach (var student in students)
        {
            student.Age = 18;
        }
        
        db.Updateable(students).ExecuteCommand();
        
        // 方式3:使用Fastest批量更新
        db.Fastest<Student>().BulkUpdate(students);
    }
    
    // 批量删除
    public static void BulkDelete()
    {
        var db = GetSqlSugarClient();
        
        // 方式1:根据条件批量删除
        db.Deleteable<Student>()
            .Where(s => s.CreateTime < DateTime.Now.AddYears(-1))
            .ExecuteCommand();
        
        // 方式2:根据ID列表删除
        var ids = new List<int> { 1, 2, 3, 4, 5 };
        db.Deleteable<Student>()
            .In(ids)
            .ExecuteCommand();
        
        // 方式3:批量删除实体列表
        var students = db.Queryable<Student>()
            .Where(s => s.Status == 0)
            .ToList();
        
        db.Deleteable(students).ExecuteCommand();
    }
    
    // 批量Merge操作(插入或更新)
    public static void BulkMerge()
    {
        var db = GetSqlSugarClient();
        var students = GenerateTestData(1000);
        
        // SQL Server
        if (db.CurrentConnectionConfig.DbType == DbType.SqlServer)
        {
            db.Storageable(students)
                .ToStorage()
                .AsInsertable.ExecuteCommand();  // 插入不存在的
            
            db.Storageable(students)
                .ToStorage()
                .AsUpdateable.ExecuteCommand();  // 更新已存在的
        }
        
        // 或使用自定义逻辑
        foreach (var student in students)
        {
            var existing = db.Queryable<Student>()
                .First(s => s.Id == student.Id);
            
            if (existing == null)
            {
                db.Insertable(student).ExecuteCommand();
            }
            else
            {
                db.Updateable(student).ExecuteCommand();
            }
        }
    }
}

15.2 存储过程和函数

public class StoredProcedureExamples
{
    // 调用存储过程
    public static void CallStoredProcedure()
    {
        var db = GetSqlSugarClient();
        
        // 无参数存储过程
        db.Ado.UseStoredProcedure().GetDataTable("sp_GetAllStudents");
        
        // 带输入参数
        var parameters = new[]
        {
            new SugarParameter("@ClassId", 1)
        };
        var dt = db.Ado.UseStoredProcedure()
            .GetDataTable("sp_GetStudentsByClass", parameters);
        
        // 带输出参数
        var outParams = new[]
        {
            new SugarParameter("@ClassId", 1),
            new SugarParameter("@TotalCount", null, true) // 输出参数
        };
        db.Ado.UseStoredProcedure()
            .ExecuteCommand("sp_GetStudentCount", outParams);
        
        var totalCount = outParams[1].Value;
        Console.WriteLine($"总数: {totalCount}");
    }
    
    // 调用存储过程返回实体
    public static List<Student> CallStoredProcedureReturnEntity()
    {
        var db = GetSqlSugarClient();
        
        var parameters = new[]
        {
            new SugarParameter("@ClassId", 1)
        };
        
        return db.Ado.UseStoredProcedure()
            .SqlQuery<Student>("sp_GetStudentsByClass", parameters);
    }
    
    // 调用标量函数
    public static object CallScalarFunction()
    {
        var db = GetSqlSugarClient();
        
        var result = db.Ado.GetScalar(
            "SELECT dbo.fn_GetStudentCount(@ClassId)",
            new { ClassId = 1 });
        
        return result;
    }
    
    // 调用表值函数
    public static List<Student> CallTableValuedFunction()
    {
        var db = GetSqlSugarClient();
        
        var sql = "SELECT * FROM dbo.fn_GetStudentsByClass(@ClassId)";
        return db.Ado.SqlQuery<Student>(sql, new { ClassId = 1 });
    }
    
    // 创建存储过程
    public static void CreateStoredProcedure()
    {
        var db = GetSqlSugarClient();
        
        var sql = @"
            CREATE PROCEDURE sp_InsertStudent
                @Name NVARCHAR(50),
                @Age INT,
                @Email NVARCHAR(100),
                @NewId INT OUTPUT
            AS
            BEGIN
                INSERT INTO Student (Name, Age, Email, CreateTime)
                VALUES (@Name, @Age, @Email, GETDATE())
                
                SET @NewId = SCOPE_IDENTITY()
            END
        ";
        
        db.Ado.ExecuteCommand(sql);
    }
}

15.3 视图支持

// 定义视图实体
[SugarTable("v_student_class")]
public class StudentClassView
{
    public int StudentId { get; set; }
    public string StudentName { get; set; }
    public int Age { get; set; }
    public string ClassName { get; set; }
    public string TeacherName { get; set; }
}

public class ViewExamples
{
    // 查询视图
    public static List<StudentClassView> QueryView()
    {
        var db = GetSqlSugarClient();
        
        return db.Queryable<StudentClassView>()
            .Where(v => v.Age > 18)
            .ToList();
    }
    
    // 创建视图
    public static void CreateView()
    {
        var db = GetSqlSugarClient();
        
        var sql = @"
            CREATE VIEW v_student_class AS
            SELECT 
                s.Id AS StudentId,
                s.Name AS StudentName,
                s.Age,
                c.Name AS ClassName,
                t.Name AS TeacherName
            FROM Student s
            INNER JOIN Class c ON s.ClassId = c.Id
            INNER JOIN Teacher t ON c.TeacherId = t.Id
        ";
        
        db.Ado.ExecuteCommand(sql);
    }
    
    // 使用SqlFunc查询视图
    public static void QueryViewWithSqlFunc()
    {
        var db = GetSqlSugarClient();
        
        var result = db.Queryable<StudentClassView>()
            .Where(v => SqlFunc.IsNullOrEmpty(v.TeacherName) == false)
            .Select(v => new
            {
                v.StudentName,
                v.ClassName,
                v.TeacherName
            })
            .ToList();
    }
}

15.4 临时表

public class TempTableExamples
{
    // 创建临时表
    public static void CreateTempTable()
    {
        var db = GetSqlSugarClient();
        
        // SQL Server临时表
        db.Ado.ExecuteCommand(@"
            CREATE TABLE #TempStudent (
                Id INT,
                Name NVARCHAR(50),
                Age INT
            )
        ");
        
        // 插入数据到临时表
        db.Ado.ExecuteCommand(@"
            INSERT INTO #TempStudent (Id, Name, Age)
            SELECT Id, Name, Age FROM Student WHERE Age > 18
        ");
        
        // 查询临时表
        var result = db.Ado.SqlQuery<Student>("SELECT * FROM #TempStudent");
        
        // 临时表会在连接关闭时自动删除
    }
    
    // 使用表变量(SQL Server)
    public static void UseTableVariable()
    {
        var db = GetSqlSugarClient();
        
        var sql = @"
            DECLARE @TempTable TABLE (
                Id INT,
                Name NVARCHAR(50),
                Age INT
            )
            
            INSERT INTO @TempTable
            SELECT Id, Name, Age FROM Student WHERE Age > 18
            
            SELECT * FROM @TempTable
        ";
        
        var result = db.Ado.SqlQuery<Student>(sql);
    }
    
    // CTE(公共表表达式)
    public static void UseCTE()
    {
        var db = GetSqlSugarClient();
        
        var sql = @"
            WITH StudentCTE AS (
                SELECT Id, Name, Age, ClassId
                FROM Student
                WHERE Age > 18
            )
            SELECT s.*, c.Name AS ClassName
            FROM StudentCTE s
            INNER JOIN Class c ON s.ClassId = c.Id
        ";
        
        var result = db.Ado.SqlQuery<dynamic>(sql);
    }
}

15.5 XML和JSON支持

public class XmlJsonExamples
{
    // JSON列操作(PostgreSQL, MySQL 5.7+)
    public static void JsonColumnOperations()
    {
        var db = GetSqlSugarClient();
        
        // 查询JSON字段
        var sql = @"
            SELECT * FROM student 
            WHERE JSON_EXTRACT(ext_data, '$.city') = '北京'
        ";
        var result = db.Ado.SqlQuery<Student>(sql);
        
        // 更新JSON字段
        db.Ado.ExecuteCommand(@"
            UPDATE student 
            SET ext_data = JSON_SET(ext_data, '$.city', '上海')
            WHERE id = 1
        ");
    }
    
    // 序列化为JSON
    public static void SerializeToJson()
    {
        var db = GetSqlSugarClient();
        
        var students = db.Queryable<Student>().ToList();
        var json = JsonConvert.SerializeObject(students, Formatting.Indented);
        
        Console.WriteLine(json);
        File.WriteAllText("students.json", json);
    }
    
    // 从JSON导入
    public static void ImportFromJson()
    {
        var db = GetSqlSugarClient();
        
        var json = File.ReadAllText("students.json");
        var students = JsonConvert.DeserializeObject<List<Student>>(json);
        
        db.Insertable(students).ExecuteCommand();
    }
    
    // XML操作(SQL Server)
    public static void XmlOperations()
    {
        var db = GetSqlSugarClient();
        
        // 查询返回XML
        var xml = db.Ado.GetString(@"
            SELECT Id, Name, Age
            FROM Student
            FOR XML AUTO, ROOT('Students')
        ");
        
        Console.WriteLine(xml);
        
        // 从XML导入
        db.Ado.ExecuteCommand(@"
            DECLARE @xml XML = '<Students>
                <Student><Name>张三</Name><Age>18</Age></Student>
                <Student><Name>李四</Name><Age>20</Age></Student>
            </Students>'
            
            INSERT INTO Student (Name, Age)
            SELECT 
                T.c.value('Name[1]', 'NVARCHAR(50)'),
                T.c.value('Age[1]', 'INT')
            FROM @xml.nodes('/Students/Student') T(c)
        ");
    }
}

15.6 设计模式

// 1. 单例模式
public class DatabaseSingleton
{
    private static SqlSugarClient _instance;
    private static readonly object _lock = new object();
    
    public static SqlSugarClient Instance
    {
        get
        {
            if (_instance == null)
            {
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = new SqlSugarClient(new ConnectionConfig
                        {
                            ConnectionString = "...",
                            DbType = DbType.SqlServer,
                            IsAutoCloseConnection = true
                        });
                    }
                }
            }
            return _instance;
        }
    }
}

// 2. 工厂模式
public interface IDatabaseFactory
{
    SqlSugarClient CreateDatabase(string dbType);
}

public class DatabaseFactory : IDatabaseFactory
{
    private readonly IConfiguration _configuration;
    
    public DatabaseFactory(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    
    public SqlSugarClient CreateDatabase(string dbType)
    {
        var connectionString = _configuration.GetConnectionString(dbType);
        
        var config = new ConnectionConfig
        {
            ConnectionString = connectionString,
            DbType = GetDbType(dbType),
            IsAutoCloseConnection = true
        };
        
        return new SqlSugarClient(config);
    }
    
    private DbType GetDbType(string dbType)
    {
        return dbType.ToLower() switch
        {
            "mysql" => DbType.MySql,
            "sqlserver" => DbType.SqlServer,
            "postgresql" => DbType.PostgreSQL,
            _ => throw new NotSupportedException()
        };
    }
}

// 3. 策略模式
public interface IQueryStrategy<T>
{
    List<T> Execute(SqlSugarClient db);
}

public class ActiveStudentsStrategy : IQueryStrategy<Student>
{
    public List<Student> Execute(SqlSugarClient db)
    {
        return db.Queryable<Student>()
            .Where(s => s.Status == 1)
            .ToList();
    }
}

public class GraduatedStudentsStrategy : IQueryStrategy<Student>
{
    public List<Student> Execute(SqlSugarClient db)
    {
        return db.Queryable<Student>()
            .Where(s => s.Status == 2)
            .ToList();
    }
}

// 4. 装饰器模式
public class LoggingRepositoryDecorator<T> : IRepository<T> where T : class, new()
{
    private readonly IRepository<T> _repository;
    private readonly ILogger _logger;
    
    public LoggingRepositoryDecorator(IRepository<T> repository, ILogger logger)
    {
        _repository = repository;
        _logger = logger;
    }
    
    public T GetById(object id)
    {
        _logger.LogInformation($"Getting {typeof(T).Name} by id: {id}");
        var result = _repository.GetById(id);
        _logger.LogInformation($"Retrieved {typeof(T).Name}: {result != null}");
        return result;
    }
    
    public int Insert(T entity)
    {
        _logger.LogInformation($"Inserting {typeof(T).Name}");
        var result = _repository.Insert(entity);
        _logger.LogInformation($"Inserted {typeof(T).Name} with id: {result}");
        return result;
    }
    
    // 实现其他方法...
}

// 5. 建造者模式
public class QueryBuilder<T> where T : class, new()
{
    private readonly SqlSugarClient _db;
    private ISugarQueryable<T> _queryable;
    
    public QueryBuilder(SqlSugarClient db)
    {
        _db = db;
        _queryable = db.Queryable<T>();
    }
    
    public QueryBuilder<T> Where(Expression<Func<T, bool>> expression)
    {
        _queryable = _queryable.Where(expression);
        return this;
    }
    
    public QueryBuilder<T> OrderBy(Expression<Func<T, object>> expression)
    {
        _queryable = _queryable.OrderBy(expression);
        return this;
    }
    
    public QueryBuilder<T> Take(int count)
    {
        _queryable = _queryable.Take(count);
        return this;
    }
    
    public List<T> Build()
    {
        return _queryable.ToList();
    }
}

// 使用
var students = new QueryBuilder<Student>(db)
    .Where(s => s.Age > 18)
    .OrderBy(s => s.Name)
    .Take(10)
    .Build();

15.7 错误处理

public class ErrorHandlingExamples
{
    // 全局错误处理
    public static void ConfigureGlobalErrorHandling(SqlSugarClient db)
    {
        db.Aop.OnError = (exp) =>
        {
            // 记录错误日志
            Logger.LogError(exp, "SQL执行错误");
            
            // 发送错误通知
            if (IsCriticalError(exp))
            {
                SendErrorNotification(exp);
            }
            
            // 根据错误类型处理
            if (exp.Message.Contains("timeout"))
            {
                // 处理超时错误
                HandleTimeoutError(exp);
            }
            else if (exp.Message.Contains("deadlock"))
            {
                // 处理死锁错误
                HandleDeadlockError(exp);
            }
        };
    }
    
    // 重试机制
    public static T ExecuteWithRetry<T>(Func<T> operation, int maxRetries = 3)
    {
        int retries = 0;
        
        while (true)
        {
            try
            {
                return operation();
            }
            catch (Exception ex)
            {
                retries++;
                
                if (retries >= maxRetries)
                {
                    Logger.LogError(ex, $"操作失败,已重试{maxRetries}次");
                    throw;
                }
                
                // 判断是否为可重试的错误
                if (!IsRetriableError(ex))
                {
                    throw;
                }
                
                // 指数退避
                var delay = TimeSpan.FromSeconds(Math.Pow(2, retries));
                Logger.LogWarning($"操作失败,{delay.TotalSeconds}秒后重试(第{retries}次)");
                Thread.Sleep(delay);
            }
        }
    }
    
    // 事务错误处理
    public static bool ExecuteInTransaction(SqlSugarClient db, Action operation)
    {
        try
        {
            db.BeginTran();
            operation();
            db.CommitTran();
            return true;
        }
        catch (Exception ex)
        {
            db.RollbackTran();
            Logger.LogError(ex, "事务执行失败");
            return false;
        }
    }
    
    // 自定义异常
    public class DatabaseException : Exception
    {
        public string Sql { get; set; }
        public object[] Parameters { get; set; }
        
        public DatabaseException(string message, string sql, object[] parameters)
            : base(message)
        {
            Sql = sql;
            Parameters = parameters;
        }
    }
    
    // 验证异常
    public class ValidationException : Exception
    {
        public Dictionary<string, string> Errors { get; set; }
        
        public ValidationException(string message) : base(message)
        {
            Errors = new Dictionary<string, string>();
        }
        
        public ValidationException(Dictionary<string, string> errors)
            : base("验证失败")
        {
            Errors = errors;
        }
    }
    
    private static bool IsCriticalError(SqlSugarException exp)
    {
        return exp.Message.Contains("connection") || 
               exp.Message.Contains("login");
    }
    
    private static bool IsRetriableError(Exception ex)
    {
        return ex.Message.Contains("timeout") || 
               ex.Message.Contains("deadlock");
    }
    
    private static void HandleTimeoutError(SqlSugarException exp)
    {
        Logger.LogWarning($"SQL超时: {exp.Sql}");
    }
    
    private static void HandleDeadlockError(SqlSugarException exp)
    {
        Logger.LogWarning($"发生死锁: {exp.Sql}");
    }
    
    private static void SendErrorNotification(SqlSugarException exp)
    {
        // 发送邮件或其他通知
    }
}

15.8 测试策略

// 单元测试
public class StudentRepositoryTests
{
    private Mock<ISqlSugarClient> _mockDb;
    private StudentRepository _repository;
    
    [SetUp]
    public void Setup()
    {
        _mockDb = new Mock<ISqlSugarClient>();
        _repository = new StudentRepository(_mockDb.Object);
    }
    
    [Test]
    public void GetById_ShouldReturnStudent()
    {
        // Arrange
        var expectedStudent = new Student { Id = 1, Name = "Test" };
        
        _mockDb.Setup(db => db.Queryable<Student>())
            .Returns(new MockQueryable<Student>(new[] { expectedStudent }));
        
        // Act
        var result = _repository.GetById(1);
        
        // Assert
        Assert.AreEqual(expectedStudent.Id, result.Id);
        Assert.AreEqual(expectedStudent.Name, result.Name);
    }
    
    [Test]
    public void Insert_ShouldReturnNewId()
    {
        // Arrange
        var student = new Student { Name = "New Student" };
        var expectedId = 1;
        
        _mockDb.Setup(db => db.Insertable(student).ExecuteReturnIdentity())
            .Returns(expectedId);
        
        // Act
        var result = _repository.Insert(student);
        
        // Assert
        Assert.AreEqual(expectedId, result);
    }
}

// 集成测试
public class StudentServiceIntegrationTests
{
    private SqlSugarClient _db;
    private StudentService _service;
    
    [SetUp]
    public void Setup()
    {
        // 使用测试数据库
        _db = new SqlSugarClient(new ConnectionConfig
        {
            ConnectionString = "Server=.;Database=TestDB;...",
            DbType = DbType.SqlServer,
            IsAutoCloseConnection = true
        });
        
        // 创建测试表
        _db.CodeFirst.InitTables<Student>();
        
        _service = new StudentService(new StudentRepository(_db), null, null);
    }
    
    [TearDown]
    public void TearDown()
    {
        // 清理测试数据
        _db.Deleteable<Student>().Where("1=1").ExecuteCommand();
    }
    
    [Test]
    public void CreateAndGetStudent_ShouldWork()
    {
        // Arrange
        var dto = new CreateStudentDto
        {
            Name = "Test Student",
            Age = 18,
            Email = "test@test.com"
        };
        
        // Act
        var id = _service.Create(dto);
        var result = _service.GetById(id);
        
        // Assert
        Assert.IsNotNull(result);
        Assert.AreEqual(dto.Name, result.Name);
        Assert.AreEqual(dto.Age, result.Age);
    }
}

// 性能测试
public class PerformanceTests
{
    [Test]
    public void BulkInsert_ShouldBePerformant()
    {
        var db = GetTestDatabase();
        var students = GenerateTestData(10000);
        
        var sw = Stopwatch.StartNew();
        db.Fastest<Student>().BulkCopy(students);
        sw.Stop();
        
        // 断言:10000条记录应该在2秒内完成
        Assert.Less(sw.ElapsedMilliseconds, 2000);
    }
    
    [Test]
    public void QueryWithIndex_ShouldBePerformant()
    {
        var db = GetTestDatabase();
        
        // 插入测试数据
        var students = GenerateTestData(100000);
        db.Fastest<Student>().BulkCopy(students);
        
        // 创建索引
        db.DbMaintenance.CreateIndex("student", "idx_name", "Name");
        
        var sw = Stopwatch.StartNew();
        var result = db.Queryable<Student>()
            .Where(s => s.Name == "Test")
            .ToList();
        sw.Stop();
        
        // 断言:有索引的查询应该很快
        Assert.Less(sw.ElapsedMilliseconds, 100);
    }
}

15.9 部署考虑

public class DeploymentConsiderations
{
    // 配置管理
    public static void ConfigurationManagement()
    {
        // 从配置文件读取
        var builder = new ConfigurationBuilder()
            .AddJsonFile("appsettings.json")
            .AddEnvironmentVariables();
        
        var configuration = builder.Build();
        
        var connectionString = configuration.GetConnectionString("DefaultConnection");
        var dbType = configuration["Database:Type"];
        
        var db = new SqlSugarClient(new ConnectionConfig
        {
            ConnectionString = connectionString,
            DbType = dbType == "MySQL" ? DbType.MySql : DbType.SqlServer,
            IsAutoCloseConnection = true
        });
    }
    
    // 连接池配置
    public static void ConnectionPooling()
    {
        var config = new ConnectionConfig
        {
            ConnectionString = "Server=.;Database=test;...",
            DbType = DbType.SqlServer,
            IsAutoCloseConnection = true,
            
            // 连接池配置
            MoreSettings = new ConnMoreSettings
            {
                IsAutoRemoveDataCache = true,
                SqlServerCodeFirstNvarchar = true
            }
        };
        
        // 使用SqlSugarScope支持多线程
        var db = new SqlSugarScope(config);
    }
    
    // 数据库迁移
    public static void DatabaseMigration()
    {
        var db = GetDatabase();
        
        // 1. 检查表是否存在
        if (!db.DbMaintenance.IsAnyTable("student", false))
        {
            // 2. 创建表
            db.CodeFirst.InitTables<Student>();
        }
        
        // 3. 检查列是否存在
        if (!db.DbMaintenance.IsAnyColumn("student", "Email"))
        {
            // 4. 添加列
            db.DbMaintenance.AddColumn("student", new DbColumnInfo
            {
                DbColumnName = "Email",
                DataType = "varchar(100)"
            });
        }
        
        // 5. 数据迁移
        MigrateData(db);
    }
    
    // 版本控制
    public class DatabaseVersion
    {
        public int Version { get; set; }
        public string Description { get; set; }
        public DateTime AppliedDate { get; set; }
    }
    
    public static void ApplyMigrations(SqlSugarClient db)
    {
        // 创建版本表
        if (!db.DbMaintenance.IsAnyTable("__migrations", false))
        {
            db.CodeFirst.InitTables<DatabaseVersion>();
        }
        
        // 获取当前版本
        var currentVersion = db.Queryable<DatabaseVersion>()
            .OrderBy(v => v.Version, OrderByType.Desc)
            .Select(v => v.Version)
            .FirstOrDefault();
        
        // 应用新迁移
        var migrations = GetPendingMigrations(currentVersion);
        
        foreach (var migration in migrations)
        {
            migration.Execute(db);
            
            db.Insertable(new DatabaseVersion
            {
                Version = migration.Version,
                Description = migration.Description,
                AppliedDate = DateTime.Now
            }).ExecuteCommand();
        }
    }
    
    // 健康检查
    public static bool HealthCheck(SqlSugarClient db)
    {
        try
        {
            // 执行简单查询
            db.Ado.GetInt("SELECT 1");
            return true;
        }
        catch
        {
            return false;
        }
    }
}

15.10 综合最佳实践

public class BestPractices
{
    // 1. 使用using语句确保资源释放
    public static void UseUsingStatement()
    {
        using (var db = new SqlSugarClient(new ConnectionConfig { ... }))
        {
            var students = db.Queryable<Student>().ToList();
        }
        // db会自动释放
    }
    
    // 2. 使用参数化查询防止SQL注入
    public static void UseParameterizedQuery()
    {
        var db = GetDatabase();
        var name = "'; DROP TABLE Student; --";
        
        // ❌ 错误:字符串拼接
        // var sql = $"SELECT * FROM Student WHERE Name = '{name}'";
        
        // ✅ 正确:参数化查询
        var students = db.Queryable<Student>()
            .Where(s => s.Name == name)
            .ToList();
    }
    
    // 3. 合理使用事务
    public static void UseTransactionsProperly()
    {
        var db = GetDatabase();
        
        try
        {
            db.BeginTran();
            
            // 执行多个相关操作
            db.Insertable(new Order()).ExecuteCommand();
            db.Insertable(new OrderItem()).ExecuteCommand();
            db.Updateable<Product>().ExecuteCommand();
            
            db.CommitTran();
        }
        catch
        {
            db.RollbackTran();
            throw;
        }
    }
    
    // 4. 避免N+1查询
    public static void AvoidNPlusOneQueries()
    {
        var db = GetDatabase();
        
        // ❌ 错误:N+1查询
        var students = db.Queryable<Student>().ToList();
        foreach (var student in students)
        {
            var @class = db.Queryable<Class>()
                .First(c => c.Id == student.ClassId);  // N次查询
        }
        
        // ✅ 正确:使用Include或Join
        var studentsWithClass = db.Queryable<Student>()
            .Includes(s => s.Class)
            .ToList();
    }
    
    // 5. 使用异步操作提高性能
    public static async Task<List<Student>> UseAsyncOperations()
    {
        var db = GetDatabase();
        
        return await db.Queryable<Student>()
            .Where(s => s.Age > 18)
            .ToListAsync();
    }
    
    // 6. 合理使用缓存
    public static void UseCachingWisely()
    {
        var db = GetDatabase();
        
        // 对不常变化的数据使用缓存
        var countries = db.Queryable<Country>()
            .WithCache(3600)  // 缓存1小时
            .ToList();
        
        // 对频繁变化的数据不使用缓存
        var orders = db.Queryable<Order>()
            .Where(o => o.CreateTime >= DateTime.Today)
            .ToList();  // 不缓存
    }
    
    // 7. 只查询需要的字段
    public static void SelectOnlyNeededColumns()
    {
        var db = GetDatabase();
        
        // ❌ 错误:查询所有字段
        var students = db.Queryable<Student>().ToList();
        
        // ✅ 正确:只查询需要的字段
        var studentNames = db.Queryable<Student>()
            .Select(s => new { s.Id, s.Name })
            .ToList();
    }
    
    // 8. 使用分页避免大量数据
    public static void UsePaginationForLargeDatasets()
    {
        var db = GetDatabase();
        
        int totalCount = 0;
        var pageData = db.Queryable<Student>()
            .ToPageList(1, 100, ref totalCount);
    }
    
    // 9. 配置日志记录
    public static void ConfigureLogging()
    {
        var db = new SqlSugarClient(new ConnectionConfig
        {
            // ...
            IsAutoCloseConnection = true,
            
            // 只在开发环境记录SQL
#if DEBUG
            AopEvents = new AopEvents
            {
                OnLogExecuting = (sql, pars) =>
                {
                    Console.WriteLine(sql);
                }
            }
#endif
        });
    }
    
    // 10. 使用工作单元模式
    public static void UseUnitOfWorkPattern()
    {
        using (var uow = new UnitOfWork(GetDatabase()))
        {
            try
            {
                uow.BeginTran();
                
                var studentRepo = uow.GetRepository<Student>();
                var classRepo = uow.GetRepository<Class>();
                
                studentRepo.Insert(new Student());
                classRepo.Update(new Class());
                
                uow.CommitTran();
            }
            catch
            {
                uow.RollbackTran();
                throw;
            }
        }
    }
}

// 完整的最佳实践示例
public class CompleteExample
{
    private readonly ILogger<CompleteExample> _logger;
    private readonly IUnitOfWork _unitOfWork;
    private readonly IMapper _mapper;
    
    public CompleteExample(
        ILogger<CompleteExample> logger,
        IUnitOfWork unitOfWork,
        IMapper mapper)
    {
        _logger = logger;
        _unitOfWork = unitOfWork;
        _mapper = mapper;
    }
    
    public async Task<PageResult<StudentDto>> GetStudentsAsync(StudentQueryDto query)
    {
        try
        {
            _logger.LogInformation("查询学生列表");
            
            var repository = _unitOfWork.GetRepository<Student>();
            
            var queryable = _unitOfWork.Db.Queryable<Student>()
                .WhereIF(!string.IsNullOrEmpty(query.Keyword),
                    s => s.Name.Contains(query.Keyword))
                .WhereIF(query.ClassId.HasValue,
                    s => s.ClassId == query.ClassId)
                .OrderBy(s => s.CreateTime, OrderByType.Desc);
            
            int totalCount = 0;
            var list = await queryable
                .ToPageListAsync(query.PageIndex, query.PageSize, ref totalCount);
            
            var dtos = _mapper.Map<List<StudentDto>>(list);
            
            return new PageResult<StudentDto>
            {
                PageIndex = query.PageIndex,
                PageSize = query.PageSize,
                TotalCount = totalCount,
                Items = dtos
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "查询学生列表失败");
            throw;
        }
    }
}

15.11 教程系列总结

通过本系列15章的学习,我们完整地学习了SqlSugar ORM框架:

基础篇(第1-5章)

  • 第一章:了解了SqlSugar的特点和安装配置
  • 第二章:掌握了实体配置和CodeFirst
  • 第三章:学会了基础的CRUD操作
  • 第四章:深入学习了查询功能
  • 第五章:掌握了高级查询技巧

进阶篇(第6-10章)

  • 第六章:学会了复杂的多表查询和连接
  • 第七章:掌握了事务处理
  • 第八章:理解了导航属性和延迟加载
  • 第九章:学会了分页查询和性能优化
  • 第十章:掌握了分表分库和多租户架构

高级篇(第11-15章)

  • 第十一章:实现了AOP和日志监控
  • 第十二章:掌握了DbFirst和代码生成
  • 第十三章:学会了多数据库支持
  • 第十四章:理解了仓储模式和依赖注入
  • 第十五章:学习了高级特性和最佳实践

核心知识点回顾

// 1. 连接配置
var db = new SqlSugarClient(new ConnectionConfig
{
    ConnectionString = "...",
    DbType = DbType.SqlServer,
    IsAutoCloseConnection = true
});

// 2. 实体定义
[SugarTable("student")]
public class Student
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
    public int Id { get; set; }
    
    [SugarColumn(Length = 50, IsNullable = false)]
    public string Name { get; set; }
}

// 3. 基础操作
// 插入
db.Insertable(student).ExecuteCommand();

// 查询
db.Queryable<Student>().ToList();

// 更新
db.Updateable(student).ExecuteCommand();

// 删除
db.Deleteable<Student>().Where(s => s.Id == 1).ExecuteCommand();

// 4. 复杂查询
var result = db.Queryable<Student>()
    .LeftJoin<Class>((s, c) => s.ClassId == c.Id)
    .Where(s => s.Age > 18)
    .OrderBy(s => s.CreateTime, OrderByType.Desc)
    .Select((s, c) => new { s.Name, c.ClassName })
    .ToList();

// 5. 事务
db.Ado.BeginTran();
try
{
    db.Insertable(student).ExecuteCommand();
    db.Insertable(@class).ExecuteCommand();
    db.Ado.CommitTran();
}
catch
{
    db.Ado.RollbackTran();
}

// 6. 分页
int total = 0;
var pageData = db.Queryable<Student>()
    .ToPageList(1, 20, ref total);

// 7. 导航属性
var students = db.Queryable<Student>()
    .Includes(s => s.Class)
    .ToList();

// 8. 仓储模式
public interface IRepository<T>
{
    T GetById(object id);
    int Insert(T entity);
    bool Update(T entity);
    bool Delete(object id);
}

学习建议

  1. 循序渐进:从基础CRUD开始,逐步学习高级特性
  2. 动手实践:每个知识点都要亲自编写代码验证
  3. 阅读文档:官方文档是最权威的参考资料
  4. 参与社区:在GitHub和论坛上与其他开发者交流
  5. 关注更新:SqlSugar持续更新,关注新特性
  6. 性能优化:始终关注查询性能和最佳实践
  7. 安全第一:注意SQL注入防护和数据安全
  8. 代码规范:遵循良好的编码规范和设计模式

实际项目应用

在实际项目中使用SqlSugar的建议:

// 1. 项目结构
/*
MyProject
├── MyProject.Models        // 实体模型
├── MyProject.Repository    // 数据访问层
├── MyProject.Service       // 业务逻辑层
├── MyProject.Api           // API层
└── MyProject.Tests         // 测试项目
*/

// 2. 依赖注入配置
public void ConfigureServices(IServiceCollection services)
{
    // 注册SqlSugar
    services.AddSingleton<ISqlSugarClient>(provider => { ... });
    
    // 注册仓储
    services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
    
    // 注册服务
    services.AddScoped<IStudentService, StudentService>();
}

// 3. 统一返回格式
public class ApiResult<T>
{
    public bool Success { get; set; }
    public string Message { get; set; }
    public T Data { get; set; }
    public int Code { get; set; }
}

// 4. 统一异常处理
public class GlobalExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        var result = new ApiResult<object>
        {
            Success = false,
            Message = context.Exception.Message,
            Code = 500
        };
        
        context.Result = new JsonResult(result);
    }
}

15.12 本章小结

本章作为教程的最后一章,介绍了SqlSugar的高级特性和最佳实践:

  1. 批量操作:掌握了Fastest等高性能批量操作方法
  2. 存储过程:学会了调用存储过程和函数
  3. 视图支持:了解了视图的查询和创建
  4. 临时表:掌握了临时表和CTE的使用
  5. XML/JSON:学会了处理XML和JSON数据
  6. 设计模式:应用了多种设计模式优化代码
  7. 错误处理:实现了完善的错误处理机制
  8. 测试策略:掌握了单元测试和集成测试方法
  9. 部署考虑:了解了生产环境的部署要点
  10. 最佳实践:总结了开发中的各种最佳实践

通过完整的15章学习,您现在应该能够:

  • 熟练使用SqlSugar进行数据库开发
  • 设计和实现高性能的数据访问层
  • 构建可维护、可扩展的企业级应用
  • 解决实际开发中遇到的各种问题
  • 遵循最佳实践编写高质量代码

感谢您完成本系列教程的学习!

SqlSugar是一个功能强大且不断发展的ORM框架,希望本教程能够帮助您快速掌握并应用到实际项目中。祝您在.NET开发的道路上越走越远!


相关资源

继续学习

  • 深入学习EF Core对比
  • 研究微服务架构
  • 探索云原生开发
  • 学习分布式事务