学习目标

通过本章学习,你将掌握: - ADO.NET核心概念和基础操作 - Entity Framework Core的使用 - 数据库连接和事务管理 - LINQ to SQL查询技术 - 数据库性能优化技巧 - NoSQL数据库操作 - 数据库设计最佳实践

18.1 ADO.NET基础

核心组件介绍

using System.Data;
using System.Data.SqlClient;
using Microsoft.Data.SqlClient; // 推荐使用新版本

// ADO.NET核心组件演示
public class AdoNetBasics
{
    private readonly string _connectionString;
    
    public AdoNetBasics(string connectionString)
    {
        _connectionString = connectionString;
    }
    
    // 基本数据库连接
    public async Task<bool> TestConnectionAsync()
    {
        try
        {
            using var connection = new SqlConnection(_connectionString);
            await connection.OpenAsync();
            
            Console.WriteLine($"数据库连接成功");
            Console.WriteLine($"数据库版本: {connection.ServerVersion}");
            Console.WriteLine($"连接状态: {connection.State}");
            
            return true;
        }
        catch (Exception ex)
        {
            Console.WriteLine($"数据库连接失败: {ex.Message}");
            return false;
        }
    }
    
    // 执行查询操作
    public async Task<List<Employee>> GetEmployeesAsync()
    {
        var employees = new List<Employee>();
        
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();
        
        var sql = @"
            SELECT Id, FirstName, LastName, Email, Department, Salary, HireDate
            FROM Employees
            ORDER BY LastName, FirstName";
        
        using var command = new SqlCommand(sql, connection);
        using var reader = await command.ExecuteReaderAsync();
        
        while (await reader.ReadAsync())
        {
            employees.Add(new Employee
            {
                Id = reader.GetInt32("Id"),
                FirstName = reader.GetString("FirstName"),
                LastName = reader.GetString("LastName"),
                Email = reader.GetString("Email"),
                Department = reader.GetString("Department"),
                Salary = reader.GetDecimal("Salary"),
                HireDate = reader.GetDateTime("HireDate")
            });
        }
        
        return employees;
    }
    
    // 执行插入操作
    public async Task<int> InsertEmployeeAsync(Employee employee)
    {
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();
        
        var sql = @"
            INSERT INTO Employees (FirstName, LastName, Email, Department, Salary, HireDate)
            VALUES (@FirstName, @LastName, @Email, @Department, @Salary, @HireDate);
            SELECT SCOPE_IDENTITY();";
        
        using var command = new SqlCommand(sql, connection);
        
        // 使用参数化查询防止SQL注入
        command.Parameters.AddWithValue("@FirstName", employee.FirstName);
        command.Parameters.AddWithValue("@LastName", employee.LastName);
        command.Parameters.AddWithValue("@Email", employee.Email);
        command.Parameters.AddWithValue("@Department", employee.Department);
        command.Parameters.AddWithValue("@Salary", employee.Salary);
        command.Parameters.AddWithValue("@HireDate", employee.HireDate);
        
        var result = await command.ExecuteScalarAsync();
        return Convert.ToInt32(result);
    }
    
    // 执行更新操作
    public async Task<bool> UpdateEmployeeAsync(Employee employee)
    {
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();
        
        var sql = @"
            UPDATE Employees 
            SET FirstName = @FirstName, 
                LastName = @LastName, 
                Email = @Email, 
                Department = @Department, 
                Salary = @Salary
            WHERE Id = @Id";
        
        using var command = new SqlCommand(sql, connection);
        
        command.Parameters.AddWithValue("@Id", employee.Id);
        command.Parameters.AddWithValue("@FirstName", employee.FirstName);
        command.Parameters.AddWithValue("@LastName", employee.LastName);
        command.Parameters.AddWithValue("@Email", employee.Email);
        command.Parameters.AddWithValue("@Department", employee.Department);
        command.Parameters.AddWithValue("@Salary", employee.Salary);
        
        var rowsAffected = await command.ExecuteNonQueryAsync();
        return rowsAffected > 0;
    }
    
    // 执行删除操作
    public async Task<bool> DeleteEmployeeAsync(int employeeId)
    {
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();
        
        var sql = "DELETE FROM Employees WHERE Id = @Id";
        
        using var command = new SqlCommand(sql, connection);
        command.Parameters.AddWithValue("@Id", employeeId);
        
        var rowsAffected = await command.ExecuteNonQueryAsync();
        return rowsAffected > 0;
    }
    
    // 批量操作
    public async Task<int> BulkInsertEmployeesAsync(List<Employee> employees)
    {
        using var connection = new SqlConnection(_connectionString);
        await connection.OpenAsync();
        
        using var transaction = connection.BeginTransaction();
        
        try
        {
            var sql = @"
                INSERT INTO Employees (FirstName, LastName, Email, Department, Salary, HireDate)
                VALUES (@FirstName, @LastName, @Email, @Department, @Salary, @HireDate)";
            
            var insertedCount = 0;
            
            foreach (var employee in employees)
            {
                using var command = new SqlCommand(sql, connection, transaction);
                
                command.Parameters.AddWithValue("@FirstName", employee.FirstName);
                command.Parameters.AddWithValue("@LastName", employee.LastName);
                command.Parameters.AddWithValue("@Email", employee.Email);
                command.Parameters.AddWithValue("@Department", employee.Department);
                command.Parameters.AddWithValue("@Salary", employee.Salary);
                command.Parameters.AddWithValue("@HireDate", employee.HireDate);
                
                var rowsAffected = await command.ExecuteNonQueryAsync();
                if (rowsAffected > 0)
                    insertedCount++;
            }
            
            transaction.Commit();
            return insertedCount;
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            Console.WriteLine($"批量插入失败: {ex.Message}");
            throw;
        }
    }
}

// 员工数据模型
public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string Department { get; set; }
    public decimal Salary { get; set; }
    public DateTime HireDate { get; set; }
    
    public string FullName => $"{FirstName} {LastName}";
    
    public override string ToString()
    {
        return $"{FullName} - {Department} - {Salary:C}";
    }
}

连接字符串管理

using Microsoft.Extensions.Configuration;

// 连接字符串管理器
public class ConnectionStringManager
{
    private readonly IConfiguration _configuration;
    
    public ConnectionStringManager(IConfiguration configuration)
    {
        _configuration = configuration;
    }
    
    // 获取连接字符串
    public string GetConnectionString(string name = "DefaultConnection")
    {
        return _configuration.GetConnectionString(name) 
               ?? throw new InvalidOperationException($"连接字符串 '{name}' 未找到");
    }
    
    // 构建连接字符串
    public static string BuildConnectionString(string server, string database, 
        string userId = null, string password = null, bool integratedSecurity = true)
    {
        var builder = new SqlConnectionStringBuilder
        {
            DataSource = server,
            InitialCatalog = database,
            IntegratedSecurity = integratedSecurity,
            TrustServerCertificate = true, // 开发环境使用
            ConnectTimeout = 30,
            CommandTimeout = 60
        };
        
        if (!integratedSecurity)
        {
            builder.UserID = userId;
            builder.Password = password;
        }
        
        return builder.ConnectionString;
    }
    
    // 测试连接字符串
    public static async Task<bool> TestConnectionStringAsync(string connectionString)
    {
        try
        {
            using var connection = new SqlConnection(connectionString);
            await connection.OpenAsync();
            return true;
        }
        catch
        {
            return false;
        }
    }
    
    // 获取数据库信息
    public static async Task<DatabaseInfo> GetDatabaseInfoAsync(string connectionString)
    {
        using var connection = new SqlConnection(connectionString);
        await connection.OpenAsync();
        
        var sql = @"
            SELECT 
                DB_NAME() as DatabaseName,
                @@VERSION as ServerVersion,
                SERVERPROPERTY('ProductVersion') as ProductVersion,
                SERVERPROPERTY('Edition') as Edition,
                SERVERPROPERTY('MachineName') as MachineName";
        
        using var command = new SqlCommand(sql, connection);
        using var reader = await command.ExecuteReaderAsync();
        
        if (await reader.ReadAsync())
        {
            return new DatabaseInfo
            {
                DatabaseName = reader.GetString("DatabaseName"),
                ServerVersion = reader.GetString("ServerVersion"),
                ProductVersion = reader.GetString("ProductVersion"),
                Edition = reader.GetString("Edition"),
                MachineName = reader.GetString("MachineName")
            };
        }
        
        return null;
    }
}

// 数据库信息模型
public class DatabaseInfo
{
    public string DatabaseName { get; set; }
    public string ServerVersion { get; set; }
    public string ProductVersion { get; set; }
    public string Edition { get; set; }
    public string MachineName { get; set; }
    
    public override string ToString()
    {
        return $"数据库: {DatabaseName}, 版本: {ProductVersion}, 服务器: {MachineName}";
    }
}

18.2 Entity Framework Core

DbContext配置

using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

