傳統以字串拼接建構 SQL 查詢,不僅程式碼難讀、難維護,更極易引入 SQL 注入 風險:
string sql = "SELECT * FROM Customers WHERE 1=1";
if (!string.IsNullOrEmpty(name)) sql += " AND Name LIKE '" + name + "%'";
if (city != null) sql += " AND City = '" + city + "'"; // 直接拼接使用者輸入
存儲過程僅將問題轉移到資料庫層,動態 SQL 仍需拼接,注入風險依存。
SelectQueryBuilder 提供強型別、鏈式呼叫介面,自動處理參數化、條件組合、JOIN、分組排序等複雜邏輯,最終輸出參數化 SQL 或 DbCommand 物件。
var q = new SelectQueryBuilder();
q.SelectFromTable("Customers")
.SelectAllColumns()
.TopRecords = maxRecords;
if (!string.IsNullOrEmpty(name))
q.AddWhere("CompanyName", Comparison.Like, name + "%");
if (city != null)
q.AddWhere("City", Comparison.Like, city + "%");
if (country != null)
q.AddWhere("Country", Comparison.Equals, country);
// 產生參數化 SQL
string sql = q.BuildQuery();
// 或直接產生 DbCommand(自動參數化,防注入)
q.SetDbProviderFactory(DbProviderFactories.GetFactory("System.Data.SqlClient"));
DbCommand cmd = q.BuildCommand();
需直接嵌入資料庫函數(如 GETDATE())而不被加引號:
q.AddWhere("OrderDate", Comparison.LessOrEquals, new SqlLiteral("GETDATE()"));
// 生成:WHERE OrderDate <= GETDATE()
q.SelectFromTable("Orders")
.AddJoin(JoinType.InnerJoin, "Customers", "CustomerID", Comparison.Equals, "Orders", "CustomerID")
.AddWhere("Customers.City", Comparison.Equals, "London");
// 生成:INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID
q.SelectColumns("COUNT(*) AS Count", "ShipCity")
.SelectFromTable("Orders")
.GroupBy("ShipCity")
.AddHaving("ShipCity", Comparison.NotEquals, "Amsterdam")
.AddOrderBy("COUNT(*)", Sorting.Descending);
支援類似 SQL Server 查詢設計器的「準則/Or 欄」邏輯:
// 第 1 層:AND 關係
q.AddWhere("CustomerID", Comparison.Equals, "VINET", 1);
q.AddWhere("OrderDate", Comparison.LessThan, new DateTime(2005,1,1), 1);
// 第 2 層:OR 關係
q.AddWhere("CustomerID", Comparison.Equals, "TOMSP", 2);
q.AddWhere("OrderDate", Comparison.LessThan, new DateTime(2004,6,30), 2);
// 第 3 層:另一組 OR
q.AddWhere("CustomerID", Comparison.Equals, "TOMSP", 3);
q.AddWhere("OrderDate", Comparison.GreaterThan, new DateTime(2006,1,1), 3);
// 生成:WHERE (層1條件) OR (層2條件) OR (層3條件)
var clause = q.AddWhere("OrderDate", Comparison.LessThan, new DateTime(2004,6,30), 2);
clause.AddClause(LogicOperator.Or, Comparison.GreaterThan, new DateTime(2006,1,1));
// 生成:(OrderDate < '2004-06-30' OR OrderDate > '2006-01-01')
框架同步提供 InsertQueryBuilder、UpdateQueryBuilder、DeleteQueryBuilder,統一風格覆蓋 CRUD 全場景。原始碼與 DLL 可從 CodeEngine 獲取。
拒絕字串拼接,擁抱 SelectQueryBuilder:
DbProviderFactory,支援多種資料庫