# Windows窗体 + SQL Server 自动清理功能完整方案优化版

Windows窗体 + SQL Server 自动清理功能实现

一、数据库脚本(SQL Server)

sql 复制代码
-- ============================================================
-- 数据库清理系统 - 表结构创建脚本
-- ============================================================

USE master;
GO

-- 如果数据库已存在,先删除
IF EXISTS (SELECT name FROM sys.databases WHERE name = 'AutoCleanupDB')
    DROP DATABASE AutoCleanupDB;
GO

-- 创建数据库
CREATE DATABASE AutoCleanupDB;
GO

USE AutoCleanupDB;
GO

-- ============================================================
-- 1. 主数据表 - 用于测试清理功能
-- ============================================================
CREATE TABLE LogData
(
    Id BIGINT PRIMARY KEY IDENTITY(1,1),
    Content NVARCHAR(MAX),
    LogLevel INT,
    CreateTime DATETIME DEFAULT GETDATE(),
    Category NVARCHAR(100),
    INDEX IX_LogData_CreateTime (CreateTime DESC),
    INDEX IX_LogData_Category (Category)
);
GO

-- ============================================================
-- 2. 清理配置表 - 存储清理规则配置
-- ============================================================
CREATE TABLE CleanupConfig
(
    Id INT PRIMARY KEY IDENTITY(1,1),
    ConfigName NVARCHAR(100) NOT NULL UNIQUE,
    TableName NVARCHAR(100) NOT NULL,
    Mode INT NOT NULL, -- 1:按数量 2:按日期
    MaxRows INT NULL, -- 按数量模式时使用:保留最新的N条记录
    KeepDays INT NULL, -- 按日期模式时使用:保留最近N天的记录
    Enabled BIT DEFAULT 1,
    LastCleanTime DATETIME NULL,
    ScheduleType INT DEFAULT 1, -- 1:每日 2:每周 3:每月
    NextCleanTime DATETIME NULL,
    CreatedTime DATETIME DEFAULT GETDATE(),
    Description NVARCHAR(500) NULL,
    INDEX IX_CleanupConfig_Enabled (Enabled),
    INDEX IX_CleanupConfig_NextCleanTime (NextCleanTime)
);
GO

-- ============================================================
-- 3. 清理历史记录表 - 记录每次清理操作
-- ============================================================
CREATE TABLE CleanupHistory
(
    Id BIGINT PRIMARY KEY IDENTITY(1,1),
    ConfigId INT NOT NULL,
    ConfigName NVARCHAR(100),
    TableName NVARCHAR(100),
    CleanMode INT, -- 1:按数量 2:按日期
    DeletedRows INT,
    StartTime DATETIME DEFAULT GETDATE(),
    EndTime DATETIME NULL,
    DurationMs INT NULL,
    Status INT DEFAULT 0, -- 0:进行中 1:成功 2:失败
    ErrorMessage NVARCHAR(MAX),
    FOREIGN KEY (ConfigId) REFERENCES CleanupConfig(Id) ON DELETE CASCADE,
    INDEX IX_CleanupHistory_StartTime (StartTime DESC),
    INDEX IX_CleanupHistory_ConfigId (ConfigId)
);
GO

-- ============================================================
-- 4. 存储过程 - 按数量清理数据
-- ============================================================
CREATE PROCEDURE usp_CleanupByRows
    @TableName NVARCHAR(100),
    @MaxRows INT,
    @DeletedRows INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @SQL NVARCHAR(MAX);
    DECLARE @StartTime DATETIME = GETDATE();
    DECLARE @ErrorMsg NVARCHAR(MAX);
    
    BEGIN TRY
        BEGIN TRANSACTION;
        
        -- 按数量清理:删除超过最大行数的旧记录
        SET @SQL = N'
            WITH NumberedRows AS (
                SELECT Id, ROW_NUMBER() OVER (ORDER BY CreateTime DESC) AS RowNum
                FROM ' + QUOTENAME(@TableName) + '
            )
            DELETE FROM NumberedRows WHERE RowNum > @MaxRowsParam;
        ';
        
        EXEC sp_executesql @SQL, N'@MaxRowsParam INT', @MaxRowsParam = @MaxRows;
        
        SET @DeletedRows = @@ROWCOUNT;
        
        -- 更新统计信息
        IF @DeletedRows > 0
        BEGIN
            SET @SQL = N'UPDATE STATISTICS ' + QUOTENAME(@TableName) + ';';
            EXEC sp_executesql @SQL;
        END
        
        COMMIT TRANSACTION;
        
        PRINT '按数量清理完成:表 ' + @TableName + ',删除 ' + CAST(@DeletedRows AS NVARCHAR(10)) + ' 行数据';
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        SET @ErrorMsg = ERROR_MESSAGE();
        SET @DeletedRows = -1;
        RAISERROR('清理失败:%s', 16, 1, @ErrorMsg);
    END CATCH
END;
GO

-- ============================================================
-- 5. 存储过程 - 按日期清理数据
-- ============================================================
CREATE PROCEDURE usp_CleanupByDate
    @TableName NVARCHAR(100),
    @KeepDays INT,
    @DeletedRows INT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @SQL NVARCHAR(MAX);
    DECLARE @CutoffDate DATETIME = DATEADD(DAY, -@KeepDays, GETDATE());
    DECLARE @ErrorMsg NVARCHAR(MAX);
    
    BEGIN TRY
        BEGIN TRANSACTION;
        
        -- 按日期清理:删除超过保留天数的记录
        SET @SQL = N'
            DELETE FROM ' + QUOTENAME(@TableName) + '
            WHERE CreateTime < @CutoffDateParam;
        ';
        
        EXEC sp_executesql @SQL, N'@CutoffDateParam DATETIME', @CutoffDateParam = @CutoffDate;
        
        SET @DeletedRows = @@ROWCOUNT;
        
        -- 更新统计信息
        IF @DeletedRows > 0
        BEGIN
            SET @SQL = N'UPDATE STATISTICS ' + QUOTENAME(@TableName) + ';';
            EXEC sp_executesql @SQL;
        END
        
        COMMIT TRANSACTION;
        
        PRINT '按日期清理完成:表 ' + @TableName + ',删除 ' + CAST(@DeletedRows AS NVARCHAR(10)) + ' 行数据';
    END TRY
    BEGIN CATCH
        ROLLBACK TRANSACTION;
        SET @ErrorMsg = ERROR_MESSAGE();
        SET @DeletedRows = -1;
        RAISERROR('清理失败:%s', 16, 1, @ErrorMsg);
    END CATCH
END;
GO

-- ============================================================
-- 6. 存储过程 - 执行清理任务
-- ============================================================
CREATE PROCEDURE usp_ExecuteCleanup
    @ConfigId INT,
    @HistoryId BIGINT OUTPUT
AS
BEGIN
    SET NOCOUNT ON;
    DECLARE @StartTime DATETIME = GETDATE();
    DECLARE @DeletedRows INT = 0;
    DECLARE @Status INT = 1; -- 默认成功
    DECLARE @ErrorMessage NVARCHAR(MAX) = NULL;
    DECLARE @DurationMs INT;
    
    -- 获取配置信息
    DECLARE @ConfigName NVARCHAR(100),
            @TableName NVARCHAR(100),
            @Mode INT,
            @MaxRows INT,
            @KeepDays INT;
    
    SELECT @ConfigName = ConfigName,
           @TableName = TableName,
           @Mode = Mode,
           @MaxRows = MaxRows,
           @KeepDays = KeepDays
    FROM CleanupConfig
    WHERE Id = @ConfigId AND Enabled = 1;
    
    IF @ConfigName IS NULL
    BEGIN
        SET @ErrorMessage = '配置不存在或已禁用';
        SET @Status = 2;
        GOTO InsertHistory;
    END
    
    BEGIN TRY
        -- 插入清理历史记录(开始)
        INSERT INTO CleanupHistory (ConfigId, ConfigName, TableName, CleanMode, StartTime, Status)
        VALUES (@ConfigId, @ConfigName, @TableName, @Mode, @StartTime, 0);
        
        SET @HistoryId = SCOPE_IDENTITY();
        
        -- 根据清理模式执行不同的清理逻辑
        IF @Mode = 1 -- 按数量清理
        BEGIN
            IF @MaxRows IS NULL OR @MaxRows <= 0
            BEGIN
                SET @ErrorMessage = '按数量清理模式需要设置有效的MaxRows值';
                SET @Status = 2;
            END
            ELSE
            BEGIN
                EXEC usp_CleanupByRows @TableName, @MaxRows, @DeletedRows OUTPUT;
            END
        END
        ELSE IF @Mode = 2 -- 按日期清理
        BEGIN
            IF @KeepDays IS NULL OR @KeepDays <= 0
            BEGIN
                SET @ErrorMessage = '按日期清理模式需要设置有效的KeepDays值';
                SET @Status = 2;
            END
            ELSE
            BEGIN
                EXEC usp_CleanupByDate @TableName, @KeepDays, @DeletedRows OUTPUT;
            END
        END
        ELSE
        BEGIN
            SET @ErrorMessage = '无效的清理模式:' + CAST(@Mode AS NVARCHAR(10));
            SET @Status = 2;
        END
        
        -- 检查存储过程执行结果
        IF @DeletedRows = -1
        BEGIN
            SET @ErrorMessage = '清理存储过程执行失败';
            SET @Status = 2;
        END
        
        -- 更新配置的最后清理时间
        UPDATE CleanupConfig 
        SET LastCleanTime = GETDATE()
        WHERE Id = @ConfigId;
        
        -- 计算下次清理时间
        UPDATE CleanupConfig
        SET NextCleanTime = CASE ScheduleType
            WHEN 1 THEN DATEADD(DAY, 1, GETDATE()) -- 每日
            WHEN 2 THEN DATEADD(WEEK, 1, GETDATE()) -- 每周
            WHEN 3 THEN DATEADD(MONTH, 1, GETDATE()) -- 每月
            ELSE DATEADD(DAY, 1, GETDATE())
        END
        WHERE Id = @ConfigId;
        
    END TRY
    BEGIN CATCH
        SET @Status = 2;
        SET @ErrorMessage = ERROR_MESSAGE();
    END
    
InsertHistory:
    -- 计算执行时长
    SET @DurationMs = DATEDIFF(MILLISECOND, @StartTime, GETDATE());
    
    -- 更新历史记录
    IF @HistoryId IS NOT NULL
    BEGIN
        UPDATE CleanupHistory 
        SET EndTime = GETDATE(),
            DurationMs = @DurationMs,
            DeletedRows = @DeletedRows,
            Status = @Status,
            ErrorMessage = @ErrorMessage
        WHERE Id = @HistoryId;
    END
    ELSE
    BEGIN
        -- 如果之前没有插入历史记录,现在插入
        INSERT INTO CleanupHistory (ConfigId, ConfigName, TableName, CleanMode, StartTime, EndTime, 
                                    DurationMs, DeletedRows, Status, ErrorMessage)
        VALUES (@ConfigId, @ConfigName, @TableName, @Mode, @StartTime, GETDATE(), 
                @DurationMs, @DeletedRows, @Status, @ErrorMessage);
        
        SET @HistoryId = SCOPE_IDENTITY();
    END
    
    -- 返回状态
    SELECT @Status AS Status, @ErrorMessage AS ErrorMessage, @DeletedRows AS DeletedRows;
END;
GO

-- ============================================================
-- 7. 存储过程 - 获取需要执行的清理任务
-- ============================================================
CREATE PROCEDURE usp_GetPendingCleanupTasks
AS
BEGIN
    SET NOCOUNT ON;
    
    -- 获取所有已启用且到达执行时间的任务
    SELECT 
        Id AS ConfigId,
        ConfigName,
        TableName,
        Mode,
        MaxRows,
        KeepDays,
        ScheduleType,
        LastCleanTime,
        DATEDIFF(MINUTE, ISNULL(LastCleanTime, '1900-01-01'), GETDATE()) AS MinutesSinceLastClean
    FROM CleanupConfig
    WHERE Enabled = 1
        AND (NextCleanTime IS NULL OR NextCleanTime <= GETDATE())
    ORDER BY LastCleanTime ASC; -- 优先执行长时间未清理的任务
END;
GO

-- ============================================================
-- 8. 存储过程 - 获取数据库状态信息
-- ============================================================
CREATE PROCEDURE usp_GetDatabaseStatus
AS
BEGIN
    SET NOCOUNT ON;
    
    -- 数据库基本信息
    SELECT 
        DB_NAME() AS DatabaseName,
        (SELECT COUNT(*) FROM LogData) AS LogDataCount,
        (SELECT COUNT(*) FROM CleanupConfig) AS ConfigCount,
        (SELECT COUNT(*) FROM CleanupHistory) AS HistoryCount;
    
    -- 表大小信息
    SELECT 
        t.name AS TableName,
        SUM(p.rows) AS RowCount,
        SUM(a.total_pages) * 8 / 1024 AS TotalSizeMB,
        SUM(a.used_pages) * 8 / 1024 AS UsedSizeMB
    FROM sys.tables t
    INNER JOIN sys.partitions p ON t.object_id = p.object_id
    INNER JOIN sys.allocation_units a ON p.partition_id = a.container_id
    WHERE t.name IN ('LogData', 'CleanupConfig', 'CleanupHistory')
    GROUP BY t.name;
    
    -- 最近清理历史
    SELECT TOP 10
        ch.Id,
        ch.ConfigName,
        ch.TableName,
        CASE ch.CleanMode 
            WHEN 1 THEN '按数量' 
            WHEN 2 THEN '按日期' 
            ELSE '未知' 
        END AS CleanMode,
        ch.DeletedRows,
        ch.StartTime,
        ch.EndTime,
        ch.DurationMs,
        CASE ch.Status 
            WHEN 0 THEN '进行中' 
            WHEN 1 THEN '成功' 
            WHEN 2 THEN '失败' 
            ELSE '未知' 
        END AS Status,
        ch.ErrorMessage
    FROM CleanupHistory ch
    ORDER BY ch.StartTime DESC;
END;
GO

-- ============================================================
-- 9. 插入示例数据
-- ============================================================

-- 插入测试日志数据(生成过去60天的数据)
DECLARE @i INT = 1;
WHILE @i <= 1000
BEGIN
    INSERT INTO LogData (Content, LogLevel, CreateTime, Category)
    VALUES (
        '测试日志内容 ' + CAST(@i AS NVARCHAR(10)),
        (@i % 3) + 1, -- 1:Info, 2:Warning, 3:Error
        DATEADD(DAY, -(@i % 60), GETDATE()), -- 随机分布在过去60天内
        CASE (@i % 4)
            WHEN 0 THEN 'System'
            WHEN 1 THEN 'Application'
            WHEN 2 THEN 'Security'
            ELSE 'Network'
        END
    );
    SET @i = @i + 1;
END

-- 插入示例清理配置
INSERT INTO CleanupConfig (ConfigName, TableName, Mode, MaxRows, KeepDays, Enabled, ScheduleType, Description)
VALUES 
    ('保留最新500条日志', 'LogData', 1, 500, NULL, 1, 1, '按数量清理:只保留最新的500条日志记录'),
    ('删除30天前日志', 'LogData', 2, NULL, 30, 1, 1, '按日期清理:删除30天前的日志记录'),
    ('保留最新1000条并删除60天前', 'LogData', 1, 1000, 60, 1, 2, '每周清理:保留最新1000条,删除60天前的记录');

-- 更新下次清理时间
UPDATE CleanupConfig 
SET NextCleanTime = DATEADD(HOUR, 1, GETDATE())
WHERE Enabled = 1;

PRINT '数据库初始化完成!';
PRINT '已创建表:LogData, CleanupConfig, CleanupHistory';
PRINT '已插入示例数据:LogData(1000行), CleanupConfig(3条配置)';
GO

二、Windows窗体应用程序(.NET Framework 4.7.2)

1. App.config(配置文件)

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2"/>
    </startup>
    
    <connectionStrings>
        <add name="AutoCleanupDB" 
             connectionString="Server=.;Database=AutoCleanupDB;Integrated Security=True;Connect Timeout=30;"
             providerName="System.Data.SqlClient"/>
    </connectionStrings>
    
    <appSettings>
        <!-- 自动清理检查间隔(毫秒) -->
        <add key="AutoCleanupInterval" value="60000"/>
        <!-- 最大历史记录显示条数 -->
        <add key="MaxHistoryRecords" value="50"/>
        <!-- 是否启用自动清理 -->
        <add key="EnableAutoCleanup" value="true"/>
    </appSettings>
</configuration>

2. Program.cs(程序入口)

csharp 复制代码
using System;
using System.Windows.Forms;

namespace AutoCleanupSystem
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}

3. DatabaseHelper.cs(数据库辅助类)

csharp 复制代码
using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace AutoCleanupSystem
{
    /// <summary>
    /// 数据库操作辅助类
    /// 封装所有数据库连接和操作逻辑
    /// </summary>
    public class DatabaseHelper
    {
        private static readonly string connectionString = ConfigurationManager.ConnectionStrings["AutoCleanupDB"].ConnectionString;

        /// <summary>
        /// 测试数据库连接
        /// </summary>
        public static bool TestConnection()
        {
            try
            {
                using (var connection = new SqlConnection(connectionString))
                {
                    connection.Open();
                    return true;
                }
            }
            catch
            {
                return false;
            }
        }

        /// <summary>
        /// 执行非查询SQL语句
        /// </summary>
        public static int ExecuteNonQuery(string sql, params SqlParameter[] parameters)
        {
            using (var connection = new SqlConnection(connectionString))
            using (var command = new SqlCommand(sql, connection))
            {
                connection.Open();
                if (parameters != null)
                    command.Parameters.AddRange(parameters);
                return command.ExecuteNonQuery();
            }
        }

        /// <summary>
        /// 执行查询并返回DataTable
        /// </summary>
        public static DataTable ExecuteQuery(string sql, params SqlParameter[] parameters)
        {
            var dataTable = new DataTable();
            
            using (var connection = new SqlConnection(connectionString))
            using (var command = new SqlCommand(sql, connection))
            using (var adapter = new SqlDataAdapter(command))
            {
                if (parameters != null)
                    command.Parameters.AddRange(parameters);
                
                adapter.Fill(dataTable);
            }
            
            return dataTable;
        }

        /// <summary>
        /// 获取数据库状态信息
        /// </summary>
        public static DataSet GetDatabaseStatus()
        {
            var dataSet = new DataSet();
            
            using (var connection = new SqlConnection(connectionString))
            using (var command = new SqlCommand("usp_GetDatabaseStatus", connection))
            using (var adapter = new SqlDataAdapter(command))
            {
                command.CommandType = CommandType.StoredProcedure;
                connection.Open();
                
                // 填充多个结果集
                adapter.Fill(dataSet);
            }
            
            return dataSet;
        }

        /// <summary>
        /// 获取待执行的清理任务
        /// </summary>
        public static DataTable GetPendingTasks()
        {
            return ExecuteQuery("EXEC usp_GetPendingCleanupTasks");
        }

        /// <summary>
        /// 执行清理任务
        /// </summary>
        public static CleanupResult ExecuteCleanup(int configId)
        {
            var result = new CleanupResult();
            
            using (var connection = new SqlConnection(connectionString))
            using (var command = new SqlCommand("usp_ExecuteCleanup", connection))
            {
                command.CommandType = CommandType.StoredProcedure;
                
                // 添加输入参数
                command.Parameters.Add(new SqlParameter("@ConfigId", configId));
                
                // 添加输出参数
                var historyIdParam = new SqlParameter("@HistoryId", SqlDbType.BigInt)
                {
                    Direction = ParameterDirection.Output
                };
                command.Parameters.Add(historyIdParam);
                
                // 添加返回值参数
                var statusParam = new SqlParameter("@Status", SqlDbType.Int);
                var errorParam = new SqlParameter("@ErrorMessage", SqlDbType.NVarChar, -1);
                var deletedRowsParam = new SqlParameter("@DeletedRows", SqlDbType.Int);
                
                connection.Open();
                
                using (var reader = command.ExecuteReader())
                {
                    if (reader.Read())
                    {
                        result.Status = reader.GetInt32(reader.GetOrdinal("Status"));
                        result.ErrorMessage = reader["ErrorMessage"] == DBNull.Value ? 
                            null : reader["ErrorMessage"].ToString();
                        result.DeletedRows = reader.GetInt32(reader.GetOrdinal("DeletedRows"));
                    }
                }
                
                result.HistoryId = historyIdParam.Value == DBNull.Value ? 
                    0 : Convert.ToInt64(historyIdParam.Value);
            }
            
            return result;
        }

        /// <summary>
        /// 获取所有清理配置
        /// </summary>
        public static DataTable GetCleanupConfigs()
        {
            return ExecuteQuery(@"
                SELECT 
                    Id,
                    ConfigName,
                    TableName,
                    Mode,
                    MaxRows,
                    KeepDays,
                    Enabled,
                    LastCleanTime,
                    ScheduleType,
                    NextCleanTime,
                    CreatedTime,
                    Description
                FROM CleanupConfig
                ORDER BY Enabled DESC, ConfigName
            ");
        }

        /// <summary>
        /// 保存清理配置
        /// </summary>
        public static int SaveCleanupConfig(CleanupConfig config)
        {
            var parameters = new SqlParameter[]
            {
                new SqlParameter("@ConfigName", config.ConfigName),
                new SqlParameter("@TableName", config.TableName),
                new SqlParameter("@Mode", config.Mode),
                new SqlParameter("@MaxRows", config.MaxRows ?? (object)DBNull.Value),
                new SqlParameter("@KeepDays", config.KeepDays ?? (object)DBNull.Value),
                new SqlParameter("@Enabled", config.Enabled),
                new SqlParameter("@ScheduleType", config.ScheduleType),
                new SqlParameter("@Description", config.Description ?? (object)DBNull.Value)
            };

            if (config.Id > 0)
            {
                // 更新
                var sql = @"
                    UPDATE CleanupConfig 
                    SET ConfigName = @ConfigName,
                        TableName = @TableName,
                        Mode = @Mode,
                        MaxRows = @MaxRows,
                        KeepDays = @KeepDays,
                        Enabled = @Enabled,
                        ScheduleType = @ScheduleType,
                        Description = @Description
                    WHERE Id = @Id";
                
                var paramList = new SqlParameter[parameters.Length + 1];
                parameters.CopyTo(paramList, 0);
                paramList[parameters.Length] = new SqlParameter("@Id", config.Id);
                
                return ExecuteNonQuery(sql, paramList);
            }
            else
            {
                // 插入
                var sql = @"
                    INSERT INTO CleanupConfig 
                        (ConfigName, TableName, Mode, MaxRows, KeepDays, 
                         Enabled, ScheduleType, CreatedTime, Description)
                    VALUES 
                        (@ConfigName, @TableName, @Mode, @MaxRows, @KeepDays,
                         @Enabled, @ScheduleType, GETDATE(), @Description);
                    SELECT SCOPE_IDENTITY();";
                
                var result = ExecuteQuery(sql, parameters);
                return Convert.ToInt32(result.Rows[0][0]);
            }
        }

        /// <summary>
        /// 删除清理配置
        /// </summary>
        public static int DeleteCleanupConfig(int configId)
        {
            return ExecuteNonQuery("DELETE FROM CleanupConfig WHERE Id = @Id",
                new SqlParameter("@Id", configId));
        }

        /// <summary>
        /// 获取清理历史记录
        /// </summary>
        public static DataTable GetCleanupHistory(int? configId = null, int limit = 50)
        {
            var sql = @"
                SELECT TOP (@Limit)
                    ch.Id,
                    ch.ConfigId,
                    ch.ConfigName,
                    ch.TableName,
                    ch.CleanMode,
                    ch.DeletedRows,
                    ch.StartTime,
                    ch.EndTime,
                    ch.DurationMs,
                    ch.Status,
                    ch.ErrorMessage
                FROM CleanupHistory ch
                WHERE (@ConfigId IS NULL OR ch.ConfigId = @ConfigId)
                ORDER BY ch.StartTime DESC";
            
            var parameters = new SqlParameter[]
            {
                new SqlParameter("@Limit", limit),
                new SqlParameter("@ConfigId", configId ?? (object)DBNull.Value)
            };
            
            return ExecuteQuery(sql, parameters);
        }
    }

    /// <summary>
    /// 清理配置实体类
    /// </summary>
    public class CleanupConfig
    {
        public int Id { get; set; }
        public string ConfigName { get; set; }
        public string TableName { get; set; }
        public int Mode { get; set; } // 1:按数量 2:按日期
        public int? MaxRows { get; set; }
        public int? KeepDays { get; set; }
        public bool Enabled { get; set; }
        public int ScheduleType { get; set; } // 1:每日 2:每周 3:每月
        public string Description { get; set; }
    }

    /// <summary>
    /// 清理结果类
    /// </summary>
    public class CleanupResult
    {
        public long HistoryId { get; set; }
        public int Status { get; set; } // 0:进行中 1:成功 2:失败
        public string ErrorMessage { get; set; }
        public int DeletedRows { get; set; }
        
        public bool IsSuccess => Status == 1;
    }
}

4. MainForm.cs(主窗体)

csharp 复制代码
using System;
using System.Data;
using System.Drawing;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Configuration;

namespace AutoCleanupSystem
{
    public partial class MainForm : Form
    {
        private Timer autoCleanupTimer;
        private bool isAutoCleanupEnabled;
        private int autoCleanupInterval;
        
        public MainForm()
        {
            InitializeComponent();
            InitializeSettings();
            InitializeForm();
        }

        /// <summary>
        /// 初始化应用程序设置
        /// </summary>
        private void InitializeSettings()
        {
            // 从配置文件读取设置
            isAutoCleanupEnabled = ConfigurationManager.AppSettings["EnableAutoCleanup"] == "true";
            autoCleanupInterval = int.Parse(ConfigurationManager.AppSettings["AutoCleanupInterval"]);
            
            // 初始化自动清理定时器
            autoCleanupTimer = new Timer
            {
                Interval = autoCleanupInterval,
                Enabled = isAutoCleanupEnabled
            };
            autoCleanupTimer.Tick += AutoCleanupTimer_Tick;
        }

        /// <summary>
        /// 初始化窗体界面
        /// </summary>
        private void InitializeForm()
        {
            // 设置状态标签
            lblConnectionStatus.Text = DatabaseHelper.TestConnection() ? 
                "数据库连接正常" : "数据库连接失败";
            lblConnectionStatus.ForeColor = DatabaseHelper.TestConnection() ? 
                Color.Green : Color.Red;
            
            // 设置自动清理状态
            chkAutoCleanup.Checked = isAutoCleanupEnabled;
            lblAutoCleanupStatus.Text = isAutoCleanupEnabled ? "自动清理已启用" : "自动清理已禁用";
            lblAutoCleanupStatus.ForeColor = isAutoCleanupEnabled ? Color.Green : Color.Red;
            
            // 加载初始数据
            LoadDatabaseStatus();
            LoadCleanupConfigs();
            LoadCleanupHistory();
        }

        /// <summary>
        /// 加载数据库状态信息
        /// </summary>
        private void LoadDatabaseStatus()
        {
            try
            {
                var dataSet = DatabaseHelper.GetDatabaseStatus();
                
                if (dataSet.Tables.Count > 0 && dataSet.Tables[0].Rows.Count > 0)
                {
                    var statusRow = dataSet.Tables[0].Rows[0];
                    lblDatabaseName.Text = statusRow["DatabaseName"].ToString();
                    lblLogDataCount.Text = statusRow["LogDataCount"].ToString();
                    lblConfigCount.Text = statusRow["ConfigCount"].ToString();
                    lblHistoryCount.Text = statusRow["HistoryCount"].ToString();
                }
                
                // 显示表大小信息
                if (dataSet.Tables.Count > 1)
                {
                    dgvTableSizes.DataSource = dataSet.Tables[1];
                    FormatDataGridView(dgvTableSizes);
                }
                
                // 显示最近清理历史
                if (dataSet.Tables.Count > 2)
                {
                    dgvRecentHistory.DataSource = dataSet.Tables[2];
                    FormatHistoryDataGridView(dgvRecentHistory);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载数据库状态失败:{ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 加载清理配置
        /// </summary>
        private void LoadCleanupConfigs()
        {
            try
            {
                dgvCleanupConfigs.DataSource = DatabaseHelper.GetCleanupConfigs();
                FormatConfigDataGridView(dgvCleanupConfigs);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载清理配置失败:{ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 加载清理历史记录
        /// </summary>
        private void LoadCleanupHistory()
        {
            try
            {
                dgvCleanupHistory.DataSource = DatabaseHelper.GetCleanupHistory();
                FormatHistoryDataGridView(dgvCleanupHistory);
            }
            catch (Exception ex)
            {
                MessageBox.Show($"加载清理历史失败:{ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// 格式化配置数据网格视图
        /// </summary>
        private void FormatConfigDataGridView(DataGridView dgv)
        {
            if (dgv.Columns.Count == 0) return;
            
            // 设置列标题和宽度
            dgv.Columns["Id"].Visible = false;
            dgv.Columns["ConfigName"].HeaderText = "配置名称";
            dgv.Columns["ConfigName"].Width = 150;
            dgv.Columns["TableName"].HeaderText = "表名";
            dgv.Columns["TableName"].Width = 100;
            dgv.Columns["Mode"].HeaderText = "清理模式";
            dgv.Columns["Mode"].Width = 80;
            dgv.Columns["MaxRows"].HeaderText = "最大行数";
            dgv.Columns["MaxRows"].Width = 80;
            dgv.Columns["KeepDays"].HeaderText = "保留天数";
            dgv.Columns["KeepDays"].Width = 80;
            dgv.Columns["Enabled"].HeaderText = "启用";
            dgv.Columns["Enabled"].Width = 50;
            dgv.Columns["ScheduleType"].HeaderText = "计划类型";
            dgv.Columns["ScheduleType"].Width = 80;
            dgv.Columns["LastCleanTime"].HeaderText = "最后清理时间";
            dgv.Columns["LastCleanTime"].Width = 120;
            dgv.Columns["NextCleanTime"].HeaderText = "下次清理时间";
            dgv.Columns["NextCleanTime"].Width = 120;
            dgv.Columns["Description"].HeaderText = "描述";
            dgv.Columns["Description"].Width = 200;
            
            // 格式化模式列
            if (dgv.Columns.Contains("Mode"))
            {
                dgv.Columns["Mode"].DefaultCellStyle.Format = "模式类型";
            }
            
            // 格式化布尔列
            if (dgv.Columns.Contains("Enabled"))
            {
                dgv.Columns["Enabled"].DefaultCellStyle.NullValue = false;
            }
            
            // 设置选择模式
            dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dgv.MultiSelect = false;
        }

        /// <summary>
        /// 格式化历史数据网格视图
        /// </summary>
        private void FormatHistoryDataGridView(DataGridView dgv)
        {
            if (dgv.Columns.Count == 0) return;
            
            // 设置列标题和宽度
            if (dgv.Columns.Contains("Id"))
                dgv.Columns["Id"].Visible = false;
            if (dgv.Columns.Contains("ConfigId"))
                dgv.Columns["ConfigId"].Visible = false;
            
            dgv.Columns["ConfigName"].HeaderText = "配置名称";
            dgv.Columns["ConfigName"].Width = 120;
            dgv.Columns["TableName"].HeaderText = "表名";
            dgv.Columns["TableName"].Width = 100;
            dgv.Columns["CleanMode"].HeaderText = "清理模式";
            dgv.Columns["CleanMode"].Width = 80;
            dgv.Columns["DeletedRows"].HeaderText = "删除行数";
            dgv.Columns["DeletedRows"].Width = 80;
            dgv.Columns["StartTime"].HeaderText = "开始时间";
            dgv.Columns["StartTime"].Width = 120;
            dgv.Columns["EndTime"].HeaderText = "结束时间";
            dgv.Columns["EndTime"].Width = 120;
            dgv.Columns["DurationMs"].HeaderText = "耗时(ms)";
            dgv.Columns["DurationMs"].Width = 80;
            dgv.Columns["Status"].HeaderText = "状态";
            dgv.Columns["Status"].Width = 60;
            dgv.Columns["ErrorMessage"].HeaderText = "错误信息";
            dgv.Columns["ErrorMessage"].Width = 200;
            
            // 设置状态列颜色
            dgv.CellFormatting += (sender, e) =>
            {
                if (e.ColumnIndex == dgv.Columns["Status"].Index && e.Value != null)
                {
                    var status = e.Value.ToString();
                    e.CellStyle.ForeColor = status switch
                    {
                        "1" or "成功" => Color.Green,
                        "2" or "失败" => Color.Red,
                        _ => Color.Orange
                    };
                }
                
                if (e.ColumnIndex == dgv.Columns["CleanMode"].Index && e.Value != null)
                {
                    e.Value = e.Value.ToString() switch
                    {
                        "1" => "按数量",
                        "2" => "按日期",
                        _ => e.Value
                    };
                }
            };
        }

        /// <summary>
        /// 格式化数据网格视图
        /// </summary>
        private void FormatDataGridView(DataGridView dgv)
        {
            dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
            dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            dgv.MultiSelect = false;
            dgv.ReadOnly = true;
        }

        /// <summary>
        /// 自动清理定时器事件
        /// </summary>
        private async void AutoCleanupTimer_Tick(object sender, EventArgs e)
        {
            // 在UI线程上更新时间显示
            lblLastCheckTime.Invoke((MethodInvoker)delegate
            {
                lblLastCheckTime.Text = $"最后检查:{DateTime.Now:HH:mm:ss}";
            });
            
            try
            {
                // 获取待执行任务
                var pendingTasks = DatabaseHelper.GetPendingTasks();
                
                if (pendingTasks.Rows.Count > 0)
                {
                    // 在UI线程显示消息
                    this.Invoke((MethodInvoker)delegate
                    {
                        lblPendingTasks.Text = $"发现 {pendingTasks.Rows.Count} 个待执行任务";
                        lblPendingTasks.ForeColor = Color.Orange;
                    });
                    
                    // 异步执行清理任务
                    foreach (DataRow task in pendingTasks.Rows)
                    {
                        int configId = Convert.ToInt32(task["ConfigId"]);
                        string configName = task["ConfigName"].ToString();
                        
                        await Task.Run(() =>
                        {
                            var result = DatabaseHelper.ExecuteCleanup(configId);
                            
                            // 在UI线程更新结果
                            this.Invoke((MethodInvoker)delegate
                            {
                                if (result.IsSuccess)
                                {
                                    AddLogMessage($"✅ 任务执行成功:{configName},删除 {result.DeletedRows} 行");
                                }
                                else
                                {
                                    AddLogMessage($"❌ 任务执行失败:{configName},错误:{result.ErrorMessage}");
                                }
                            });
                        });
                        
                        // 任务间延迟1秒
                        await Task.Delay(1000);
                    }
                    
                    // 刷新显示
                    this.Invoke((MethodInvoker)delegate
                    {
                        LoadDatabaseStatus();
                        LoadCleanupConfigs();
                        LoadCleanupHistory();
                        lblPendingTasks.Text = "所有任务执行完成";
                        lblPendingTasks.ForeColor = Color.Green;
                    });
                }
                else
                {
                    this.Invoke((MethodInvoker)delegate
                    {
                        lblPendingTasks.Text = "无待执行任务";
                        lblPendingTasks.ForeColor = Color.Gray;
                    });
                }
            }
            catch (Exception ex)
            {
                this.Invoke((MethodInvoker)delegate
                {
                    AddLogMessage($"⚠️ 自动清理检查失败:{ex.Message}");
                    lblPendingTasks.Text = "检查任务时发生错误";
                    lblPendingTasks.ForeColor = Color.Red;
                });
            }
        }

        /// <summary>
        /// 添加日志消息
        /// </summary>
        private void AddLogMessage(string message)
        {
            string timestamp = DateTime.Now.ToString("HH:mm:ss");
            txtLog.AppendText($"[{timestamp}] {message}{Environment.NewLine}");
            
            // 自动滚动到最后
            txtLog.SelectionStart = txtLog.TextLength;
            txtLog.ScrollToCaret();
            
            // 限制日志行数
            var lines = txtLog.Lines;
            if (lines.Length > 100)
            {
                txtLog.Lines = lines[^100..];
            }
        }

        /// <summary>
        /// 执行选中配置的清理任务
        /// </summary>
        private async void btnExecute_Click(object sender, EventArgs e)
        {
            if (dgvCleanupConfigs.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选择一个清理配置", "提示", 
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            
            var selectedRow = dgvCleanupConfigs.SelectedRows[0];
            int configId = Convert.ToInt32(selectedRow.Cells["Id"].Value);
            string configName = selectedRow.Cells["ConfigName"].Value.ToString();
            
            try
            {
                btnExecute.Enabled = false;
                btnExecute.Text = "执行中...";
                
                AddLogMessage($"开始执行清理任务:{configName}");
                
                // 异步执行清理
                var result = await Task.Run(() => DatabaseHelper.ExecuteCleanup(configId));
                
                if (result.IsSuccess)
                {
                    AddLogMessage($"✅ 清理成功:{configName},删除 {result.DeletedRows} 行数据");
                    MessageBox.Show($"清理成功!\n删除行数:{result.DeletedRows}", 
                        "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }
                else
                {
                    AddLogMessage($"❌ 清理失败:{configName},错误:{result.ErrorMessage}");
                    MessageBox.Show($"清理失败!\n错误信息:{result.ErrorMessage}", 
                        "失败", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                
                // 刷新数据
                LoadDatabaseStatus();
                LoadCleanupConfigs();
                LoadCleanupHistory();
            }
            catch (Exception ex)
            {
                AddLogMessage($"⚠️ 执行清理时发生异常:{ex.Message}");
                MessageBox.Show($"执行清理时发生异常:{ex.Message}", 
                    "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            finally
            {
                btnExecute.Enabled = true;
                btnExecute.Text = "执行清理";
            }
        }

        /// <summary>
        /// 添加新配置
        /// </summary>
        private void btnAddConfig_Click(object sender, EventArgs e)
        {
            using (var configForm = new ConfigForm())
            {
                if (configForm.ShowDialog() == DialogResult.OK)
                {
                    LoadCleanupConfigs();
                    AddLogMessage("✅ 清理配置添加成功");
                }
            }
        }

        /// <summary>
        /// 编辑选中配置
        /// </summary>
        private void btnEditConfig_Click(object sender, EventArgs e)
        {
            if (dgvCleanupConfigs.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选择一个清理配置", "提示", 
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            
            var selectedRow = dgvCleanupConfigs.SelectedRows[0];
            int configId = Convert.ToInt32(selectedRow.Cells["Id"].Value);
            
            using (var configForm = new ConfigForm(configId))
            {
                if (configForm.ShowDialog() == DialogResult.OK)
                {
                    LoadCleanupConfigs();
                    AddLogMessage("✅ 清理配置修改成功");
                }
            }
        }

        /// <summary>
        /// 删除选中配置
        /// </summary>
        private void btnDeleteConfig_Click(object sender, EventArgs e)
        {
            if (dgvCleanupConfigs.SelectedRows.Count == 0)
            {
                MessageBox.Show("请先选择一个清理配置", "提示", 
                    MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }
            
            var selectedRow = dgvCleanupConfigs.SelectedRows[0];
            int configId = Convert.ToInt32(selectedRow.Cells["Id"].Value);
            string configName = selectedRow.Cells["ConfigName"].Value.ToString();
            
            if (MessageBox.Show($"确定要删除配置 '{configName}' 吗?", 
                "确认删除", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                try
                {
                    int result = DatabaseHelper.DeleteCleanupConfig(configId);
                    if (result > 0)
                    {
                        LoadCleanupConfigs();
                        AddLogMessage($"✅ 清理配置 '{configName}' 删除成功");
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show($"删除配置失败:{ex.Message}", 
                        "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
            }
        }

        /// <summary>
        /// 刷新数据
        /// </summary>
        private void btnRefresh_Click(object sender, EventArgs e)
        {
            LoadDatabaseStatus();
            LoadCleanupConfigs();
            LoadCleanupHistory();
            AddLogMessage("🔄 数据刷新完成");
        }

        /// <summary>
        /// 自动清理复选框状态改变
        /// </summary>
        private void chkAutoCleanup_CheckedChanged(object sender, EventArgs e)
        {
            isAutoCleanupEnabled = chkAutoCleanup.Checked;
            autoCleanupTimer.Enabled = isAutoCleanupEnabled;
            
            lblAutoCleanupStatus.Text = isAutoCleanupEnabled ? "自动清理已启用" : "自动清理已禁用";
            lblAutoCleanupStatus.ForeColor = isAutoCleanupEnabled ? Color.Green : Color.Red;
            
            AddLogMessage(isAutoCleanupEnabled ? 
                "✅ 自动清理功能已启用" : "⏸️ 自动清理功能已禁用");
        }

        /// <summary>
        /// 立即检查待执行任务
        /// </summary>
        private void btnCheckNow_Click(object sender, EventArgs e)
        {
            AutoCleanupTimer_Tick(null, EventArgs.Empty);
        }

        /// <summary>
        /// 清除日志
        /// </summary>
        private void btnClearLog_Click(object sender, EventArgs e)
        {
            txtLog.Clear();
            AddLogMessage("📋 日志已清空");
        }

        /// <summary>
        /// 窗体加载完成事件
        /// </summary>
        private void MainForm_Load(object sender, EventArgs e)
        {
            AddLogMessage($"🚀 数据库清理系统启动 - {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
            AddLogMessage($"📊 数据库连接:{lblConnectionStatus.Text}");
            AddLogMessage($"⚙️ 自动清理:{(isAutoCleanupEnabled ? "已启用" : "已禁用")}");
        }

        /// <summary>
        /// 窗体关闭事件
        /// </summary>
        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            autoCleanupTimer?.Stop();
            autoCleanupTimer?.Dispose();
            AddLogMessage("🛑 数据库清理系统关闭");
        }
    }
}

5. ConfigForm.cs(配置编辑窗体)

csharp 复制代码
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;

namespace AutoCleanupSystem
{
    public partial class ConfigForm : Form
    {
        private CleanupConfig config;
        private bool isEditMode = false;
        
        public ConfigForm(int configId = 0)
        {
            InitializeComponent();
            
            if (configId > 0)
            {
                // 编辑模式
                isEditMode = true;
                Text = "编辑清理配置";
                LoadConfig(configId);
            }
            else
            {
                // 添加模式
                Text = "添加清理配置";
                config = new CleanupConfig
                {
                    Enabled = true,
                    ScheduleType = 1, // 每日
                    Mode = 1 // 按数量
                };
            }
            
            InitializeForm();
        }
        
        /// <summary>
        /// 加载配置数据
        /// </summary>
        private void LoadConfig(int configId)
        {
            var dt = DatabaseHelper.GetCleanupConfigs();
            var rows = dt.Select($"Id = {configId}");
            
            if (rows.Length > 0)
            {
                var row = rows[0];
                config = new CleanupConfig
                {
                    Id = Convert.ToInt32(row["Id"]),
                    ConfigName = row["ConfigName"].ToString(),
                    TableName = row["TableName"].ToString(),
                    Mode = Convert.ToInt32(row["Mode"]),
                    MaxRows = row["MaxRows"] == DBNull.Value ? null : (int?)Convert.ToInt32(row["MaxRows"]),
                    KeepDays = row["KeepDays"] == DBNull.Value ? null : (int?)Convert.ToInt32(row["KeepDays"]),
                    Enabled = Convert.ToBoolean(row["Enabled"]),
                    ScheduleType = Convert.ToInt32(row["ScheduleType"]),
                    Description = row["Description"] == DBNull.Value ? null : row["Description"].ToString()
                };
                
                // 填充表单
                txtConfigName.Text = config.ConfigName;
                txtTableName.Text = config.TableName;
                cmbMode.SelectedIndex = config.Mode - 1;
                txtMaxRows.Text = config.MaxRows?.ToString();
                txtKeepDays.Text = config.KeepDays?.ToString();
                chkEnabled.Checked = config.Enabled;
                cmbScheduleType.SelectedIndex = config.ScheduleType - 1;
                txtDescription.Text = config.Description;
            }
        }
        
        /// <summary>
        /// 初始化窗体界面
        /// </summary>
        private void InitializeForm()
        {
            // 设置控件初始值
            cmbMode.SelectedIndex = 0;
            cmbScheduleType.SelectedIndex = 0;
            
            // 模式改变事件
            cmbMode.SelectedIndexChanged += CmbMode_SelectedIndexChanged;
            UpdateModeControls();
        }
        
        /// <summary>
        /// 清理模式改变事件
        /// </summary>
        private void CmbMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            UpdateModeControls();
        }
        
        /// <summary>
        /// 更新模式相关控件
        /// </summary>
        private void UpdateModeControls()
        {
            bool isByRows = cmbMode.SelectedIndex == 0; // 0:按数量
            
            lblMaxRows.Enabled = isByRows;
            txtMaxRows.Enabled = isByRows;
            lblKeepDays.Enabled = !isByRows;
            txtKeepDays.Enabled = !isByRows;
        }
        
        /// <summary>
        /// 保存配置
        /// </summary>
        private void btnSave_Click(object sender, EventArgs e)
        {
            if (!ValidateInput())
                return;
            
            try
            {
                // 更新配置对象
                config.ConfigName = txtConfigName.Text.Trim();
                config.TableName = txtTableName.Text.Trim();
                config.Mode = cmbMode.SelectedIndex + 1;
                config.ScheduleType = cmbScheduleType.SelectedIndex + 1;
                config.Enabled = chkEnabled.Checked;
                config.Description = txtDescription.Text.Trim();
                
                // 根据模式设置参数
                if (config.Mode == 1) // 按数量
                {
                    config.MaxRows = int.Parse(txtMaxRows.Text);
                    config.KeepDays = null;
                }
                else // 按日期
                {
                    config.MaxRows = null;
                    config.KeepDays = int.Parse(txtKeepDays.Text);
                }
                
                // 保存到数据库
                int result = DatabaseHelper.SaveCleanupConfig(config);
                
                if (result > 0)
                {
                    MessageBox.Show("配置保存成功!", "成功", 
                        MessageBoxButtons.OK, MessageBoxIcon.Information);
                    DialogResult = DialogResult.OK;
                    Close();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show($"保存配置失败:{ex.Message}", "错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        
        /// <summary>
        /// 验证输入
        /// </summary>
        private bool ValidateInput()
        {
            // 验证必填字段
            if (string.IsNullOrWhiteSpace(txtConfigName.Text))
            {
                MessageBox.Show("请输入配置名称", "验证错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtConfigName.Focus();
                return false;
            }
            
            if (string.IsNullOrWhiteSpace(txtTableName.Text))
            {
                MessageBox.Show("请输入表名", "验证错误", 
                    MessageBoxButtons.OK, MessageBoxIcon.Warning);
                txtTableName.Focus();
                return false;
            }
            
            // 验证模式相关参数
            if (cmbMode.SelectedIndex == 0) // 按数量
            {
                if (!int.TryParse(txtMaxRows.Text, out int maxRows) || maxRows <= 0)
                {
                    MessageBox.Show("请输入有效的最大行数(大于0)", "验证错误", 
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    txtMaxRows.Focus();
                    return false;
                }
            }
            else // 按日期
            {
                if (!int.TryParse(txtKeepDays.Text, out int keepDays) || keepDays <= 0)
                {
                    MessageBox.Show("请输入有效的保留天数(大于0)", "验证错误", 
                        MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    txtKeepDays.Focus();
                    return false;
                }
            }
            
            return true;
        }
        
        /// <summary>
        /// 取消按钮
        /// </summary>
        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
            Close();
        }
    }
}

6. MainForm.Designer.cs(主窗体设计器代码)

csharp 复制代码
namespace AutoCleanupSystem
{
    partial class MainForm
    {
        private System.ComponentModel.IContainer components = null;
        private TabControl tabControl1;
        private TabPage tabPage1;
        private TabPage tabPage2;
        private TabPage tabPage3;
        private GroupBox groupBox1;
        private Label lblDatabaseName;
        private Label label1;
        private Label label2;
        private Label lblLogDataCount;
        private Label label3;
        private Label lblConfigCount;
        private Label label4;
        private Label lblHistoryCount;
        private DataGridView dgvTableSizes;
        private DataGridView dgvRecentHistory;
        private Label label5;
        private Label label6;
        private DataGridView dgvCleanupConfigs;
        private Button btnExecute;
        private Button btnAddConfig;
        private Button btnEditConfig;
        private Button btnDeleteConfig;
        private Button btnRefresh;
        private DataGridView dgvCleanupHistory;
        private Label label7;
        private Label label8;
        private Label lblConnectionStatus;
        private CheckBox chkAutoCleanup;
        private Label lblAutoCleanupStatus;
        private Button btnCheckNow;
        private Label lblPendingTasks;
        private Label lblLastCheckTime;
        private TextBox txtLog;
        private Button btnClearLog;
        
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }
        
        private void InitializeComponent()
        {
            this.tabControl1 = new TabControl();
            this.tabPage1 = new TabPage();
            this.dgvRecentHistory = new DataGridView();
            this.label6 = new Label();
            this.dgvTableSizes = new DataGridView();
            this.label5 = new Label();
            this.groupBox1 = new GroupBox();
            this.lblHistoryCount = new Label();
            this.label4 = new Label();
            this.lblConfigCount = new Label();
            this.label3 = new Label();
            this.lblLogDataCount = new Label();
            this.label2 = new Label();
            this.lblDatabaseName = new Label();
            this.label1 = new Label();
            this.tabPage2 = new TabPage();
            this.btnDeleteConfig = new Button();
            this.btnEditConfig = new Button();
            this.btnAddConfig = new Button();
            this.btnExecute = new Button();
            this.dgvCleanupConfigs = new DataGridView();
            this.label7 = new Label();
            this.tabPage3 = new TabPage();
            this.dgvCleanupHistory = new DataGridView();
            this.label8 = new Label();
            this.btnRefresh = new Button();
            this.lblConnectionStatus = new Label();
            this.chkAutoCleanup = new CheckBox();
            this.lblAutoCleanupStatus = new Label();
            this.btnCheckNow = new Button();
            this.lblPendingTasks = new Label();
            this.lblLastCheckTime = new Label();
            this.txtLog = new TextBox();
            this.btnClearLog = new Button();
            this.tabControl1.SuspendLayout();
            this.tabPage1.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvRecentHistory)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.dgvTableSizes)).BeginInit();
            this.groupBox1.SuspendLayout();
            this.tabPage2.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvCleanupConfigs)).BeginInit();
            this.tabPage3.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvCleanupHistory)).BeginInit();
            this.SuspendLayout();
            
            // tabControl1
            this.tabControl1.Controls.Add(this.tabPage1);
            this.tabControl1.Controls.Add(this.tabPage2);
            this.tabControl1.Controls.Add(this.tabPage3);
            this.tabControl1.Dock = DockStyle.Top;
            this.tabControl1.Location = new Point(0, 0);
            this.tabControl1.Name = "tabControl1";
            this.tabControl1.SelectedIndex = 0;
            this.tabControl1.Size = new Size(984, 450);
            this.tabControl1.TabIndex = 0;
            
            // tabPage1 - 监控面板
            this.tabPage1.Controls.Add(this.dgvRecentHistory);
            this.tabPage1.Controls.Add(this.label6);
            this.tabPage1.Controls.Add(this.dgvTableSizes);
            this.tabPage1.Controls.Add(this.label5);
            this.tabPage1.Controls.Add(this.groupBox1);
            this.tabPage1.Location = new Point(4, 22);
            this.tabPage1.Name = "tabPage1";
            this.tabPage1.Padding = new Padding(3);
            this.tabPage1.Size = new Size(976, 424);
            this.tabPage1.TabIndex = 0;
            this.tabPage1.Text = "监控面板";
            this.tabPage1.UseVisualStyleBackColor = true;
            
            // groupBox1 - 数据库状态
            this.groupBox1.Controls.Add(this.lblHistoryCount);
            this.groupBox1.Controls.Add(this.label4);
            this.groupBox1.Controls.Add(this.lblConfigCount);
            this.groupBox1.Controls.Add(this.label3);
            this.groupBox1.Controls.Add(this.lblLogDataCount);
            this.groupBox1.Controls.Add(this.label2);
            this.groupBox1.Controls.Add(this.lblDatabaseName);
            this.groupBox1.Controls.Add(this.label1);
            this.groupBox1.Location = new Point(6, 6);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new Size(300, 130);
            this.groupBox1.TabIndex = 0;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "数据库状态";
            
            // 状态标签
            this.label1.AutoSize = true;
            this.label1.Location = new Point(20, 25);
            this.label1.Name = "label1";
            this.label1.Size = new Size(65, 12);
            this.label1.TabIndex = 0;
            this.label1.Text = "数据库名:";
            
            this.lblDatabaseName.AutoSize = true;
            this.lblDatabaseName.Font = new Font("宋体", 9F, FontStyle.Bold);
            this.lblDatabaseName.Location = new Point(91, 25);
            this.lblDatabaseName.Name = "lblDatabaseName";
            this.lblDatabaseName.Size = new Size(31, 12);
            this.lblDatabaseName.TabIndex = 1;
            this.lblDatabaseName.Text = "N/A";
            
            // 其他状态标签类似设置...
            
            // dgvTableSizes
            this.dgvTableSizes.Location = new Point(312, 30);
            this.dgvTableSizes.Name = "dgvTableSizes";
            this.dgvTableSizes.Size = new Size(300, 150);
            this.dgvTableSizes.TabIndex = 1;
            
            // dgvRecentHistory
            this.dgvRecentHistory.Location = new Point(312, 210);
            this.dgvRecentHistory.Name = "dgvRecentHistory";
            this.dgvRecentHistory.Size = new Size(300, 200);
            this.dgvRecentHistory.TabIndex = 3;
            
            // tabPage2 - 清理配置
            this.tabPage2.Controls.Add(this.btnDeleteConfig);
            this.tabPage2.Controls.Add(this.btnEditConfig);
            this.tabPage2.Controls.Add(this.btnAddConfig);
            this.tabPage2.Controls.Add(this.btnExecute);
            this.tabPage2.Controls.Add(this.dgvCleanupConfigs);
            this.tabPage2.Controls.Add(this.label7);
            this.tabPage2.Location = new Point(4, 22);
            this.tabPage2.Name = "tabPage2";
            this.tabPage2.Padding = new Padding(3);
            this.tabPage2.Size = new Size(976, 424);
            this.tabPage2.TabIndex = 1;
            this.tabPage2.Text = "清理配置";
            this.tabPage2.UseVisualStyleBackColor = true;
            
            // dgvCleanupConfigs
            this.dgvCleanupConfigs.Location = new Point(6, 30);
            this.dgvCleanupConfigs.Name = "dgvCleanupConfigs";
            this.dgvCleanupConfigs.Size = new Size(964, 350);
            this.dgvCleanupConfigs.TabIndex = 0;
            
            // btnExecute
            this.btnExecute.Location = new Point(6, 386);
            this.btnExecute.Name = "btnExecute";
            this.btnExecute.Size = new Size(100, 30);
            this.btnExecute.TabIndex = 1;
            this.btnExecute.Text = "执行清理";
            this.btnExecute.UseVisualStyleBackColor = true;
            this.btnExecute.Click += new EventHandler(this.btnExecute_Click);
            
            // 其他按钮类似设置...
            
            // tabPage3 - 清理历史
            this.tabPage3.Controls.Add(this.dgvCleanupHistory);
            this.tabPage3.Controls.Add(this.label8);
            this.tabPage3.Location = new Point(4, 22);
            this.tabPage3.Name = "tabPage3";
            this.tabPage3.Size = new Size(976, 424);
            this.tabPage3.TabIndex = 2;
            this.tabPage3.Text = "清理历史";
            this.tabPage3.UseVisualStyleBackColor = true;
            
            // 底部状态栏区域
            this.lblConnectionStatus.AutoSize = true;
            this.lblConnectionStatus.Location = new Point(10, 460);
            this.lblConnectionStatus.Name = "lblConnectionStatus";
            this.lblConnectionStatus.Size = new Size(107, 12);
            this.lblConnectionStatus.TabIndex = 1;
            this.lblConnectionStatus.Text = "数据库连接状态:";
            
            this.chkAutoCleanup.AutoSize = true;
            this.chkAutoCleanup.Location = new Point(150, 460);
            this.chkAutoCleanup.Name = "chkAutoCleanup";
            this.chkAutoCleanup.Size = new Size(84, 16);
            this.chkAutoCleanup.TabIndex = 2;
            this.chkAutoCleanup.Text = "自动清理";
            this.chkAutoCleanup.UseVisualStyleBackColor = true;
            this.chkAutoCleanup.CheckedChanged += new EventHandler(this.chkAutoCleanup_CheckedChanged);
            
            this.lblAutoCleanupStatus.AutoSize = true;
            this.lblAutoCleanupStatus.Location = new Point(250, 460);
            this.lblAutoCleanupStatus.Name = "lblAutoCleanupStatus";
            this.lblAutoCleanupStatus.Size = new Size(89, 12);
            this.lblAutoCleanupStatus.TabIndex = 3;
            this.lblAutoCleanupStatus.Text = "自动清理状态:";
            
            this.btnCheckNow.Location = new Point(350, 455);
            this.btnCheckNow.Name = "btnCheckNow";
            this.btnCheckNow.Size = new Size(100, 25);
            this.btnCheckNow.TabIndex = 4;
            this.btnCheckNow.Text = "立即检查";
            this.btnCheckNow.UseVisualStyleBackColor = true;
            this.btnCheckNow.Click += new EventHandler(this.btnCheckNow_Click);
            
            this.lblPendingTasks.AutoSize = true;
            this.lblPendingTasks.Location = new Point(460, 460);
            this.lblPendingTasks.Name = "lblPendingTasks";
            this.lblPendingTasks.Size = new Size(89, 12);
            this.lblPendingTasks.TabIndex = 5;
            this.lblPendingTasks.Text = "待执行任务:";
            
            this.lblLastCheckTime.AutoSize = true;
            this.lblLastCheckTime.Location = new Point(600, 460);
            this.lblLastCheckTime.Name = "lblLastCheckTime";
            this.lblLastCheckTime.Size = new Size(77, 12);
            this.lblLastCheckTime.TabIndex = 6;
            this.lblLastCheckTime.Text = "最后检查:";
            
            this.btnRefresh.Location = new Point(700, 455);
            this.btnRefresh.Name = "btnRefresh";
            this.btnRefresh.Size = new Size(100, 25);
            this.btnRefresh.TabIndex = 7;
            this.btnRefresh.Text = "刷新数据";
            this.btnRefresh.UseVisualStyleBackColor = true;
            this.btnRefresh.Click += new EventHandler(this.btnRefresh_Click);
            
            // 日志区域
            this.txtLog.Location = new Point(10, 485);
            this.txtLog.Multiline = true;
            this.txtLog.Name = "txtLog";
            this.txtLog.ReadOnly = true;
            this.txtLog.ScrollBars = ScrollBars.Vertical;
            this.txtLog.Size = new Size(864, 105);
            this.txtLog.TabIndex = 8;
            
            this.btnClearLog.Location = new Point(880, 485);
            this.btnClearLog.Name = "btnClearLog";
            this.btnClearLog.Size = new Size(100, 25);
            this.btnClearLog.TabIndex = 9;
            this.btnClearLog.Text = "清除日志";
            this.btnClearLog.UseVisualStyleBackColor = true;
            this.btnClearLog.Click += new EventHandler(this.btnClearLog_Click);
            
            // MainForm
            this.AutoScaleDimensions = new SizeF(6F, 12F);
            this.AutoScaleMode = AutoScaleMode.Font;
            this.ClientSize = new Size(984, 600);
            this.Controls.Add(this.btnClearLog);
            this.Controls.Add(this.txtLog);
            this.Controls.Add(this.btnRefresh);
            this.Controls.Add(this.lblLastCheckTime);
            this.Controls.Add(this.lblPendingTasks);
            this.Controls.Add(this.btnCheckNow);
            this.Controls.Add(this.lblAutoCleanupStatus);
            this.Controls.Add(this.chkAutoCleanup);
            this.Controls.Add(this.lblConnectionStatus);
            this.Controls.Add(this.tabControl1);
            this.Name = "MainForm";
            this.Text = "数据库自动清理系统 - .NET Framework 4.7.2";
            this.Load += new EventHandler(this.MainForm_Load);
            this.FormClosing += new FormClosingEventHandler(this.MainForm_FormClosing);
            this.tabControl1.ResumeLayout(false);
            this.tabPage1.ResumeLayout(false);
            this.tabPage1.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvRecentHistory)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.dgvTableSizes)).EndInit();
            this.groupBox1.ResumeLayout(false);
            this.groupBox1.PerformLayout();
            this.tabPage2.ResumeLayout(false);
            this.tabPage2.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvCleanupConfigs)).EndInit();
            this.tabPage3.ResumeLayout(false);
            this.tabPage3.PerformLayout();
            ((System.ComponentModel.ISupportInitialize)(this.dgvCleanupHistory)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();
        }
    }
}

三、系统功能说明

1. 主要功能

  • 按数量清理:保留最新的N条记录,删除超出数量的旧记录
  • 按日期清理:删除超过指定天数的历史记录
  • 自动清理:定时检查并执行清理任务
  • 清理配置管理:添加、编辑、删除清理规则
  • 历史记录查看:查看所有清理操作的历史记录
  • 实时监控:监控数据库状态和清理任务执行情况

2. 技术特点

  • 使用.NET Framework 4.7.2开发
  • SQL Server数据库存储
  • 存储过程实现核心清理逻辑
  • 多线程异步执行清理任务
  • 详细的日志记录和错误处理

3. 使用说明

  1. 先运行SQL脚本创建数据库和表结构
  2. 打开应用程序,系统会自动连接数据库
  3. 在"清理配置"页面添加清理规则
  4. 可以手动执行清理,也可以启用自动清理功能
  5. 在"监控面板"查看数据库状态和清理历史

4. 项目结构

复制代码
AutoCleanupSystem/
│
├── Program.cs              # 程序入口
├── MainForm.cs             # 主窗体
├── MainForm.Designer.cs    # 主窗体设计器
├── ConfigForm.cs           # 配置编辑窗体
├── ConfigForm.Designer.cs  # 配置编辑窗体设计器
├── DatabaseHelper.cs       # 数据库操作辅助类
├── App.config              # 配置文件
│
└── SQL/
    └── DatabaseSetup.sql   # 数据库初始化脚本
相关推荐
mifengxing2 小时前
操作系统(一)
大数据·数据库·操作系统
纯爱掌门人2 小时前
鸿蒙端云一体化开发(二):云数据库
数据库·华为·harmonyos·端云一体化
l1t3 小时前
DeepSeek辅助总结的测试PostgreSQL数据库插入性能方法
数据库·postgresql
赫萝的红苹果3 小时前
实验探究并验证MySQL innoDB中的各种锁机制及作用范围
android·数据库·mysql
霖霖总总3 小时前
[小技巧45]MySQL Undo Log解析:Undo Log分类与存储机制
数据库·mysql
曾经的三心草4 小时前
Redis-1-基础操作
数据库·redis·缓存
软件资深者4 小时前
HP M126a打印机,系统不支持请求的命令或者资源管理器出错
windows·windows11·系统修复
SJjiemo4 小时前
TreeSize Pro 专业磁盘空间分析
windows
电商API&Tina4 小时前
Python请求淘宝商品评论API接口全指南||taobao评论API
java·开发语言·数据库·python·json·php