|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
java的设计机制:首先产生一个中间码,第二部编译为本地(机器)码。这个机制有很大的缺点。sql<P> 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注进式打击。
stringstatement="SELECTTOP"+maxRecords+"*FROMCustomers";
stringwhereConcatenator="WHERE";
if(companyNameTextBox.Text.Length>0)
{
statement+=whereConcatenator;
statement+="CompanyNamelike"+companyNameTextBox.Text+"%";
whereConcatenator="AND";
}
if(cityTextBox.Text.Length>0)
{
statement+=whereConcatenator;
statement+="Citylike"+cityTextBox.Text+"%";
whereConcatenator="AND";
}
if(countryComboBox.SelectedItem!=null)
{
statement+=whereConcatenator;
statement+="Country="+countryComboBox.SelectedItem+"";
whereConcatenator="AND";
}
我信任下面的代码对你来讲长短常熟习的,你大概在已往的十多年一向是如许利用的,大概你已经编码过数据库驱动的搜刮功效。让我告知你这类头脑:这类查询你的数据库的办法不克不及再利用了,它是丢脸的也是不平安的。
SelectQueryBuilder体例的代码
一样的查询可以利用SelectQueryBuilder类创建。
SelectQueryBuilderquery=newSelectQueryBuilder();
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);
stringstatement=query.BuildQuery();
//or,haveaDbCommandobjectbuilt
//forevenmoresafetyagainstSQLInjectionattacks:
query.SetDbProviderFactory(
DbProviderFactories.GetFactory(
"System.Data.SqlClient"));
DbCommandcommand=query.BuildCommand();
你能看到,这类体例比间接利用毗连字符串更直不雅。思索到第一个例子SQL注进的伤害,经由过程SelectQueryBuilder创建的SELECT查询长短常平安的,其实不用忧虑利用的TextBoxs中的内容。现实上它也十分复杂!
利用SQL函数
假如你想在你的查询中利用SQL函数,你能利用SqlLiteral类来打包函数的挪用。申明这个类能作甚么的最好体例就是给你显现一小段代码例子:
SelectQueryBuilderquery=newSelectQueryBuilder();
query.SelectFromTable("Orders");
query.AddWhere("OrderDate",Comparison.LessOrEquals,newSqlLiteral("getDate()"));
假如我们没有打包getDate()函数挪用到SqlLiteral类中,创建的查询就会发生WHERE子句:OrderDate<=’getDate()’。固然,我们但愿在语句中的这个函数没有被单引号包抄。这时候SqlLiteral就能够派上用处了:它间接拷贝字符串到输入,并没有把它格局化成字符串。如今的输入WHERE子句应该是OrderDate<=getDate()!
查询中利用JOINs
要创立到别的表的JOINs,你能利用AddJoin办法。上面的代码显现了怎样创立一个从Ordres表到Customers表的INNERJOIN。
SelectQueryBuilderquery=newSelectQueryBuilder();
query.SelectFromTable("Orders");
query.AddJoin(JoinType.InnerJoin,"Customers","CustomerID",Comparison.Equals,"Orders","CustomerID");
query.AddWhere("Customers.City",Comparison.Equals,"London");
这段代码选择一切寓居在London的客户的定单。一旦挪用了BuildQuery办法,就会发生上面的SQL语句:
SELECTOrders.*
FROMOrders
INNERJOINCustomersONOrders.CustomerID=Customers.CustomerID
WHERE(Customers.City=London)
注重到缺省的查询只会创建所选择的表的selects*语句(这个例子中的Orders.*)。假如你也想选择毗连表的列的话,你必需得显式地选择它们。你能通用挪用query.SelectColumns(“Orders.*”,”Customers.*”)。
<P> 创建盘算查询
假如你想对你的数据库实行一个盘算查询。你能利用SelectCount办法好像上面显现的:
Query.SelectCount();
在加倍庞大的盘算查询中,你大概想利用GROUPBY语句。看一下上面的例子,它显现了怎样利用GroupBy和AddHaving办法。
SelectQueryBuilderquery=newSelectQueryBuilder();
query.SelectColumns("count(*)ASCount","ShipCity");
query.SelectFromTable("Orders");
query.GroupBy("ShipCity");
query.AddHaving("ShipCity",Comparison.NotEquals,"Amsterdam");
query.AddOrderBy("count(*)",Sorting.Descending);
下面的代码选择了每一个乡村的定单数,并用定单数量排序,不思索来便宜Amsterdam的定单,BuildQuery办法的输入了局应该是:
SELECTcount(*)ASCount,ShipCity
FROMOrders
GROUPBYShipCity
HAVING(ShipCityAmsterdam)
ORDERBYcount(*)DESC
庞大的Where语句
假如你已经用过微软的Access或SQLServer的内置的查询天生器的话,是不是惊奇你能创建和代码一样的包括多层ANDs和Ors,并没有体贴()标记的地位的查询?是的?我也能!
你能利用SelectQueryBuilder类完成!你能加多层的WHERE语句到你的查询。缺省,一切对query.AddWhere的挪用被放在查询的第一层上。你能够把它比作SQLServer查询天生器的’Criteria’列;第2、3、四层等响应地对应于’Or…’列。
看一下上面的SQLServer查询天生器的快照,经由过程它我能疾速地把复杂的假的SELECT语句放在一同来:
如你看到的,我创立一个查询,它选择一切在1-1-2005日期之前的客户’VINET’的定单,和一切30-6-2004日期之前或1-1-2006日期以后的客户’TOMSP’的定单(请不要问为何有人想查询某团体的定单,这仅仅是一个例子)。这个查询可以创建:
SelectQueryBuilderquery=newSelectQueryBuilder();
query.SelectFromTable("Orders");
//AddCriteriacolumntolevel1
query.AddWhere("CustomerID",Comparison.Equals,"VINET",1);
query.AddWhere("OrderDate",Comparison.LessThan,newDateTime(2005,1,1),1);
//AddfirstOr...columntolevel2
query.AddWhere("CustomerID",Comparison.Equals,"TOMSP",2);
query.AddWhere("OrderDate",Comparison.LessThan,newDateTime(2004,6,30),2);
//AddsecondOr...columntolevel3
query.AddWhere("CustomerID",Comparison.Equals,"TOMSP",3);
query.AddWhere("OrderDate",Comparison.GreaterThan,newDateTime(2006,1,1),3);
当挪用BuildQuery时,一切界说的层将被OR到一同,几近和SQLServer天生的一样。
假如你到所发生的语句靠近一样时,想让查询更庞大,你大概会说“我的放两个随后的语句一同放在一个语句中,在两个日时代利用OR”。你可以如许作。在SQLServer查询天生器中,这个查询看起来像:
一样,它也大概利用SelectQueryBuilder经由过程创立’嵌套的WHERE子句’来完成。
SelectQueryBuilderquery=newSelectQueryBuilder();
query.SelectFromTable("Orders");
//AddCriteriacolumntolevel1
query.AddWhere("CustomerID",Comparison.Equals,"VINET",1);
query.AddWhere("OrderDate",Comparison.LessThan,
newDateTime(2005,1,1),1);
//AddOr...columntolevel2
query.AddWhere("CustomerID",
Comparison.Equals,"TOMSP",2);
//Addthedateselectionclause
WhereClauseclause=query.AddWhere("OrderDate",Comparison.LessThan,
newDateTime(2004,6,30),2);
//Addanestedclausetothecapturedclause
clause.AddClause(LogicOperator.Or,
Comparison.GreaterThan,newDateTime(2006,1,1));
注重到我用了一个WhereClause工具,它由AddWhere挪用前往。接着挪用clause.AddClause创立一个嵌套的子句柄,而且选择经由过程指定LogicOperator.Or来把它OR到第一个子句上。所发生的语句以下:
SELECTOrders.*
FROMOrders
WHERE
(
(CustomerID=VINET)
AND(OrderDate<2005/01/0112:00:00)
)
OR
(
(CustomerID=TOMSP)
AND(OrderDate<2004/06/3012:00:00OR
OrderDate>2006/01/0112:00:00)
)
请注重这个例子中日期包括’12:00:00’,这是由于我在DateTime机关体中疏忽了工夫。但这只需因为我的习气。假如我利用newDateTime(2006,1,1,0,0,0),日期字符串将包括’00:00:00’。
结论
在先容中我就提到,SelectQueryBuilder是CodeEngine框架的一部分。这个框架也包括了DeleteQueryBuilder,UpdateQueryBuilder,InsertQueryBuilder。我在经由过程我的C#DAL发生器天生的代码中利用这些天生器。你能从www.code-engine.com高低载一份框架DLL的拷贝。在这时代我也将公布别的的查询天生器的源代码。同时假如你有甚么成绩,评价或倡议,请实时与我接洽。c语言的编译器,几乎是所有新平台都有的。因此从这点上看,c语言的程序,比其他任何语言更加容易跨平台。 |
|