SelectQueryBuilder類允許在你的代碼中建立復雜的SQL語句和命令。它也能幫助於避免SQL注入式攻擊。
介紹
承認,並且我們都這樣作過,也認為下面的方式是最好的和唯一的方式。就是我們建立大量的字符串包含所有的Where子句,然後提交到數據庫去執行它。來斷的加語句到我們的SQL字符串,極有可能會帶來Bugs和SQL注入式攻擊的危險。並且也使得我們的代碼更難看也不易於管理。
這種情況必須停止,但如何停止?有人說使用存儲過程。但它並沒有真正的解決這個問題。你還得動態建立你的SQL語句,只不過有問題移到數據庫層面上了,依然有SQL注入的危險。除了這個“解決方案”外,可能還有非常多的選擇供你考慮,但它們都會帶來一個基本的挑戰:讓SQL語句工作的更好、更安全。
當我從我的在線DAL(數據訪問層)生成工具http://www.code-engine.com/建立C#模板時,我想提供一個易於使用的方法來定制查詢數據。我不再想使用“字符串查詢”(我以前開發的模板)來查詢數據。我厭煩這種凌亂的方式來得到數據。我想用一種清晰的、直覺的、靈活的、簡單的方式從表中選擇數據,聯接一些別的語句,使用大量的Where子句,用一些列來分組數據,返回前X個記錄。
我開始開發所想的有這種嚴密功能的SelectQueryBuilder類。它暴露了許多屬性和方法,你能很容易地在Select語句中使用它們。一旦調用BuildQuery()和BuildCommand()方法,它能提供一種更好的舊的“字符串查詢“或可以使用命令參數的DbCommand對象來查詢數據。
使用代碼
舊的方式的代碼
下面的代碼闡明了以前建立SELECT語句的方法,它使用許多類變量來說明應該使用那種連接操作(WHERE,或者OR),同時也給你的數據庫帶來了可能的SQL注入式攻擊。
string statement = "SELECT TOP " + maxRecords + " * FROM Customers "; string whereConcatenator = "WHERE "; if (companyNameTextBox.Text.Length > 0) { statement += whereConcatenator; statement += "CompanyName like '" + companyNameTextBox.Text + "%' "; whereConcatenator = "AND "; } if (cityTextBox.Text.Length > 0) { statement += whereConcatenator; statement += "City like '" + cityTextBox.Text + "%' "; whereConcatenator = "AND "; } if (countryComboBox.SelectedItem != null) { statement += whereConcatenator; statement += "Country = '" + countryComboBox.SelectedItem + "' "; whereConcatenator = "AND "; }
我相信上面的代碼對你來說是非常熟悉的,你可能在過去的十多年一直是這樣使用的,或者你曾經編碼過數據庫驅動的搜索功能。讓我告訴你這種思想:這種查詢你的數據庫的方法不能再使用了,它是難看的也是不安全的。
SelectQueryBuilder方式的代碼
同樣的查詢能夠使用SelectQueryBuilder類建立。
SelectQueryBuilder query = new SelectQueryBuilder(); query.SelectFromTable("Customers"); query.SelectAllColumns(); query.TopRecords = maxRecords; if (companyNameTextBox.Text.Length > 0) query.AddWhere("CompanyName", Comparison.Like,companyNameTextBox.Text + "%"); if (cityTextBox.Text.Length > 0) query.AddWhere("City", Comparison.Like, cityTextBox.Text + "%"); if (countryComboBox.SelectedItem != null) query.AddWhere("Country", Comparison.Equals, countryComboBox.SelectedItem); string statement = query.BuildQuery(); // or, have a DbCommand object built // for even more safety against SQL Injection attacks: query.SetDbProviderFactory( DbProviderFactories.GetFactory( "System.Data.SqlClient")); DbCommand command = query.BuildCommand();
你能看到,這種方式比直接使用連接字符串更直觀。考慮到第一個例子SQL注入的危險,通過SelectQueryBuilder建立的SELECT查詢是非常安全的,並不用擔心使用的TextBoxs中的內容。事實上它也非常簡單!
使用SQL函數
如果你想在你的查詢中使用SQL函數,你能使用SqlLiteral類來打包函數的調用。說明這個類能作什麼的最好方式就是給你顯示一小段代碼例子: