首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 數據庫知識 >  >> SQL Server 資料庫 >> 關於SqlServer

輕量級 SQL 建構工具:BuildQuery 類完整實作與使用指南

     編輯:關於SqlServer

設計初衷

避免字串拼接 SQL 的痛苦:參數處理、引號、逗號、WHERE 條件組裝。`BuildQuery` 類封裝欄位/值/引號/運算子,支援 `INSERT`/`UPDATE`/`DELETE` 三大操作,可重複使用 (Flush 機制),輸出參數化就緒的 SQL 字串 (仍需配合參數化執行防注入)。

核心類別完整程式碼 (C#)


public class BuildQuery
{
    #region Fields
    private readonly Dictionary _fields = new();      // 欄位名 -> 欄位名 (保持順序)
    private readonly Dictionary _data = new();        // 欄位名 -> 值
    private readonly Dictionary _quotes = new();        // 欄位名 -> 是否加引號
    private readonly List _idFields = new();                  // WHERE 條件欄位
    private readonly List _idValues = new();                  // WHERE 條件值
    private readonly List _idQuotes = new();                    // WHERE 條件引號
    private readonly List _idOperators = new();               // WHERE 條件運算子
    private string _table;
    private bool _getIdentity;
    #endregion

    #region Properties
    public string Table { get => _table; set => _table = value; }
    public bool GetIdentity { get => _getIdentity; set => _getIdentity = value; }
    #endregion

    #region Public Methods
    public void FlushAllData() {
        _fields.Clear(); _data.Clear(); _quotes.Clear();
        _idFields.Clear(); _idValues.Clear(); _idQuotes.Clear(); _idOperators.Clear();
    }

    /// 加入 SET/VALUES 欄位與值
    public void Build(string field, string value, bool quotes) {
        if (!_fields.ContainsKey(field)) _fields[field] = field;
        _data[field] = value;
        _quotes[field] = quotes;
    }

    /// 加入 WHERE 條件 (預設 =)
    public void IDSettings(string field, string value, bool quotes) 
        => IDSettings(field, value, quotes, "=");

    /// 加入 WHERE 條件 (自訂運算子)
    public void IDSettings(string field, string value, bool quotes, string op) {
        _idFields.Add(field); _idValues.Add(value); _idQuotes.Add(quotes); _idOperators.Add(op);
    }

    public string Insert() {
        if (string.IsNullOrEmpty(_table)) return "ERROR: Table not set";
        var sb = new StringBuilder($"INSERT INTO {_table} (");
        int i = 0, n = _data.Count;
        foreach (var kv in _fields) {
            sb.Append(kv.Value); if (++i < n) sb.Append(", ");
        }
        sb.Append(") VALUES (");
        i = 0;
        foreach (var kv in _data) {
            if (_quotes[kv.Key]) sb.Append("'");
            sb.Append(kv.Value);
            if (_quotes[kv.Key]) sb.Append("'");
            if (++i < n) sb.Append(", ");
        }
        sb.Append(")");
        if (_getIdentity) sb.Append("; SELECT SCOPE_IDENTITY() AS NewId;");
        return sb.ToString();
    }

    public string Update() {
        if (string.IsNullOrEmpty(_table)) return "ERROR: Table not set";
        var sb = new StringBuilder($"UPDATE {_table} SET ");
        int i = 0, n = _data.Count;
        foreach (var kv in _fields) {
            sb.Append($"{kv.Value} = ");
            if (_quotes[kv.Key]) sb.Append("'");
            sb.Append(_data[kv.Key]);
            if (_quotes[kv.Key]) sb.Append("'");
            if (++i < n) sb.Append(", ");
        }
        if (_idFields.Count > 0) {
            sb.Append(" WHERE ");
            for (int j = 0; j < _idFields.Count; j++) {
                if (j > 0) sb.Append(" AND ");
                sb.Append($"{_idFields[j]} {_idOperators[j]} ");
                if (_idQuotes[j]) sb.Append("'");
                sb.Append(_idValues[j]);
                if (_idQuotes[j]) sb.Append("'");
            }
        }
        return sb.ToString();
    }

    public string Delete() {
        if (string.IsNullOrEmpty(_table)) return "ERROR: Table not set";
        var sb = new StringBuilder($"DELETE FROM {_table} WHERE ");
        for (int j = 0; j < _idFields.Count; j++) {
            if (j > 0) sb.Append(" AND ");
            sb.Append($"{_idFields[j]} {_idOperators[j]} ");
            if (_idQuotes[j]) sb.Append("'");
            sb.Append(_idValues[j]);
            if (_idQuotes[j]) sb.Append("'");
        }
        return sb.ToString();
    }
    #endregion
}

使用範例

INSERT (含身分識別回傳)


var q = new BuildQuery { Table = "Users", GetIdentity = true };
q.Build("Name", "John Smith", true);
q.Build("Age", "30", false);
q.Build("Email", "john@example.com", true);
string sql = q.Insert();
// INSERT INTO Users (Name, Age, Email) VALUES ('John Smith', 30, 'john@example.com'); SELECT SCOPE_IDENTITY() AS NewId;
q.FlushAllData(); // 重用物件

UPDATE


q.Table = "Users";
q.IDSettings("Id", "123", false);
q.Build("Name", "John Updated", true);
q.Build("Age", "31", false);
string sql = q.Update();
// UPDATE Users SET Name = 'John Updated', Age = 31 WHERE Id = 123

DELETE


q.Table = "Users";
q.IDSettings("Id", "123", false);
q.IDSettings("IsActive", "0", false, "<>"); // 自訂運算子
string sql = q.Delete();
// DELETE FROM Users WHERE Id = 123 AND IsActive <> 0

進階建議與擴充

  • 參數化整合:輸出 SQL 含參數佔位符 (`@p0`, `@p1`...),並回傳 `Dictionary` 參數集合,直接餵給 `SqlCommand.Parameters`,徹底防注入。
  • 型別安全:`Build` 方法改為泛型 `Build(field, T value)`,內部根據型別決定引號/格式 (日期、GUID、布林)。
  • 條件群組:支援 `OR`、`IN`、`BETWEEN`、巢狀群組 `(` `)`。
  • 方言適配:抽象 `SqlDialect` 介面,支援 MySQL/PostgreSQL/Oracle 引號/限制語法差異。
  • 驗證模式:`Validate()` 檢查必填欄位、主鍵條件、資料型別一致性。

總結

`BuildQuery` 以字典+列表輕量封裝 SQL 建構細節,解決「引號、逗號、AND、WHERE」的重複勞動,適合中小型專案、動態報表、遷移腳本快速生成 SQL。核心價值:**關注點分離** (業務邏輯 vs SQL 語法)、**可重用物件** (Flush 機制)、**可擴充架構**。生產核心系統仍建議使用成熟 ORM (EF Core, Dapper) 或預存程序。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved