国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 開發 > 綜合 > 正文

在C#中建立復雜的、靈活的SQL查詢/命令

2024-07-21 02:28:36
字體:
來源:轉載
供稿:網友

  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類來打包函數的調用。說明這個類能作什么的最好方式就是給你顯示一小段代碼例子:

selectquerybuilder query = new selectquerybuilder();
query.selectfromtable("orders");
query.addwhere("orderdate", comparison.lessorequals,new sqlliteral("getdate()"));

  如果我們沒有打包getdate()函數調用到sqlliteral類中,建立的查詢就會產生where子句:orderdate<=’getdate()’。當然,我們希望在語句中的這個函數沒有被單引號包圍。這時sqlliteral就可以派上用場了:它直接拷貝字符串到輸出,并沒有把它格式化成字符串?,F在的輸出where子句應當是orderdate<=getdate()!

  查詢中使用joins

  要創建到其它表的joins,你能使用addjoin方法。下面的代碼顯示了如何創建一個從ordres表到customers表的inner join。

selectquerybuilder query = new selectquerybuilder();
query.selectfromtable("orders");
query.addjoin(jointype.innerjoin,"customers", "customerid",comparison.equals,"orders", "customerid");
query.addwhere("customers.city",comparison.equals, "london");

  這段代碼選擇所有居住在london的客戶的訂單。一旦調用了buildquery方法,就會產生下面的sql語句:

select orders.*
from orders
inner join customers on orders.customerid = customers.customerid
where (customers.city = 'london')

  注意到缺省的查詢只會建立所選擇的表的selects * 語句(這個例子中的orders.*)。如果你也想選擇連接表的列的話,你必須得顯式地選擇它們。你能通用調用query.selectcolumns(“orders.*”,”customers.*”)。

  建立計算查詢

  如果你想對你的數據庫執行一個計算查詢。你能使用selectcount方法如同下面顯示的:

  query.selectcount();

  在更加復雜的計算查詢中,你可能想使用group by語句??匆幌孪旅娴睦?,它顯示了如何使用groupby和addhaving方法。

selectquerybuilder query = new selectquerybuilder();
query.selectcolumns("count(*) as count", "shipcity");
query.selectfromtable("orders");
query.groupby("shipcity");
query.addhaving("shipcity", comparison.notequals, "amsterdam");
query.addorderby("count(*)", sorting.descending);

  上面的代碼選擇了每個城市的訂單數,并用訂單數目排序,不考慮來自制amsterdam的訂單,buildquery方法的輸出結果應當是:

select count(*) as count, shipcity
from orders
group by shipcity
having (shipcity <> 'amsterdam')
order by count(*) desc

  復雜的where語句

  如果你曾經用過微軟的access或sql server的內置的查詢生成器的話,是否驚訝你能建立和代碼一樣的包含多層ands和ors,并沒有關心()符號的位置的查詢?是的?我也能!

  你能使用selectquerybuilder類實現!你能加多層的where語句到你的查詢。缺省,所有對query.addwhere的調用被放在查詢的第一層上。你可以把它比作sql server查詢生成器的’criteria’列;第二、三、四層等相應地對應于’or…’列。

  看一下下面的sql server查詢生成器的快照,通過它我能快速地把簡單的假的select語句放在一起來:

  如你看到的,我創建一個查詢,它選擇所有在1-1-2005日期之前的客戶’vinet’的訂單,和所有30-6-2004日期之前或1-1-2006日期之后的客戶’tomsp’的訂單(請不要問為什么有人想查詢某個人的訂單,這僅僅是一個 例子)。這個查詢能夠建立:

selectquerybuilder query = new selectquerybuilder();
query.selectfromtable("orders");
// add 'criteria' column to level 1
query.addwhere("customerid", comparison.equals,"vinet", 1);
query.addwhere("orderdate", comparison.lessthan,new datetime(2005,1,1), 1);
// add first 'or...' column to level 2
query.addwhere("customerid", comparison.equals, "tomsp", 2);
query.addwhere("orderdate", comparison.lessthan,new datetime(2004,6,30), 2);
// add second 'or...' column to level 3
query.addwhere("customerid", comparison.equals,"tomsp", 3);
query.addwhere("orderdate", comparison.greaterthan,new datetime(2006,1,1), 3);

  當調用 buildquery時,所有定義的層將被or到一起,幾乎和sql server生成的一樣。

  如果你到所產生的語句接近一樣時,想讓查詢更復雜,你可能會說“我的放兩個隨后的語句一起放在一個語句中,在兩個日期間使用or”。你能夠這樣作。在sql server查詢生成器中,這個查詢看起來像:

  同樣,它也可能使用selectquerybuilder通過創建’嵌套的where子句’來實現。

selectquerybuilder query = new selectquerybuilder();
query.selectfromtable("orders");
// add 'criteria' column to level 1
query.addwhere("customerid", comparison.equals, "vinet", 1);
query.addwhere("orderdate", comparison.lessthan,
new datetime(2005,1,1), 1);
// add 'or...' column to level 2
query.addwhere("customerid",
comparison.equals, "tomsp", 2);
// add the date selection clause
whereclause clause =query.addwhere("orderdate", comparison.lessthan,
  new datetime(2004,6,30), 2);
// add a nested clause to the captured clause
clause.addclause(logicoperator.or,
comparison.greaterthan, new datetime(2006,1,1));

  注意到我用了一個whereclause對象,它由addwhere調用返回。接著調用clause.addclause創建一個嵌套的子句柄,并且選擇通過指定logicoperator.or來把它or到第一個子句上。所產生的語句如下:

select orders.*
from orders
where
(
 (customerid = 'vinet')
 and (orderdate < '2005/01/01 12:00:00')
)
or
(
 (customerid = 'tomsp')
 and (orderdate < '2004/06/30 12:00:00' or
 orderdate > '2006/01/01 12:00:00')
)

  請注意這個例子中日期包含’12:00:00’,這是因為我在datetime構造體中忽略了時間。但這只要由于我的習慣。如果我使用new datetime(2006,1,1,0,0,0),日期字符串將包含’00:00:00’。

  結論

  在介紹中我就提到,selectquerybuilder是codeengine框架的一部分。這個框架 也包含了deletequerybuilder,updatequerybuilder,insertquerybuilder。我在通過我的c#dal產生器生成的代碼中使用這些生成器。你能從www.code-engine.com上下載一份 框架dll的拷貝。在這期間我也將發布其它的查詢生成器的源代碼。同時如果你有什么問題,評價或建議,請及時與我聯系。
  • 本文來源于網頁設計愛好者web開發社區http://www.html.org.cn收集整理,歡迎訪問。
  • 發表評論 共有條評論
    用戶名: 密碼:
    驗證碼: 匿名發表
    主站蜘蛛池模板: 景谷| 麻江县| 无棣县| 尚志市| 康保县| 怀化市| 南雄市| 莱芜市| 琼结县| 昌图县| 灵山县| 渭南市| 万山特区| 洛扎县| 马鞍山市| 丹寨县| 庄河市| 南乐县| 新乡县| 色达县| 烟台市| 景洪市| 上思县| 定西市| 清远市| 呼玛县| 金昌市| 宝应县| 砀山县| 波密县| 靖宇县| 莱州市| 镇平县| 庆城县| 大厂| 金阳县| 新绛县| 延庆县| 城固县| 田东县| 榆林市|