// 应用程序数据库上下文
public class ApplicationDbContext : DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }
    
    // 数据集
    public DbSet<Employee> Employees { get; set; }
    public DbSet<Department> Departments { get; set; }
    public DbSet<Project> Projects { get; set; }
    public DbSet<EmployeeProject> EmployeeProjects { get; set; }
    
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        // 配置Employee实体
        modelBuilder.Entity<Employee>(entity =>
        {
            entity.HasKey(e => e.Id);
            entity.Property(e => e.FirstName).IsRequired().HasMaxLength(50);
            entity.Property(e => e.LastName).IsRequired().HasMaxLength(50);
            entity.Property(e => e.Email).IsRequired().HasMaxLength(100);
            entity.HasIndex(e => e.Email).IsUnique();
            entity.Property(e => e.Salary).HasColumnType("decimal(18,2)");
            
            // 配置与Department的关系
            entity.HasOne(e => e.Department)
                  .WithMany(d => d.Employees)
                  .HasForeignKey(e => e.DepartmentId)
                  .OnDelete(DeleteBehavior.Restrict);
        });
        
        // 配置Department实体
        modelBuilder.Entity<Department>(entity =>
        {
            entity.HasKey(d => d.Id);
            entity.Property(d => d.Name).IsRequired().HasMaxLength(100);
            entity.Property(d => d.Description).HasMaxLength(500);
            entity.HasIndex(d => d.Name).IsUnique();
        });
        
        // 配置Project实体
        modelBuilder.Entity<Project>(entity =>
        {
            entity.HasKey(p => p.Id);
            entity.Property(p => p.Name).IsRequired().HasMaxLength(200);
            entity.Property(p => p.Description).HasMaxLength(1000);
            entity.Property(p => p.Budget).HasColumnType("decimal(18,2)");
        });
        
        // 配置多对多关系
        modelBuilder.Entity<EmployeeProject>(entity =>
        {
            entity.HasKey(ep => new { ep.EmployeeId, ep.ProjectId });
            
            entity.HasOne(ep => ep.Employee)
                  .WithMany(e => e.EmployeeProjects)
                  .HasForeignKey(ep => ep.EmployeeId);
            
            entity.HasOne(ep => ep.Project)
                  .WithMany(p => p.EmployeeProjects)
                  .HasForeignKey(ep => ep.ProjectId);
            
            entity.Property(ep => ep.Role).HasMaxLength(100);
            entity.Property(ep => ep.HoursAllocated).HasDefaultValue(0);
        });
        
        // 种子数据
        SeedData(modelBuilder);
    }
    
    private void SeedData(ModelBuilder modelBuilder)
    {
        // 部门种子数据
        modelBuilder.Entity<Department>().HasData(
            new Department { Id = 1, Name = "技术部", Description = "负责软件开发和技术支持" },
            new Department { Id = 2, Name = "销售部", Description = "负责产品销售和客户关系" },
            new Department { Id = 3, Name = "人事部", Description = "负责人力资源管理" },
            new Department { Id = 4, Name = "财务部", Description = "负责财务管理和会计" }
        );
        
        // 员工种子数据
        modelBuilder.Entity<Employee>().HasData(
            new Employee 
            { 
                Id = 1, 
                FirstName = "张", 
                LastName = "三", 
                Email = "zhang.san@company.com", 
                DepartmentId = 1, 
                Salary = 8000, 
                HireDate = new DateTime(2020, 1, 15) 
            },
            new Employee 
            { 
                Id = 2, 
                FirstName = "李", 
                LastName = "四", 
                Email = "li.si@company.com", 
                DepartmentId = 1, 
                Salary = 9500, 
                HireDate = new DateTime(2019, 6, 10) 
            },
            new Employee 
            { 
                Id = 3, 
                FirstName = "王", 
                LastName = "五", 
                Email = "wang.wu@company.com", 
                DepartmentId = 2, 
                Salary = 7500, 
                HireDate = new DateTime(2021, 3, 20) 
            }
        );
        
        // 项目种子数据
        modelBuilder.Entity<Project>().HasData(
            new Project 
            { 
                Id = 1, 
                Name = "电商平台开发", 
                Description = "开发新的电商平台系统", 
                Budget = 500000, 
                StartDate = new DateTime(2023, 1, 1), 
                EndDate = new DateTime(2023, 12, 31) 
            },
            new Project 
            { 
                Id = 2, 
                Name = "移动应用开发", 
                Description = "开发配套的移动应用", 
                Budget = 300000, 
                StartDate = new DateTime(2023, 6, 1), 
                EndDate = new DateTime(2024, 3, 31) 
            }
        );
    }
    
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (!optionsBuilder.IsConfigured)
        {
            // 开发环境配置
            optionsBuilder.UseSqlServer("Server=localhost;Database=CompanyDB;Trusted_Connection=true;TrustServerCertificate=true;")
                         .LogTo(Console.WriteLine, LogLevel.Information)
                         .EnableSensitiveDataLogging()
                         .EnableDetailedErrors();
        }
    }
}

// 更新的实体模型
public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public decimal Salary { get; set; }
    public DateTime HireDate { get; set; }
    
    // 外键
    public int DepartmentId { get; set; }
    
    // 导航属性
    public Department Department { get; set; }
    public List<EmployeeProject> EmployeeProjects { get; set; } = new();
    
    public string FullName => $"{FirstName} {LastName}";
}

public class Department
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    
    // 导航属性
    public List<Employee> Employees { get; set; } = new();
}

public class Project
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public decimal Budget { get; set; }
    public DateTime StartDate { get; set; }
    public DateTime? EndDate { get; set; }
    
    // 导航属性
    public List<EmployeeProject> EmployeeProjects { get; set; } = new();
}

public class EmployeeProject
{
    public int EmployeeId { get; set; }
    public int ProjectId { get; set; }
    public string Role { get; set; }
    public int HoursAllocated { get; set; }
    public DateTime AssignedDate { get; set; }
    
    // 导航属性
    public Employee Employee { get; set; }
    public Project Project { get; set; }
}

Entity Framework Core操作

// EF Core数据访问服务
public class EmployeeService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<EmployeeService> _logger;
    
    public EmployeeService(ApplicationDbContext context, ILogger<EmployeeService> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    // 获取所有员工(包含部门信息)
    public async Task<List<Employee>> GetAllEmployeesAsync()
    {
        return await _context.Employees
            .Include(e => e.Department)
            .OrderBy(e => e.LastName)
            .ThenBy(e => e.FirstName)
            .ToListAsync();
    }
    
    // 根据ID获取员工
    public async Task<Employee> GetEmployeeByIdAsync(int id)
    {
        return await _context.Employees
            .Include(e => e.Department)
            .Include(e => e.EmployeeProjects)
                .ThenInclude(ep => ep.Project)
            .FirstOrDefaultAsync(e => e.Id == id);
    }
    
    // 根据部门获取员工
    public async Task<List<Employee>> GetEmployeesByDepartmentAsync(int departmentId)
    {
        return await _context.Employees
            .Include(e => e.Department)
            .Where(e => e.DepartmentId == departmentId)
            .ToListAsync();
    }
    
    // 搜索员工
    public async Task<List<Employee>> SearchEmployeesAsync(string searchTerm)
    {
        if (string.IsNullOrWhiteSpace(searchTerm))
            return await GetAllEmployeesAsync();
        
        searchTerm = searchTerm.ToLower();
        
        return await _context.Employees
            .Include(e => e.Department)
            .Where(e => e.FirstName.ToLower().Contains(searchTerm) ||
                       e.LastName.ToLower().Contains(searchTerm) ||
                       e.Email.ToLower().Contains(searchTerm) ||
                       e.Department.Name.ToLower().Contains(searchTerm))
            .ToListAsync();
    }
    
    // 添加员工
    public async Task<Employee> AddEmployeeAsync(Employee employee)
    {
        try
        {
            _context.Employees.Add(employee);
            await _context.SaveChangesAsync();
            
            _logger.LogInformation($"员工 {employee.FullName} 添加成功,ID: {employee.Id}");
            return employee;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"添加员工 {employee.FullName} 失败");
            throw;
        }
    }
    
    // 更新员工
    public async Task<bool> UpdateEmployeeAsync(Employee employee)
    {
        try
        {
            _context.Employees.Update(employee);
            var result = await _context.SaveChangesAsync();
            
            _logger.LogInformation($"员工 {employee.FullName} 更新成功");
            return result > 0;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"更新员工 {employee.FullName} 失败");
            throw;
        }
    }
    
    // 删除员工
    public async Task<bool> DeleteEmployeeAsync(int id)
    {
        try
        {
            var employee = await _context.Employees.FindAsync(id);
            if (employee == null)
                return false;
            
            _context.Employees.Remove(employee);
            var result = await _context.SaveChangesAsync();
            
            _logger.LogInformation($"员工 {employee.FullName} 删除成功");
            return result > 0;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, $"删除员工 ID:{id} 失败");
            throw;
        }
    }
    
    // 批量添加员工
    public async Task<int> BulkAddEmployeesAsync(List<Employee> employees)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            _context.Employees.AddRange(employees);
            var result = await _context.SaveChangesAsync();
            
            await transaction.CommitAsync();
            _logger.LogInformation($"批量添加 {result} 个员工成功");
            
            return result;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "批量添加员工失败");
            throw;
        }
    }
    
    // 获取员工统计信息
    public async Task<EmployeeStatistics> GetEmployeeStatisticsAsync()
    {
        var stats = await _context.Employees
            .GroupBy(e => e.DepartmentId)
            .Select(g => new DepartmentStatistic
            {
                DepartmentId = g.Key,
                DepartmentName = g.First().Department.Name,
                EmployeeCount = g.Count(),
                AverageSalary = g.Average(e => e.Salary),
                TotalSalary = g.Sum(e => e.Salary)
            })
            .ToListAsync();
        
        return new EmployeeStatistics
        {
            TotalEmployees = await _context.Employees.CountAsync(),
            AverageSalary = await _context.Employees.AverageAsync(e => e.Salary),
            DepartmentStatistics = stats
        };
    }
}

// 统计信息模型
public class EmployeeStatistics
{
    public int TotalEmployees { get; set; }
    public decimal AverageSalary { get; set; }
    public List<DepartmentStatistic> DepartmentStatistics { get; set; } = new();
}

public class DepartmentStatistic
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public int EmployeeCount { get; set; }
    public decimal AverageSalary { get; set; }
    public decimal TotalSalary { get; set; }
}

## 18.3 事务管理

### 数据库事务基础

