1、ExecuteQuery方法
创新互联建站于2013年开始,是专业互联网技术服务公司,拥有项目做网站、网站建设网站策划,项目实施与项目整合能力。我们以让每一个梦想脱颖而出为使命,1280元丰满做网站,已为上家服务,为丰满各地企业和个人服务,联系电话:13518219792
看命名,我们很容易联想到ADO.NET里熟悉的Command的ExecuteNonQuery方法,但是VS的智能提示告诉我们这个方法返回的是一个泛型集合,应该“所思非所得”。下面通过一个简单方法,验证我们的猜想(数据库设计可以参考这一篇):
- ///
- /// 直接执行sql语句,获取总人数
- ///
- ///
- public int GetTotalCount()
- {
- string strSql = "SELECT COUNT(0) FROM Person(NOLOCK)";
- var query = dataContext.ExecuteQuery
(strSql); - int result = query.First
(); - Console.WriteLine();
- Console.WriteLine("total count:{0}", result);
- return result;
- }
调试的时候,通过IntelliTrace跟踪到:
毫无疑问,上面的图片说明最初的想法是不正确的,”ADO.NET:执行Reader…”云云,让我们更加坚信它实际执行的应该是ExecuteReader方法。当然最简单的方法是直接查看它的方法说明:
- // 摘要:
- // 直接对数据库执行 SQL 查询并返回对象。
- //
- // 参数:
- // query:
- // 要执行的 SQL 查询。
- //
- // parameters:
- // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
- 则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果某参数为
- // null,则该参数会转换为 DBNull.Value。
- //
- // 类型参数:
- // TResult:
- // 返回的集合中的元素的类型。
- //
- // 返回结果:
- // 由查询返回的对象的集合。
- public IEnumerable
ExecuteQuery (string query, params object[] parameters);
ExecuteQuery方法还有一个非泛型方法:
- //
- // 摘要:
- // 直接对数据库执行 SQL 查询。
- //
- // 参数:
- // elementType:
- //
要返回的 System.Collections.Generic.IEnumerable
- // 是由 System.Data.Linq.DataContext 显式跟踪的实体。
- System.Data.Linq.DataContext.ObjectTrackingEnabled
- // 为 true。实体具有主键。否则会引发异常。
- //
- // query:
- // 要执行的 SQL 查询。
- //
- // parameters:
- // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
- 则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果某参数为
- // null,则该参数会转换为 DBNull.Value。
- //
- // 返回结果:
- // 由查询返回的对象的 System.Collections.Generic.IEnumerable
集合。 - public IEnumerable ExecuteQuery(Type elementType, string query, params object[] parameters);
看它的参数需要多传递一个elementType,明显不如泛型方法简洁。
2、ExecuteCommand方法
同样道理,这个方法立刻让我们联想到(世界没有联想,生活将会怎样?),联想到,等等,不知联想到什么。然后我们看一下方法使用说明:
- //
- // 摘要:
- // 直接对数据库执行 SQL 命令。
- //
- // 参数:
- // command:
- // 要执行的 SQL 命令。
- //
- // parameters:
- // 要传递给命令的参数数组。注意下面的行为:如果数组中的对象的数目小于命令字符串中已标识的最大数,
- 则会引发异常。如果数组包含未在命令字符串中引用的对象,则不会引发异常。如果任一参数为
- // null,则该参数会转换为 DBNull.Value。
- //
- // 返回结果:
- // 一个 int,表示所执行命令修改的行数。
- public int ExecuteCommand(string command, params object[] parameters);
到这里,看它的返回类型为int,表示执行命令修改的行数,这次很容易想到ExecuteNonQuery方法。对不对呢?通过下面的代码证明我们的设想:
- ///
- /// 直接执行sql语句 根据用户Id更新体重
- ///
- /// 用户Id
- /// 更新后的体重
- ///
- public int ModifyWeightById(int id, double destWeight)
- {
- string strSql = string.Format("UPDATE Person SET Weight={0} WHERE Id={1}", destWeight, id);
- int result = dataContext.ExecuteCommand(strSql);
- Console.WriteLine();
- Console.WriteLine("affect num:{0}", result);
- return result;
- }
调试过程中,通过IntelliTrace可以很清楚地捕获:
“ADO.NET:执行NonQuery…”基本可以断言我们的设想是正确的。
3、防止sql注入
1和2中,执行sql语句的两个方法都有一个params 类型的参数,我们又会想到ADO.NET非常重要的sql语句的参数化防止sql注入问题。下面通过一个方法,看看linq2sql可不可以防止sql注入。
(1)、直接执行拼接的sql语句(有风险)
- ///
- /// 直接执行sql语句 根据用户Id更新FirstName
- ///
- /// 用户Id
- /// 更新后的FirstName
- ///
- public int ModifyNameById(int id, string destName)
- {
- string strSql = string.Format("UPDATE Person SET FirstName='{0}' WHERE Id={1}", destName, id);
- //这么拼接有风险
- int result = dataContext.ExecuteCommand(strSql);
- Console.WriteLine();
- Console.WriteLine("affect num:{0}", result);
- return result;
- }
然后,在客户端这样调用这个方法:
- int result = ServiceFactory.CreatePersonService().ModifyNameById(10, "'Anders'");
- //更新id为10的人的FirstName
运行的时候,直接抛出异常,提示“Anders”附近有语法错误。毫无疑问,它执行的sql语句:
- UPDATE Person SET FirstName=''Anders'' WHERE Id=10
是不能通过的,同时证明了string.format函数不能有效防止sql注入。
(2)、直接通过linq方法的参数传递,结果如何呢?
改进(1)的传参方法:
- ///
- /// 直接执行sql语句 根据用户Id更新FirstName
- ///
- /// 用户Id
- /// 更新后的FirstName
- ///
- public int ModifyNameById(int id, string destName)
- {
- //string strSql = string.Format("UPDATE Person SET FirstName='{0}' WHERE Id={1}", destName, id);
- //这么拼接有风险
- //int result = dataContext.ExecuteCommand(strSql);
- string strSql = "UPDATE Person SET FirstName={0} WHERE Id={1}";
- int result = dataContext.ExecuteCommand(strSql, new object[] { destName, id });
- Console.WriteLine();
- Console.WriteLine("affect num:{0}", result);
- return result;
- }
再次通过如下的方式调用:
- int result = ServiceFactory.CreatePersonService().ModifyNameById(10, "'Anders'");
- //更新id为10的人的FirstName
这一次运行正常吗?经测试,真的真的是真的正常,终于可以长松一口气了。查看数据库,Id为10的那一条记录的FirstName结果改变成了“'Anders'”(带单引号),明白ADO.NET工作原理的都知道这个一点也不神奇,不是吗?
对比(1)和(2),我们发现还是用linq2sql的源生方法传参比较好,通过拼接sql应该尽量避免。
到这里,可能你会认为上面1、2、3全是废话,知道怎么用不就行了嘛?!其实很长一部分时间我也是这么想这么做的。工作久了,早就习惯了不求甚解,现在看书,看园子里高手的博客,多多少少会有点反思。
4、思考
ADO.NET中比较常用的ExecuteScalar方法,在linq2sql应该怎么实现呢?您尝试使用过了吗?
原文链接:http://www.cnblogs.com/jeffwongishandsome/archive/2010/11/03/1868438.html
分享标题:LINQtoSQL:如何直接执行SQL语句
网站网址:http://www.stwzsj.com/qtweb/news13/9763.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联