```csharp
// 事务管理服务
public class TransactionService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<TransactionService> _logger;
    
    public TransactionService(ApplicationDbContext context, ILogger<TransactionService> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    // 基本事务操作
    public async Task<bool> TransferEmployeeAsync(int employeeId, int newDepartmentId, decimal salaryAdjustment)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            // 1. 获取员工信息
            var employee = await _context.Employees
                .Include(e => e.Department)
                .FirstOrDefaultAsync(e => e.Id == employeeId);
            
            if (employee == null)
            {
                _logger.LogWarning($"员工 ID:{employeeId} 不存在");
                return false;
            }
            
            var oldDepartmentId = employee.DepartmentId;
            var oldSalary = employee.Salary;
            
            // 2. 更新员工部门和薪资
            employee.DepartmentId = newDepartmentId;
            employee.Salary += salaryAdjustment;
            
            // 3. 记录转移历史
            var transferHistory = new EmployeeTransferHistory
            {
                EmployeeId = employeeId,
                FromDepartmentId = oldDepartmentId,
                ToDepartmentId = newDepartmentId,
                OldSalary = oldSalary,
                NewSalary = employee.Salary,
                TransferDate = DateTime.UtcNow,
                Reason = "部门调动"
            };
            
            _context.EmployeeTransferHistories.Add(transferHistory);
            
            // 4. 保存所有更改
            await _context.SaveChangesAsync();
            
            // 5. 提交事务
            await transaction.CommitAsync();
            
            _logger.LogInformation($"员工 {employee.FullName} 成功从部门 {oldDepartmentId} 转移到部门 {newDepartmentId}");
            return true;
        }
        catch (Exception ex)
        {
            // 回滚事务
            await transaction.RollbackAsync();
            _logger.LogError(ex, $"员工转移失败,事务已回滚");
            return false;
        }
    }
    
    // 复杂事务操作:项目分配
    public async Task<bool> AssignEmployeesToProjectAsync(int projectId, List<EmployeeProjectAssignment> assignments)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            // 1. 验证项目存在
            var project = await _context.Projects.FindAsync(projectId);
            if (project == null)
            {
                _logger.LogWarning($"项目 ID:{projectId} 不存在");
                return false;
            }
            
            // 2. 验证所有员工存在
            var employeeIds = assignments.Select(a => a.EmployeeId).ToList();
            var existingEmployees = await _context.Employees
                .Where(e => employeeIds.Contains(e.Id))
                .Select(e => e.Id)
                .ToListAsync();
            
            var missingEmployees = employeeIds.Except(existingEmployees).ToList();
            if (missingEmployees.Any())
            {
                _logger.LogWarning($"员工 ID:{string.Join(",", missingEmployees)} 不存在");
                return false;
            }
            
            // 3. 检查员工是否已分配到该项目
            var existingAssignments = await _context.EmployeeProjects
                .Where(ep => ep.ProjectId == projectId && employeeIds.Contains(ep.EmployeeId))
                .Select(ep => ep.EmployeeId)
                .ToListAsync();
            
            if (existingAssignments.Any())
            {
                _logger.LogWarning($"员工 ID:{string.Join(",", existingAssignments)} 已分配到项目 {projectId}");
                return false;
            }
            
            // 4. 创建项目分配记录
            var employeeProjects = assignments.Select(a => new EmployeeProject
            {
                EmployeeId = a.EmployeeId,
                ProjectId = projectId,
                Role = a.Role,
                HoursAllocated = a.HoursAllocated,
                AssignedDate = DateTime.UtcNow
            }).ToList();
            
            _context.EmployeeProjects.AddRange(employeeProjects);
            
            // 5. 更新项目状态
            project.Status = "进行中";
            
            // 6. 保存更改
            await _context.SaveChangesAsync();
            
            // 7. 提交事务
            await transaction.CommitAsync();
            
            _logger.LogInformation($"成功将 {assignments.Count} 个员工分配到项目 {project.Name}");
            return true;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, $"项目分配失败,事务已回滚");
            return false;
        }
    }
    
    // 分布式事务示例
    public async Task<bool> ProcessPayrollAsync(int departmentId, decimal bonusPercentage)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            // 1. 获取部门员工
            var employees = await _context.Employees
                .Where(e => e.DepartmentId == departmentId)
                .ToListAsync();
            
            if (!employees.Any())
            {
                _logger.LogWarning($"部门 ID:{departmentId} 没有员工");
                return false;
            }
            
            var totalBonus = 0m;
            var payrollRecords = new List<PayrollRecord>();
            
            // 2. 计算每个员工的奖金
            foreach (var employee in employees)
            {
                var bonus = employee.Salary * (bonusPercentage / 100);
                totalBonus += bonus;
                
                payrollRecords.Add(new PayrollRecord
                {
                    EmployeeId = employee.Id,
                    BaseSalary = employee.Salary,
                    Bonus = bonus,
                    TotalPay = employee.Salary + bonus,
                    PayPeriod = DateTime.UtcNow.ToString("yyyy-MM"),
                    ProcessedDate = DateTime.UtcNow
                });
            }
            
            // 3. 检查部门预算
            var department = await _context.Departments.FindAsync(departmentId);
            if (department.Budget < totalBonus)
            {
                _logger.LogWarning($"部门预算不足,需要 {totalBonus:C},可用 {department.Budget:C}");
                return false;
            }
            
            // 4. 扣除部门预算
            department.Budget -= totalBonus;
            
            // 5. 添加工资记录
            _context.PayrollRecords.AddRange(payrollRecords);
            
            // 6. 保存更改
            await _context.SaveChangesAsync();
            
            // 7. 提交事务
            await transaction.CommitAsync();
            
            _logger.LogInformation($"部门 {department.Name} 工资处理完成,总奖金: {totalBonus:C}");
            return true;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "工资处理失败,事务已回滚");
            return false;
        }
    }
}

// 支持事务的数据模型
public class EmployeeTransferHistory
{
    public int Id { get; set; }
    public int EmployeeId { get; set; }
    public int FromDepartmentId { get; set; }
    public int ToDepartmentId { get; set; }
    public decimal OldSalary { get; set; }
    public decimal NewSalary { get; set; }
    public DateTime TransferDate { get; set; }
    public string Reason { get; set; }
    
    // 导航属性
    public Employee Employee { get; set; }
    public Department FromDepartment { get; set; }
    public Department ToDepartment { get; set; }
}

public class PayrollRecord
{
    public int Id { get; set; }
    public int EmployeeId { get; set; }
    public decimal BaseSalary { get; set; }
    public decimal Bonus { get; set; }
    public decimal TotalPay { get; set; }
    public string PayPeriod { get; set; }
    public DateTime ProcessedDate { get; set; }
    
    // 导航属性
    public Employee Employee { get; set; }
}

public class EmployeeProjectAssignment
{
    public int EmployeeId { get; set; }
    public string Role { get; set; }
    public int HoursAllocated { get; set; }
}

// 更新Department模型以支持预算
public partial class Department
{
    public decimal Budget { get; set; }
    public string Status { get; set; } = "活跃";
}

// 更新Project模型以支持状态
public partial class Project
{
    public string Status { get; set; } = "计划中";
}

18.4 LINQ查询技术

复杂LINQ查询

// LINQ查询服务
public class QueryService
{
    private readonly ApplicationDbContext _context;
    
    public QueryService(ApplicationDbContext context)
    {
        _context = context;
    }
    
    // 基础查询
    public async Task<List<Employee>> GetHighSalaryEmployeesAsync(decimal minSalary)
    {
        return await _context.Employees
            .Include(e => e.Department)
            .Where(e => e.Salary >= minSalary)
            .OrderByDescending(e => e.Salary)
            .ToListAsync();
    }
    
    // 分组查询
    public async Task<List<DepartmentSalaryReport>> GetDepartmentSalaryReportAsync()
    {
        return await _context.Employees
            .Include(e => e.Department)
            .GroupBy(e => new { e.DepartmentId, e.Department.Name })
            .Select(g => new DepartmentSalaryReport
            {
                DepartmentId = g.Key.DepartmentId,
                DepartmentName = g.Key.Name,
                EmployeeCount = g.Count(),
                MinSalary = g.Min(e => e.Salary),
                MaxSalary = g.Max(e => e.Salary),
                AverageSalary = g.Average(e => e.Salary),
                TotalSalary = g.Sum(e => e.Salary)
            })
            .OrderByDescending(r => r.AverageSalary)
            .ToListAsync();
    }
    
    // 连接查询
    public async Task<List<EmployeeProjectInfo>> GetEmployeeProjectInfoAsync()
    {
        return await (from e in _context.Employees
                     join ep in _context.EmployeeProjects on e.Id equals ep.EmployeeId
                     join p in _context.Projects on ep.ProjectId equals p.Id
                     join d in _context.Departments on e.DepartmentId equals d.Id
                     select new EmployeeProjectInfo
                     {
                         EmployeeId = e.Id,
                         EmployeeName = e.FirstName + " " + e.LastName,
                         DepartmentName = d.Name,
                         ProjectName = p.Name,
                         Role = ep.Role,
                         HoursAllocated = ep.HoursAllocated,
                         ProjectBudget = p.Budget
                     })
                     .OrderBy(info => info.EmployeeName)
                     .ThenBy(info => info.ProjectName)
                     .ToListAsync();
    }
    
    // 子查询
    public async Task<List<Employee>> GetEmployeesWithMostProjectsAsync()
    {
        // 找出参与项目最多的员工
        var maxProjectCount = await _context.EmployeeProjects
            .GroupBy(ep => ep.EmployeeId)
            .Select(g => g.Count())
            .MaxAsync();
        
        var employeeIdsWithMostProjects = await _context.EmployeeProjects
            .GroupBy(ep => ep.EmployeeId)
            .Where(g => g.Count() == maxProjectCount)
            .Select(g => g.Key)
            .ToListAsync();
        
        return await _context.Employees
            .Include(e => e.Department)
            .Include(e => e.EmployeeProjects)
                .ThenInclude(ep => ep.Project)
            .Where(e => employeeIdsWithMostProjects.Contains(e.Id))
            .ToListAsync();
    }
    
    // 条件查询
    public async Task<List<Employee>> SearchEmployeesAdvancedAsync(EmployeeSearchCriteria criteria)
    {
        var query = _context.Employees
            .Include(e => e.Department)
            .AsQueryable();
        
        // 动态构建查询条件
        if (!string.IsNullOrWhiteSpace(criteria.Name))
        {
            var name = criteria.Name.ToLower();
            query = query.Where(e => e.FirstName.ToLower().Contains(name) || 
                                   e.LastName.ToLower().Contains(name));
        }
        
        if (!string.IsNullOrWhiteSpace(criteria.Email))
        {
            query = query.Where(e => e.Email.ToLower().Contains(criteria.Email.ToLower()));
        }
        
        if (criteria.DepartmentId.HasValue)
        {
            query = query.Where(e => e.DepartmentId == criteria.DepartmentId.Value);
        }
        
        if (criteria.MinSalary.HasValue)
        {
            query = query.Where(e => e.Salary >= criteria.MinSalary.Value);
        }
        
        if (criteria.MaxSalary.HasValue)
        {
            query = query.Where(e => e.Salary <= criteria.MaxSalary.Value);
        }
        
        if (criteria.HireDateFrom.HasValue)
        {
            query = query.Where(e => e.HireDate >= criteria.HireDateFrom.Value);
        }
        
        if (criteria.HireDateTo.HasValue)
        {
            query = query.Where(e => e.HireDate <= criteria.HireDateTo.Value);
        }
        
        // 排序
        query = criteria.SortBy?.ToLower() switch
        {
            "name" => criteria.SortDescending ? 
                query.OrderByDescending(e => e.LastName).ThenByDescending(e => e.FirstName) :
                query.OrderBy(e => e.LastName).ThenBy(e => e.FirstName),
            "salary" => criteria.SortDescending ? 
                query.OrderByDescending(e => e.Salary) :
                query.OrderBy(e => e.Salary),
            "hiredate" => criteria.SortDescending ? 
                query.OrderByDescending(e => e.HireDate) :
                query.OrderBy(e => e.HireDate),
            "department" => criteria.SortDescending ? 
                query.OrderByDescending(e => e.Department.Name) :
                query.OrderBy(e => e.Department.Name),
            _ => query.OrderBy(e => e.LastName).ThenBy(e => e.FirstName)
        };
        
        // 分页
        if (criteria.PageSize > 0)
        {
            query = query.Skip((criteria.PageNumber - 1) * criteria.PageSize)
                         .Take(criteria.PageSize);
        }
        
        return await query.ToListAsync();
    }
    
    // 聚合查询
    public async Task<CompanyStatistics> GetCompanyStatisticsAsync()
    {
        var totalEmployees = await _context.Employees.CountAsync();
        var totalDepartments = await _context.Departments.CountAsync();
        var totalProjects = await _context.Projects.CountAsync();
        
        var salaryStats = await _context.Employees
            .GroupBy(e => 1)
            .Select(g => new
            {
                MinSalary = g.Min(e => e.Salary),
                MaxSalary = g.Max(e => e.Salary),
                AverageSalary = g.Average(e => e.Salary),
                TotalSalary = g.Sum(e => e.Salary)
            })
            .FirstOrDefaultAsync();
        
        var departmentDistribution = await _context.Employees
            .GroupBy(e => e.Department.Name)
            .Select(g => new DepartmentDistribution
            {
                DepartmentName = g.Key,
                EmployeeCount = g.Count(),
                Percentage = (double)g.Count() / totalEmployees * 100
            })
            .OrderByDescending(d => d.EmployeeCount)
            .ToListAsync();
        
        var projectStats = await _context.Projects
            .GroupBy(p => 1)
            .Select(g => new
            {
                TotalBudget = g.Sum(p => p.Budget),
                AverageBudget = g.Average(p => p.Budget),
                ActiveProjects = g.Count(p => p.Status == "进行中")
            })
            .FirstOrDefaultAsync();
        
        return new CompanyStatistics
        {
            TotalEmployees = totalEmployees,
            TotalDepartments = totalDepartments,
            TotalProjects = totalProjects,
            MinSalary = salaryStats?.MinSalary ?? 0,
            MaxSalary = salaryStats?.MaxSalary ?? 0,
            AverageSalary = salaryStats?.AverageSalary ?? 0,
            TotalSalaryExpense = salaryStats?.TotalSalary ?? 0,
            TotalProjectBudget = projectStats?.TotalBudget ?? 0,
            AverageProjectBudget = projectStats?.AverageBudget ?? 0,
            ActiveProjects = projectStats?.ActiveProjects ?? 0,
            DepartmentDistribution = departmentDistribution
        };
    }
    
    // 原生SQL查询
    public async Task<List<EmployeeSalaryRank>> GetEmployeeSalaryRankingAsync()
    {
        var sql = @"
            SELECT 
                e.Id,
                e.FirstName + ' ' + e.LastName as FullName,
                d.Name as DepartmentName,
                e.Salary,
                RANK() OVER (ORDER BY e.Salary DESC) as OverallRank,
                RANK() OVER (PARTITION BY e.DepartmentId ORDER BY e.Salary DESC) as DepartmentRank
            FROM Employees e
            INNER JOIN Departments d ON e.DepartmentId = d.Id
            ORDER BY e.Salary DESC";
        
        return await _context.Database
            .SqlQueryRaw<EmployeeSalaryRank>(sql)
            .ToListAsync();
    }
}

// 查询相关的数据模型
public class DepartmentSalaryReport
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public int EmployeeCount { get; set; }
    public decimal MinSalary { get; set; }
    public decimal MaxSalary { get; set; }
    public decimal AverageSalary { get; set; }
    public decimal TotalSalary { get; set; }
}

public class EmployeeProjectInfo
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public string DepartmentName { get; set; }
    public string ProjectName { get; set; }
    public string Role { get; set; }
    public int HoursAllocated { get; set; }
    public decimal ProjectBudget { get; set; }
}

public class EmployeeSearchCriteria
{
    public string Name { get; set; }
    public string Email { get; set; }
    public int? DepartmentId { get; set; }
    public decimal? MinSalary { get; set; }
    public decimal? MaxSalary { get; set; }
    public DateTime? HireDateFrom { get; set; }
    public DateTime? HireDateTo { get; set; }
    public string SortBy { get; set; } = "name";
    public bool SortDescending { get; set; }
    public int PageNumber { get; set; } = 1;
    public int PageSize { get; set; } = 10;
}

public class CompanyStatistics
{
    public int TotalEmployees { get; set; }
    public int TotalDepartments { get; set; }
    public int TotalProjects { get; set; }
    public decimal MinSalary { get; set; }
    public decimal MaxSalary { get; set; }
    public decimal AverageSalary { get; set; }
    public decimal TotalSalaryExpense { get; set; }
    public decimal TotalProjectBudget { get; set; }
    public decimal AverageProjectBudget { get; set; }
    public int ActiveProjects { get; set; }
    public List<DepartmentDistribution> DepartmentDistribution { get; set; } = new();
}

public class DepartmentDistribution
{
    public string DepartmentName { get; set; }
    public int EmployeeCount { get; set; }
    public double Percentage { get; set; }
}

public class EmployeeSalaryRank
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public string DepartmentName { get; set; }
    public decimal Salary { get; set; }
    public int OverallRank { get; set; }
    public int DepartmentRank { get; set; }
}

18.5 性能优化和最佳实践

数据库性能优化

// 性能优化服务
public class PerformanceOptimizationService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<PerformanceOptimizationService> _logger;
    private readonly IMemoryCache _cache;
    
    public PerformanceOptimizationService(
        ApplicationDbContext context, 
        ILogger<PerformanceOptimizationService> logger,
        IMemoryCache cache)
    {
        _context = context;
        _logger = logger;
        _cache = cache;
    }
    
    // 查询优化:使用投影减少数据传输
    public async Task<List<EmployeeSummary>> GetEmployeeSummariesAsync()
    {
        return await _context.Employees
            .Select(e => new EmployeeSummary
            {
                Id = e.Id,
                FullName = e.FirstName + " " + e.LastName,
                DepartmentName = e.Department.Name,
                Salary = e.Salary
            })
            .ToListAsync();
    }
    
    // 批量操作优化
    public async Task<int> BulkUpdateSalariesAsync(List<SalaryUpdate> updates)
    {
        var employeeIds = updates.Select(u => u.EmployeeId).ToList();
        var employees = await _context.Employees
            .Where(e => employeeIds.Contains(e.Id))
            .ToListAsync();
        
        var updateDict = updates.ToDictionary(u => u.EmployeeId, u => u.NewSalary);
        
        foreach (var employee in employees)
        {
            if (updateDict.TryGetValue(employee.Id, out var newSalary))
            {
                employee.Salary = newSalary;
            }
        }
        
        return await _context.SaveChangesAsync();
    }
    
    // 分页查询优化
    public async Task<PagedResult<Employee>> GetEmployeesPagedAsync(
        int pageNumber, 
        int pageSize, 
        string searchTerm = null)
    {
        var query = _context.Employees
            .Include(e => e.Department)
            .AsQueryable();
        
        if (!string.IsNullOrWhiteSpace(searchTerm))
        {
            var term = searchTerm.ToLower();
            query = query.Where(e => 
                e.FirstName.ToLower().Contains(term) ||
                e.LastName.ToLower().Contains(term) ||
                e.Email.ToLower().Contains(term));
        }
        
        var totalCount = await query.CountAsync();
        
        var employees = await query
            .OrderBy(e => e.LastName)
            .ThenBy(e => e.FirstName)
            .Skip((pageNumber - 1) * pageSize)
            .Take(pageSize)
            .ToListAsync();
        
        return new PagedResult<Employee>
        {
            Items = employees,
            TotalCount = totalCount,
            PageNumber = pageNumber,
            PageSize = pageSize,
            TotalPages = (int)Math.Ceiling((double)totalCount / pageSize)
        };
    }
    
    // 缓存优化
    public async Task<List<Department>> GetDepartmentsCachedAsync()
    {
        const string cacheKey = "departments_all";
        
        if (_cache.TryGetValue(cacheKey, out List<Department> cachedDepartments))
        {
            _logger.LogInformation("从缓存获取部门数据");
            return cachedDepartments;
        }
        
        var departments = await _context.Departments
            .OrderBy(d => d.Name)
            .ToListAsync();
        
        var cacheOptions = new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
            SlidingExpiration = TimeSpan.FromMinutes(5),
            Priority = CacheItemPriority.Normal
        };
        
        _cache.Set(cacheKey, departments, cacheOptions);
        _logger.LogInformation("部门数据已缓存");
        
        return departments;
    }
    
    // 异步流处理大量数据
    public async IAsyncEnumerable<Employee> GetAllEmployeesStreamAsync(
        [EnumeratorCancellation] CancellationToken cancellationToken = default)
    {
        const int batchSize = 1000;
        var skip = 0;
        
        while (true)
        {
            var batch = await _context.Employees
                .Include(e => e.Department)
                .OrderBy(e => e.Id)
                .Skip(skip)
                .Take(batchSize)
                .ToListAsync(cancellationToken);
            
            if (!batch.Any())
                break;
            
            foreach (var employee in batch)
            {
                yield return employee;
            }
            
            skip += batchSize;
        }
    }
    
    // 连接池优化示例
    public async Task<DatabaseConnectionInfo> GetConnectionInfoAsync()
    {
        var connectionString = _context.Database.GetConnectionString();
        var canConnect = await _context.Database.CanConnectAsync();
        
        // 获取连接池统计信息(需要特定的数据库提供程序支持)
        var poolInfo = new DatabaseConnectionInfo
        {
            ConnectionString = connectionString,
            CanConnect = canConnect,
            DatabaseName = _context.Database.GetDbConnection().Database,
            ServerVersion = _context.Database.GetDbConnection().ServerVersion,
            ConnectionTimeout = _context.Database.GetDbConnection().ConnectionTimeout
        };
        
        return poolInfo;
    }
    
    // 查询执行计划分析
    public async Task<string> AnalyzeQueryPlanAsync(string sql)
    {
        try
        {
            // 获取查询执行计划(SQL Server示例)
            var planQuery = $"SET SHOWPLAN_ALL ON; {sql}; SET SHOWPLAN_ALL OFF;";
            
            using var command = _context.Database.GetDbConnection().CreateCommand();
            command.CommandText = planQuery;
            
            await _context.Database.OpenConnectionAsync();
            
            using var reader = await command.ExecuteReaderAsync();
            var plan = new StringBuilder();
            
            while (await reader.ReadAsync())
            {
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    plan.AppendLine($"{reader.GetName(i)}: {reader.GetValue(i)}");
                }
                plan.AppendLine("---");
            }
            
            return plan.ToString();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "查询计划分析失败");
            return $"分析失败: {ex.Message}";
        }
        finally
        {
            await _context.Database.CloseConnectionAsync();
        }
    }
}

// 数据库监控服务
public class DatabaseMonitoringService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<DatabaseMonitoringService> _logger;
    
    public DatabaseMonitoringService(
        ApplicationDbContext context, 
        ILogger<DatabaseMonitoringService> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    // 性能监控
    public async Task<DatabasePerformanceMetrics> GetPerformanceMetricsAsync()
    {
        var stopwatch = Stopwatch.StartNew();
        
        // 测试简单查询性能
        var simpleQueryTime = await MeasureQueryTimeAsync(() => 
            _context.Employees.CountAsync());
        
        // 测试复杂查询性能
        var complexQueryTime = await MeasureQueryTimeAsync(() => 
            _context.Employees
                .Include(e => e.Department)
                .Include(e => e.EmployeeProjects)
                    .ThenInclude(ep => ep.Project)
                .ToListAsync());
        
        // 测试写入性能
        var writeTime = await MeasureWriteTimeAsync();
        
        stopwatch.Stop();
        
        return new DatabasePerformanceMetrics
        {
            SimpleQueryTime = simpleQueryTime,
            ComplexQueryTime = complexQueryTime,
            WriteTime = writeTime,
            TotalTestTime = stopwatch.ElapsedMilliseconds,
            Timestamp = DateTime.UtcNow
        };
    }
    
    private async Task<long> MeasureQueryTimeAsync(Func<Task> queryAction)
    {
        var stopwatch = Stopwatch.StartNew();
        await queryAction();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
    
    private async Task<long> MeasureWriteTimeAsync()
    {
        var stopwatch = Stopwatch.StartNew();
        
        // 创建测试数据
        var testEmployee = new Employee
        {
            FirstName = "Test",
            LastName = "Performance",
            Email = $"test.performance.{Guid.NewGuid()}@example.com",
            DepartmentId = 1,
            Salary = 50000,
            HireDate = DateTime.UtcNow
        };
        
        _context.Employees.Add(testEmployee);
        await _context.SaveChangesAsync();
        
        // 清理测试数据
        _context.Employees.Remove(testEmployee);
        await _context.SaveChangesAsync();
        
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
    
    // 数据库健康检查
    public async Task<DatabaseHealthStatus> CheckDatabaseHealthAsync()
    {
        var health = new DatabaseHealthStatus
        {
            CheckTime = DateTime.UtcNow
        };
        
        try
        {
            // 检查连接
            health.CanConnect = await _context.Database.CanConnectAsync();
            
            if (health.CanConnect)
            {
                // 检查表是否存在
                var tableCount = await _context.Database
                    .SqlQueryRaw<int>("SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE'")
                    .FirstOrDefaultAsync();
                
                health.TablesExist = tableCount > 0;
                
                // 检查数据完整性
                var employeeCount = await _context.Employees.CountAsync();
                var departmentCount = await _context.Departments.CountAsync();
                
                health.DataIntegrityCheck = employeeCount >= 0 && departmentCount >= 0;
                
                // 检查索引
                health.IndexesOptimal = await CheckIndexOptimizationAsync();
                
                health.IsHealthy = health.TablesExist && health.DataIntegrityCheck;
            }
        }
        catch (Exception ex)
        {
            health.IsHealthy = false;
            health.ErrorMessage = ex.Message;
            _logger.LogError(ex, "数据库健康检查失败");
        }
        
        return health;
    }
    
    private async Task<bool> CheckIndexOptimizationAsync()
    {
        try
        {
            // 检查索引碎片化(SQL Server示例)
            var fragmentationQuery = @"
                SELECT AVG(avg_fragmentation_in_percent) as AvgFragmentation
                FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED')
                WHERE index_id > 0";
            
            var avgFragmentation = await _context.Database
                .SqlQueryRaw<double>(fragmentationQuery)
                .FirstOrDefaultAsync();
            
            // 如果平均碎片化小于30%,认为索引状态良好
            return avgFragmentation < 30.0;
        }
        catch
        {
            // 如果无法检查索引状态,返回true避免误报
            return true;
        }
    }
}

// 性能相关的数据模型
public class EmployeeSummary
{
    public int Id { get; set; }
    public string FullName { get; set; }
    public string DepartmentName { get; set; }
    public decimal Salary { get; set; }
}

public class SalaryUpdate
{
    public int EmployeeId { get; set; }
    public decimal NewSalary { get; set; }
}

public class PagedResult<T>
{
    public List<T> Items { get; set; } = new();
    public int TotalCount { get; set; }
    public int PageNumber { get; set; }
    public int PageSize { get; set; }
    public int TotalPages { get; set; }
    public bool HasPreviousPage => PageNumber > 1;
    public bool HasNextPage => PageNumber < TotalPages;
}

public class DatabaseConnectionInfo
{
    public string ConnectionString { get; set; }
    public bool CanConnect { get; set; }
    public string DatabaseName { get; set; }
    public string ServerVersion { get; set; }
    public int ConnectionTimeout { get; set; }
}

public class DatabasePerformanceMetrics
{
    public long SimpleQueryTime { get; set; }
    public long ComplexQueryTime { get; set; }
    public long WriteTime { get; set; }
    public long TotalTestTime { get; set; }
    public DateTime Timestamp { get; set; }
}

public class DatabaseHealthStatus
{
    public DateTime CheckTime { get; set; }
    public bool CanConnect { get; set; }
    public bool TablesExist { get; set; }
    public bool DataIntegrityCheck { get; set; }
    public bool IndexesOptimal { get; set; }
    public bool IsHealthy { get; set; }
    public string ErrorMessage { get; set; }
}

数据库最佳实践

// 数据库最佳实践示例
public class DatabaseBestPracticesService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<DatabaseBestPracticesService> _logger;
    
    public DatabaseBestPracticesService(
        ApplicationDbContext context, 
        ILogger<DatabaseBestPracticesService> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    // 安全的参数化查询
    public async Task<List<Employee>> SearchEmployeesSafelyAsync(string searchTerm)
    {
        // 使用参数化查询防止SQL注入
        var sql = @"
            SELECT e.*, d.Name as DepartmentName
            FROM Employees e
            INNER JOIN Departments d ON e.DepartmentId = d.Id
            WHERE e.FirstName LIKE @searchTerm 
               OR e.LastName LIKE @searchTerm 
               OR e.Email LIKE @searchTerm";
        
        var parameter = new SqlParameter("@searchTerm", $"%{searchTerm}%");
        
        return await _context.Employees
            .FromSqlRaw(sql, parameter)
            .Include(e => e.Department)
            .ToListAsync();
    }
    
    // 数据验证和约束
    public async Task<ValidationResult> ValidateEmployeeDataAsync(Employee employee)
    {
        var result = new ValidationResult();
        
        // 检查邮箱唯一性
        var existingEmployee = await _context.Employees
            .FirstOrDefaultAsync(e => e.Email == employee.Email && e.Id != employee.Id);
        
        if (existingEmployee != null)
        {
            result.AddError("Email", "邮箱地址已存在");
        }
        
        // 检查部门是否存在
        var departmentExists = await _context.Departments
            .AnyAsync(d => d.Id == employee.DepartmentId);
        
        if (!departmentExists)
        {
            result.AddError("DepartmentId", "指定的部门不存在");
        }
        
        // 业务规则验证
        if (employee.Salary < 0)
        {
            result.AddError("Salary", "薪资不能为负数");
        }
        
        if (employee.HireDate > DateTime.UtcNow)
        {
            result.AddError("HireDate", "入职日期不能是未来时间");
        }
        
        return result;
    }
    
    // 审计日志
    public async Task<bool> CreateEmployeeWithAuditAsync(Employee employee, string createdBy)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            // 验证数据
            var validation = await ValidateEmployeeDataAsync(employee);
            if (!validation.IsValid)
            {
                _logger.LogWarning("员工数据验证失败: {Errors}", 
                    string.Join(", ", validation.Errors.Select(e => $"{e.Key}: {e.Value}")));
                return false;
            }
            
            // 创建员工
            _context.Employees.Add(employee);
            await _context.SaveChangesAsync();
            
            // 记录审计日志
            var auditLog = new AuditLog
            {
                TableName = "Employees",
                RecordId = employee.Id.ToString(),
                Action = "CREATE",
                OldValues = null,
                NewValues = JsonSerializer.Serialize(employee),
                UserId = createdBy,
                Timestamp = DateTime.UtcNow
            };
            
            _context.AuditLogs.Add(auditLog);
            await _context.SaveChangesAsync();
            
            await transaction.CommitAsync();
            
            _logger.LogInformation("员工 {EmployeeName} 创建成功,操作者: {CreatedBy}", 
                employee.FullName, createdBy);
            
            return true;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "创建员工失败");
            return false;
        }
    }
    
    // 软删除实现
    public async Task<bool> SoftDeleteEmployeeAsync(int employeeId, string deletedBy)
    {
        var employee = await _context.Employees.FindAsync(employeeId);
        if (employee == null)
        {
            return false;
        }
        
        // 实现软删除
        employee.IsDeleted = true;
        employee.DeletedAt = DateTime.UtcNow;
        employee.DeletedBy = deletedBy;
        
        // 记录审计日志
        var auditLog = new AuditLog
        {
            TableName = "Employees",
            RecordId = employeeId.ToString(),
            Action = "SOFT_DELETE",
            OldValues = JsonSerializer.Serialize(new { IsDeleted = false }),
            NewValues = JsonSerializer.Serialize(new { IsDeleted = true, DeletedAt = employee.DeletedAt }),
            UserId = deletedBy,
            Timestamp = DateTime.UtcNow
        };
        
        _context.AuditLogs.Add(auditLog);
        
        var result = await _context.SaveChangesAsync();
        
        _logger.LogInformation("员工 {EmployeeId} 已软删除,操作者: {DeletedBy}", 
            employeeId, deletedBy);
        
        return result > 0;
    }
    
    // 数据备份
    public async Task<bool> BackupEmployeeDataAsync(string backupPath)
    {
        try
        {
            var employees = await _context.Employees
                .Include(e => e.Department)
                .Where(e => !e.IsDeleted)
                .ToListAsync();
            
            var backup = new EmployeeBackup
            {
                BackupDate = DateTime.UtcNow,
                EmployeeCount = employees.Count,
                Employees = employees.Select(e => new EmployeeBackupData
                {
                    Id = e.Id,
                    FirstName = e.FirstName,
                    LastName = e.LastName,
                    Email = e.Email,
                    DepartmentName = e.Department?.Name,
                    Salary = e.Salary,
                    HireDate = e.HireDate
                }).ToList()
            };
            
            var json = JsonSerializer.Serialize(backup, new JsonSerializerOptions
            {
                WriteIndented = true,
                PropertyNamingPolicy = JsonNamingPolicy.CamelCase
            });
            
            await File.WriteAllTextAsync(backupPath, json);
            
            _logger.LogInformation("员工数据备份完成,文件: {BackupPath},记录数: {Count}", 
                backupPath, employees.Count);
            
            return true;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "员工数据备份失败");
            return false;
        }
    }
}

// 审计和验证相关的数据模型
public class AuditLog
{
    public int Id { get; set; }
    public string TableName { get; set; }
    public string RecordId { get; set; }
    public string Action { get; set; }
    public string OldValues { get; set; }
    public string NewValues { get; set; }
    public string UserId { get; set; }
    public DateTime Timestamp { get; set; }
}

public class ValidationResult
{
    public Dictionary<string, string> Errors { get; set; } = new();
    public bool IsValid => !Errors.Any();
    
    public void AddError(string field, string message)
    {
        Errors[field] = message;
    }
}

public class EmployeeBackup
{
    public DateTime BackupDate { get; set; }
    public int EmployeeCount { get; set; }
    public List<EmployeeBackupData> Employees { get; set; } = new();
}

public class EmployeeBackupData
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public string DepartmentName { get; set; }
    public decimal Salary { get; set; }
    public DateTime HireDate { get; set; }
}

// 扩展Employee模型以支持软删除
public partial class Employee
{
    public bool IsDeleted { get; set; }
    public DateTime? DeletedAt { get; set; }
    public string DeletedBy { get; set; }
}

18.6 实践练习

练习1:员工管理系统

// 完整的员工管理系统
public class EmployeeManagementSystem
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<EmployeeManagementSystem> _logger;
    private readonly TransactionService _transactionService;
    private readonly QueryService _queryService;
    private readonly PerformanceOptimizationService _performanceService;
    private readonly DatabaseBestPracticesService _bestPracticesService;
    
    public EmployeeManagementSystem(
        ApplicationDbContext context,
        ILogger<EmployeeManagementSystem> logger,
        TransactionService transactionService,
        QueryService queryService,
        PerformanceOptimizationService performanceService,
        DatabaseBestPracticesService bestPracticesService)
    {
        _context = context;
        _logger = logger;
        _transactionService = transactionService;
        _queryService = queryService;
        _performanceService = performanceService;
        _bestPracticesService = bestPracticesService;
    }
    
    // 员工入职流程
    public async Task<EmployeeOnboardingResult> OnboardEmployeeAsync(EmployeeOnboardingRequest request)
    {
        var result = new EmployeeOnboardingResult();
        
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            // 1. 创建员工记录
            var employee = new Employee
            {
                FirstName = request.FirstName,
                LastName = request.LastName,
                Email = request.Email,
                DepartmentId = request.DepartmentId,
                Salary = request.Salary,
                HireDate = DateTime.UtcNow
            };
            
            // 2. 验证员工数据
            var validation = await _bestPracticesService.ValidateEmployeeDataAsync(employee);
            if (!validation.IsValid)
            {
                result.Success = false;
                result.Errors = validation.Errors;
                return result;
            }
            
            // 3. 创建员工
            _context.Employees.Add(employee);
            await _context.SaveChangesAsync();
            
            // 4. 分配到项目(如果指定)
            if (request.ProjectAssignments?.Any() == true)
            {
                var assignments = request.ProjectAssignments.Select(pa => new EmployeeProjectAssignment
                {
                    EmployeeId = employee.Id,
                    Role = pa.Role,
                    HoursAllocated = pa.HoursAllocated
                }).ToList();
                
                foreach (var assignment in request.ProjectAssignments)
                {
                    var success = await _transactionService.AssignEmployeesToProjectAsync(
                        assignment.ProjectId, 
                        new List<EmployeeProjectAssignment> { new EmployeeProjectAssignment
                        {
                            EmployeeId = employee.Id,
                            Role = assignment.Role,
                            HoursAllocated = assignment.HoursAllocated
                        }});
                    
                    if (!success)
                    {
                        throw new InvalidOperationException($"无法将员工分配到项目 {assignment.ProjectId}");
                    }
                }
            }
            
            // 5. 创建入职记录
            var onboardingRecord = new EmployeeOnboarding
            {
                EmployeeId = employee.Id,
                OnboardingDate = DateTime.UtcNow,
                Status = "进行中",
                AssignedMentorId = request.MentorId,
                CompletionDeadline = DateTime.UtcNow.AddDays(30)
            };
            
            _context.EmployeeOnboardings.Add(onboardingRecord);
            await _context.SaveChangesAsync();
            
            await transaction.CommitAsync();
            
            result.Success = true;
            result.EmployeeId = employee.Id;
            result.OnboardingId = onboardingRecord.Id;
            
            _logger.LogInformation("员工 {EmployeeName} 入职成功,ID: {EmployeeId}", 
                employee.FullName, employee.Id);
            
            return result;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "员工入职失败");
            
            result.Success = false;
            result.Errors["General"] = ex.Message;
            return result;
        }
    }
    
    // 员工离职流程
    public async Task<bool> OffboardEmployeeAsync(int employeeId, string reason, string processedBy)
    {
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            var employee = await _context.Employees
                .Include(e => e.EmployeeProjects)
                .FirstOrDefaultAsync(e => e.Id == employeeId);
            
            if (employee == null)
            {
                return false;
            }
            
            // 1. 从所有项目中移除
            if (employee.EmployeeProjects.Any())
            {
                _context.EmployeeProjects.RemoveRange(employee.EmployeeProjects);
            }
            
            // 2. 软删除员工
            await _bestPracticesService.SoftDeleteEmployeeAsync(employeeId, processedBy);
            
            // 3. 创建离职记录
            var offboardingRecord = new EmployeeOffboarding
            {
                EmployeeId = employeeId,
                OffboardingDate = DateTime.UtcNow,
                Reason = reason,
                ProcessedBy = processedBy,
                FinalSalary = employee.Salary
            };
            
            _context.EmployeeOffboardings.Add(offboardingRecord);
            await _context.SaveChangesAsync();
            
            await transaction.CommitAsync();
            
            _logger.LogInformation("员工 {EmployeeId} 离职处理完成,原因: {Reason}", 
                employeeId, reason);
            
            return true;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "员工离职处理失败");
            return false;
        }
    }
    
    // 生成员工报告
    public async Task<EmployeeReport> GenerateEmployeeReportAsync(int employeeId)
    {
        var employee = await _context.Employees
            .Include(e => e.Department)
            .Include(e => e.EmployeeProjects)
                .ThenInclude(ep => ep.Project)
            .FirstOrDefaultAsync(e => e.Id == employeeId);
        
        if (employee == null)
        {
            return null;
        }
        
        // 获取薪资历史
        var salaryHistory = await _context.PayrollRecords
            .Where(pr => pr.EmployeeId == employeeId)
            .OrderByDescending(pr => pr.ProcessedDate)
            .Take(12)
            .ToListAsync();
        
        // 获取转移历史
        var transferHistory = await _context.EmployeeTransferHistories
            .Where(eth => eth.EmployeeId == employeeId)
            .Include(eth => eth.FromDepartment)
            .Include(eth => eth.ToDepartment)
            .OrderByDescending(eth => eth.TransferDate)
            .ToListAsync();
        
        // 计算绩效指标
        var totalProjectHours = employee.EmployeeProjects.Sum(ep => ep.HoursAllocated);
        var activeProjects = employee.EmployeeProjects.Count(ep => ep.Project.Status == "进行中");
        
        return new EmployeeReport
        {
            Employee = employee,
            SalaryHistory = salaryHistory,
            TransferHistory = transferHistory,
            TotalProjectHours = totalProjectHours,
            ActiveProjectsCount = activeProjects,
            AverageMonthlySalary = salaryHistory.Any() ? salaryHistory.Average(sh => sh.TotalPay) : employee.Salary,
            GeneratedDate = DateTime.UtcNow
        };
    }
    
    // 批量薪资调整
    public async Task<BatchSalaryAdjustmentResult> BatchAdjustSalariesAsync(
        List<SalaryAdjustment> adjustments, 
        string adjustedBy)
    {
        var result = new BatchSalaryAdjustmentResult();
        
        using var transaction = await _context.Database.BeginTransactionAsync();
        
        try
        {
            var employeeIds = adjustments.Select(a => a.EmployeeId).ToList();
            var employees = await _context.Employees
                .Where(e => employeeIds.Contains(e.Id))
                .ToListAsync();
            
            var adjustmentDict = adjustments.ToDictionary(a => a.EmployeeId);
            var processedAdjustments = new List<ProcessedSalaryAdjustment>();
            
            foreach (var employee in employees)
            {
                if (adjustmentDict.TryGetValue(employee.Id, out var adjustment))
                {
                    var oldSalary = employee.Salary;
                    var newSalary = adjustment.AdjustmentType == "Percentage" 
                        ? oldSalary * (1 + adjustment.Amount / 100)
                        : oldSalary + adjustment.Amount;
                    
                    employee.Salary = newSalary;
                    
                    processedAdjustments.Add(new ProcessedSalaryAdjustment
                    {
                        EmployeeId = employee.Id,
                        EmployeeName = employee.FullName,
                        OldSalary = oldSalary,
                        NewSalary = newSalary,
                        AdjustmentAmount = newSalary - oldSalary,
                        AdjustmentType = adjustment.AdjustmentType,
                        Reason = adjustment.Reason
                    });
                }
            }
            
            await _context.SaveChangesAsync();
            
            // 记录批量调整历史
            var batchRecord = new BatchSalaryAdjustmentHistory
            {
                AdjustmentDate = DateTime.UtcNow,
                ProcessedBy = adjustedBy,
                TotalEmployees = processedAdjustments.Count,
                TotalAdjustmentAmount = processedAdjustments.Sum(pa => pa.AdjustmentAmount),
                Details = JsonSerializer.Serialize(processedAdjustments)
            };
            
            _context.BatchSalaryAdjustmentHistories.Add(batchRecord);
            await _context.SaveChangesAsync();
            
            await transaction.CommitAsync();
            
            result.Success = true;
            result.ProcessedAdjustments = processedAdjustments;
            result.BatchId = batchRecord.Id;
            
            _logger.LogInformation("批量薪资调整完成,处理 {Count} 个员工,总调整金额: {Amount:C}", 
                processedAdjustments.Count, batchRecord.TotalAdjustmentAmount);
            
            return result;
        }
        catch (Exception ex)
        {
            await transaction.RollbackAsync();
            _logger.LogError(ex, "批量薪资调整失败");
            
            result.Success = false;
            result.ErrorMessage = ex.Message;
            return result;
        }
    }
}

// 员工管理系统相关的数据模型
public class EmployeeOnboardingRequest
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Email { get; set; }
    public int DepartmentId { get; set; }
    public decimal Salary { get; set; }
    public int? MentorId { get; set; }
    public List<ProjectAssignmentRequest> ProjectAssignments { get; set; } = new();
}

public class ProjectAssignmentRequest
{
    public int ProjectId { get; set; }
    public string Role { get; set; }
    public int HoursAllocated { get; set; }
}

public class EmployeeOnboardingResult
{
    public bool Success { get; set; }
    public int EmployeeId { get; set; }
    public int OnboardingId { get; set; }
    public Dictionary<string, string> Errors { get; set; } = new();
}

public class EmployeeOnboarding
{
    public int Id { get; set; }
    public int EmployeeId { get; set; }
    public DateTime OnboardingDate { get; set; }
    public string Status { get; set; }
    public int? AssignedMentorId { get; set; }
    public DateTime CompletionDeadline { get; set; }
    public DateTime? CompletedDate { get; set; }
    
    // 导航属性
    public Employee Employee { get; set; }
    public Employee AssignedMentor { get; set; }
}

public class EmployeeOffboarding
{
    public int Id { get; set; }
    public int EmployeeId { get; set; }
    public DateTime OffboardingDate { get; set; }
    public string Reason { get; set; }
    public string ProcessedBy { get; set; }
    public decimal FinalSalary { get; set; }
    
    // 导航属性
    public Employee Employee { get; set; }
}

public class EmployeeReport
{
    public Employee Employee { get; set; }
    public List<PayrollRecord> SalaryHistory { get; set; } = new();
    public List<EmployeeTransferHistory> TransferHistory { get; set; } = new();
    public int TotalProjectHours { get; set; }
    public int ActiveProjectsCount { get; set; }
    public decimal AverageMonthlySalary { get; set; }
    public DateTime GeneratedDate { get; set; }
}

public class SalaryAdjustment
{
    public int EmployeeId { get; set; }
    public decimal Amount { get; set; }
    public string AdjustmentType { get; set; } // "Fixed" or "Percentage"
    public string Reason { get; set; }
}

public class ProcessedSalaryAdjustment
{
    public int EmployeeId { get; set; }
    public string EmployeeName { get; set; }
    public decimal OldSalary { get; set; }
    public decimal NewSalary { get; set; }
    public decimal AdjustmentAmount { get; set; }
    public string AdjustmentType { get; set; }
    public string Reason { get; set; }
}

public class BatchSalaryAdjustmentResult
{
    public bool Success { get; set; }
    public int BatchId { get; set; }
    public List<ProcessedSalaryAdjustment> ProcessedAdjustments { get; set; } = new();
    public string ErrorMessage { get; set; }
}

public class BatchSalaryAdjustmentHistory
{
    public int Id { get; set; }
    public DateTime AdjustmentDate { get; set; }
    public string ProcessedBy { get; set; }
    public int TotalEmployees { get; set; }
    public decimal TotalAdjustmentAmount { get; set; }
    public string Details { get; set; }
}

练习2:数据分析和报告系统

// 数据分析和报告系统
public class DataAnalyticsService
{
    private readonly ApplicationDbContext _context;
    private readonly ILogger<DataAnalyticsService> _logger;
    
    public DataAnalyticsService(ApplicationDbContext context, ILogger<DataAnalyticsService> logger)
    {
        _context = context;
        _logger = logger;
    }
    
    // 生成综合分析报告
    public async Task<ComprehensiveAnalyticsReport> GenerateComprehensiveReportAsync(
        DateTime startDate, 
        DateTime endDate)
    {
        var report = new ComprehensiveAnalyticsReport
        {
            ReportPeriod = new DateRange { StartDate = startDate, EndDate = endDate },
            GeneratedDate = DateTime.UtcNow
        };
        
        // 员工统计
        report.EmployeeAnalytics = await GenerateEmployeeAnalyticsAsync(startDate, endDate);
        
        // 部门分析
        report.DepartmentAnalytics = await GenerateDepartmentAnalyticsAsync(startDate, endDate);
        
        // 项目分析
        report.ProjectAnalytics = await GenerateProjectAnalyticsAsync(startDate, endDate);
        
        // 薪资分析
        report.SalaryAnalytics = await GenerateSalaryAnalyticsAsync(startDate, endDate);
        
        // 趋势分析
        report.TrendAnalytics = await GenerateTrendAnalyticsAsync(startDate, endDate);
        
        return report;
    }
    
    private async Task<EmployeeAnalytics> GenerateEmployeeAnalyticsAsync(DateTime startDate, DateTime endDate)
    {
        var totalEmployees = await _context.Employees.CountAsync(e => !e.IsDeleted);
        
        var newHires = await _context.Employees
            .CountAsync(e => e.HireDate >= startDate && e.HireDate <= endDate);
        
        var departures = await _context.EmployeeOffboardings
            .CountAsync(eo => eo.OffboardingDate >= startDate && eo.OffboardingDate <= endDate);
        
        var avgTenure = await _context.Employees
            .Where(e => !e.IsDeleted)
            .Select(e => EF.Functions.DateDiffDay(e.HireDate, DateTime.UtcNow))
            .AverageAsync();
        
        var turnoverRate = totalEmployees > 0 ? (double)departures / totalEmployees * 100 : 0;
        
        return new EmployeeAnalytics
        {
            TotalEmployees = totalEmployees,
            NewHires = newHires,
            Departures = departures,
            NetChange = newHires - departures,
            TurnoverRate = turnoverRate,
            AverageTenureDays = avgTenure
        };
    }
    
    private async Task<List<DepartmentAnalytics>> GenerateDepartmentAnalyticsAsync(DateTime startDate, DateTime endDate)
    {
        return await _context.Departments
            .Select(d => new DepartmentAnalytics
            {
                DepartmentId = d.Id,
                DepartmentName = d.Name,
                EmployeeCount = d.Employees.Count(e => !e.IsDeleted),
                AverageSalary = d.Employees.Where(e => !e.IsDeleted).Average(e => e.Salary),
                TotalSalaryExpense = d.Employees.Where(e => !e.IsDeleted).Sum(e => e.Salary),
                NewHires = d.Employees.Count(e => e.HireDate >= startDate && e.HireDate <= endDate),
                ActiveProjects = d.Employees
                    .SelectMany(e => e.EmployeeProjects)
                    .Select(ep => ep.Project)
                    .Distinct()
                    .Count(p => p.Status == "进行中"),
                Budget = d.Budget,
                BudgetUtilization = d.Budget > 0 ? 
                    d.Employees.Where(e => !e.IsDeleted).Sum(e => e.Salary) / d.Budget * 100 : 0
            })
            .ToListAsync();
    }
    
    private async Task<ProjectAnalytics> GenerateProjectAnalyticsAsync(DateTime startDate, DateTime endDate)
    {
        var totalProjects = await _context.Projects.CountAsync();
        var activeProjects = await _context.Projects.CountAsync(p => p.Status == "进行中");
        var completedProjects = await _context.Projects.CountAsync(p => p.Status == "已完成");
        
        var totalBudget = await _context.Projects.SumAsync(p => p.Budget);
        var avgBudget = await _context.Projects.AverageAsync(p => p.Budget);
        
        var projectsByStatus = await _context.Projects
            .GroupBy(p => p.Status)
            .Select(g => new ProjectStatusCount
            {
                Status = g.Key,
                Count = g.Count(),
                TotalBudget = g.Sum(p => p.Budget)
            })
            .ToListAsync();
        
        return new ProjectAnalytics
        {
            TotalProjects = totalProjects,
            ActiveProjects = activeProjects,
            CompletedProjects = completedProjects,
            TotalBudget = totalBudget,
            AverageBudget = avgBudget,
            ProjectsByStatus = projectsByStatus
        };
    }
    
    private async Task<SalaryAnalytics> GenerateSalaryAnalyticsAsync(DateTime startDate, DateTime endDate)
    {
        var salaryStats = await _context.Employees
            .Where(e => !e.IsDeleted)
            .GroupBy(e => 1)
            .Select(g => new
            {
                MinSalary = g.Min(e => e.Salary),
                MaxSalary = g.Max(e => e.Salary),
                AverageSalary = g.Average(e => e.Salary),
                MedianSalary = g.OrderBy(e => e.Salary)
                    .Skip(g.Count() / 2)
                    .Take(1)
                    .Select(e => e.Salary)
                    .FirstOrDefault(),
                TotalSalaryExpense = g.Sum(e => e.Salary)
            })
            .FirstOrDefaultAsync();
        
        var salaryRanges = await _context.Employees
            .Where(e => !e.IsDeleted)
            .GroupBy(e => 
                e.Salary < 50000 ? "< 50K" :
                e.Salary < 75000 ? "50K - 75K" :
                e.Salary < 100000 ? "75K - 100K" :
                e.Salary < 150000 ? "100K - 150K" : "> 150K")
            .Select(g => new SalaryRangeCount
            {
                Range = g.Key,
                Count = g.Count(),
                Percentage = (double)g.Count() / _context.Employees.Count(e => !e.IsDeleted) * 100
            })
            .ToListAsync();
        
        return new SalaryAnalytics
        {
            MinSalary = salaryStats?.MinSalary ?? 0,
            MaxSalary = salaryStats?.MaxSalary ?? 0,
            AverageSalary = salaryStats?.AverageSalary ?? 0,
            MedianSalary = salaryStats?.MedianSalary ?? 0,
            TotalSalaryExpense = salaryStats?.TotalSalaryExpense ?? 0,
            SalaryRanges = salaryRanges
        };
    }
    
    private async Task<TrendAnalytics> GenerateTrendAnalyticsAsync(DateTime startDate, DateTime endDate)
    {
        // 按月统计雇佣趋势
        var hiringTrend = await _context.Employees
            .Where(e => e.HireDate >= startDate && e.HireDate <= endDate)
            .GroupBy(e => new { Year = e.HireDate.Year, Month = e.HireDate.Month })
            .Select(g => new MonthlyTrend
            {
                Year = g.Key.Year,
                Month = g.Key.Month,
                Count = g.Count()
            })
            .OrderBy(mt => mt.Year)
            .ThenBy(mt => mt.Month)
            .ToListAsync();
        
        // 按月统计离职趋势
        var departureTrend = await _context.EmployeeOffboardings
            .Where(eo => eo.OffboardingDate >= startDate && eo.OffboardingDate <= endDate)
            .GroupBy(eo => new { Year = eo.OffboardingDate.Year, Month = eo.OffboardingDate.Month })
            .Select(g => new MonthlyTrend
            {
                Year = g.Key.Year,
                Month = g.Key.Month,
                Count = g.Count()
            })
            .OrderBy(mt => mt.Year)
            .ThenBy(mt => mt.Month)
            .ToListAsync();
        
        return new TrendAnalytics
        {
            HiringTrend = hiringTrend,
            DepartureTrend = departureTrend
        };
    }
    
    // 导出报告到Excel
    public async Task<byte[]> ExportReportToExcelAsync(ComprehensiveAnalyticsReport report)
    {
        // 这里可以使用EPPlus或其他Excel库来生成Excel文件
        // 为了简化,这里返回一个模拟的字节数组
        var json = JsonSerializer.Serialize(report, new JsonSerializerOptions
        {
            WriteIndented = true,
            PropertyNamingPolicy = JsonNamingPolicy.CamelCase
        });
        
        return Encoding.UTF8.GetBytes(json);
    }
}

// 数据分析相关的数据模型
public class ComprehensiveAnalyticsReport
{
    public DateRange ReportPeriod { get; set; }
    public DateTime GeneratedDate { get; set; }
    public EmployeeAnalytics EmployeeAnalytics { get; set; }
    public List<DepartmentAnalytics> DepartmentAnalytics { get; set; } = new();
    public ProjectAnalytics ProjectAnalytics { get; set; }
    public SalaryAnalytics SalaryAnalytics { get; set; }
    public TrendAnalytics TrendAnalytics { get; set; }
}

public class DateRange
{
    public DateTime StartDate { get; set; }
    public DateTime EndDate { get; set; }
}

public class EmployeeAnalytics
{
    public int TotalEmployees { get; set; }
    public int NewHires { get; set; }
    public int Departures { get; set; }
    public int NetChange { get; set; }
    public double TurnoverRate { get; set; }
    public double AverageTenureDays { get; set; }
}

public class DepartmentAnalytics
{
    public int DepartmentId { get; set; }
    public string DepartmentName { get; set; }
    public int EmployeeCount { get; set; }
    public decimal AverageSalary { get; set; }
    public decimal TotalSalaryExpense { get; set; }
    public int NewHires { get; set; }
    public int ActiveProjects { get; set; }
    public decimal Budget { get; set; }
    public double BudgetUtilization { get; set; }
}

public class ProjectAnalytics
{
    public int TotalProjects { get; set; }
    public int ActiveProjects { get; set; }
    public int CompletedProjects { get; set; }
    public decimal TotalBudget { get; set; }
    public decimal AverageBudget { get; set; }
    public List<ProjectStatusCount> ProjectsByStatus { get; set; } = new();
}

public class ProjectStatusCount
{
    public string Status { get; set; }
    public int Count { get; set; }
    public decimal TotalBudget { get; set; }
}

public class SalaryAnalytics
{
    public decimal MinSalary { get; set; }
    public decimal MaxSalary { get; set; }
    public decimal AverageSalary { get; set; }
    public decimal MedianSalary { get; set; }
    public decimal TotalSalaryExpense { get; set; }
    public List<SalaryRangeCount> SalaryRanges { get; set; } = new();
}

public class SalaryRangeCount
{
    public string Range { get; set; }
    public int Count { get; set; }
    public double Percentage { get; set; }
}

public class TrendAnalytics
{
    public List<MonthlyTrend> HiringTrend { get; set; } = new();
    public List<MonthlyTrend> DepartureTrend { get; set; } = new();
}

public class MonthlyTrend
{
    public int Year { get; set; }
    public int Month { get; set; }
    public int Count { get; set; }
}

练习演示

// 数据库编程演示
public class DatabaseProgrammingDemo
{
    private readonly EmployeeManagementSystem _employeeSystem;
    private readonly DataAnalyticsService _analyticsService;
    private readonly ILogger<DatabaseProgrammingDemo> _logger;
    
    public DatabaseProgrammingDemo(
        EmployeeManagementSystem employeeSystem,
        DataAnalyticsService analyticsService,
        ILogger<DatabaseProgrammingDemo> logger)
    {
        _employeeSystem = employeeSystem;
        _analyticsService = analyticsService;
        _logger = logger;
    }
    
    public async Task RunDemoAsync()
    {
        _logger.LogInformation("开始数据库编程演示");
        
        try
        {
            // 1. 员工入职演示
            await DemoEmployeeOnboardingAsync();
            
            // 2. 批量薪资调整演示
            await DemoBatchSalaryAdjustmentAsync();
            
            // 3. 数据分析报告演示
            await DemoAnalyticsReportAsync();
            
            // 4. 员工离职演示
            await DemoEmployeeOffboardingAsync();
            
            _logger.LogInformation("数据库编程演示完成");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "演示过程中发生错误");
        }
    }
    
    private async Task DemoEmployeeOnboardingAsync()
    {
        _logger.LogInformation("演示员工入职流程");
        
        var onboardingRequest = new EmployeeOnboardingRequest
        {
            FirstName = "张",
            LastName = "三",
            Email = "zhangsan@company.com",
            DepartmentId = 1,
            Salary = 80000,
            MentorId = 1,
            ProjectAssignments = new List<ProjectAssignmentRequest>
            {
                new ProjectAssignmentRequest
                {
                    ProjectId = 1,
                    Role = "开发工程师",
                    HoursAllocated = 40
                }
            }
        };
        
        var result = await _employeeSystem.OnboardEmployeeAsync(onboardingRequest);
        
        if (result.Success)
        {
            _logger.LogInformation("员工入职成功,员工ID: {EmployeeId}", result.EmployeeId);
            
            // 生成员工报告
            var report = await _employeeSystem.GenerateEmployeeReportAsync(result.EmployeeId);
            _logger.LogInformation("员工报告生成完成,活跃项目数: {ActiveProjects}", 
                report.ActiveProjectsCount);
        }
        else
        {
            _logger.LogWarning("员工入职失败: {Errors}", 
                string.Join(", ", result.Errors.Select(e => $"{e.Key}: {e.Value}")));
        }
    }
    
    private async Task DemoBatchSalaryAdjustmentAsync()
    {
        _logger.LogInformation("演示批量薪资调整");
        
        var adjustments = new List<SalaryAdjustment>
        {
            new SalaryAdjustment
            {
                EmployeeId = 1,
                Amount = 10,
                AdjustmentType = "Percentage",
                Reason = "年度调薪"
            },
            new SalaryAdjustment
            {
                EmployeeId = 2,
                Amount = 5000,
                AdjustmentType = "Fixed",
                Reason = "晋升调薪"
            }
        };
        
        var result = await _employeeSystem.BatchAdjustSalariesAsync(adjustments, "HR Manager");
        
        if (result.Success)
        {
            _logger.LogInformation("批量薪资调整成功,处理 {Count} 个员工", 
                result.ProcessedAdjustments.Count);
            
            foreach (var adjustment in result.ProcessedAdjustments)
            {
                _logger.LogInformation("员工 {Name}: {OldSalary:C} -> {NewSalary:C} (调整: {Amount:C})",
                    adjustment.EmployeeName, adjustment.OldSalary, 
                    adjustment.NewSalary, adjustment.AdjustmentAmount);
            }
        }
        else
        {
            _logger.LogWarning("批量薪资调整失败: {Error}", result.ErrorMessage);
        }
    }
    
    private async Task DemoAnalyticsReportAsync()
    {
        _logger.LogInformation("演示数据分析报告生成");
        
        var startDate = DateTime.UtcNow.AddMonths(-12);
        var endDate = DateTime.UtcNow;
        
        var report = await _analyticsService.GenerateComprehensiveReportAsync(startDate, endDate);
        
        _logger.LogInformation("分析报告生成完成:");
        _logger.LogInformation("- 总员工数: {TotalEmployees}", report.EmployeeAnalytics.TotalEmployees);
        _logger.LogInformation("- 新入职: {NewHires}", report.EmployeeAnalytics.NewHires);
        _logger.LogInformation("- 离职: {Departures}", report.EmployeeAnalytics.Departures);
        _logger.LogInformation("- 流失率: {TurnoverRate:F2}%", report.EmployeeAnalytics.TurnoverRate);
        _logger.LogInformation("- 平均薪资: {AverageSalary:C}", report.SalaryAnalytics.AverageSalary);
        _logger.LogInformation("- 活跃项目: {ActiveProjects}", report.ProjectAnalytics.ActiveProjects);
        
        // 导出报告
        var excelData = await _analyticsService.ExportReportToExcelAsync(report);
        _logger.LogInformation("报告已导出,大小: {Size} 字节", excelData.Length);
    }
    
    private async Task DemoEmployeeOffboardingAsync()
    {
        _logger.LogInformation("演示员工离职流程");
        
        // 假设员工ID为1的员工离职
        var success = await _employeeSystem.OffboardEmployeeAsync(1, "个人发展", "HR Manager");
        
        if (success)
        {
            _logger.LogInformation("员工离职处理完成");
        }
        else
        {
            _logger.LogWarning("员工离职处理失败");
        }
    }
}

18.7 本章总结

在本章中,我们深入学习了C#数据库编程的各个方面:

核心概念

  • ADO.NET基础:连接字符串管理、基本数据库操作、参数化查询
  • Entity Framework Core:DbContext配置、实体关系映射、Code First开发
  • 事务管理:ACID特性、事务隔离级别、分布式事务处理
  • LINQ查询:复杂查询构建、性能优化、原生SQL集成

高级技术

  • 性能优化:查询优化、缓存策略、批量操作、异步流处理
  • 数据库监控:性能指标收集、健康检查、索引优化分析
  • 最佳实践:安全编程、数据验证、审计日志、软删除实现

实际应用

  • 员工管理系统:完整的业务流程实现,包括入职、离职、薪资管理
  • 数据分析系统:综合报告生成、趋势分析、数据可视化支持
  • 企业级功能:批量操作、事务处理、数据备份恢复

重要技能

  • 掌握现代数据库开发模式和最佳实践
  • 理解性能优化和监控的重要性
  • 学会设计可扩展和可维护的数据访问层
  • 具备处理复杂业务逻辑和数据关系的能力

数据库编程是现代应用开发的核心技能,通过本章的学习,你已经具备了开发企业级数据库应用的能力。下一章我们将学习单元测试和集成测试,了解如何确保代码质量和系统可靠性。