设为首页 收藏本站
查看: 1054|回复: 0

[经验分享] 对数据访问层的重构(及重构中Perl的应用)

[复制链接]

尚未签到

发表于 2015-12-25 15:55:40 | 显示全部楼层 |阅读模式
以前上学的时候,听到“一个学生在毕业后刚刚开始编程的头几年中,写出的代码多半是垃圾”这样的说法,均不屑一顾。现在工作一年多了,越发感觉自己代码中疏漏处甚多,故近来常做亡羊补牢的重构之举。拿自己4个月前写的数据访问层来说,这个层位于整个系统的最底端,根据传入的sql语句进行查询和更新操作。就拿查询来说吧,我当时觉得很简单,写出来的方法是这样的:

1 DSC0000.gif //代码段1
2public DataTable ExecuteQuery(string cmdText)
3 DSC0001.gif DSC0002.gif DSC0003.gif {
4 DSC0004.gif     if (cmdText == null)
5        return null;
6
7    SqlDataAdapter adapter = new SqlDataAdapter(cmdText, connection);
8    DataTable table = new DataTable();
9    try
10 DSC0005.gif DSC0006.gif     {
11        adapter.Fill(table);
12 DSC0007.gif     }
13    catch (SqlException e)
14    {
15
16        HttpContext.Current.Response.Redirect(string.format("~/ErrorPage?ErrorString={0}", HttpContext.Current.Server.UrlEncode(e.Message)));
17    }
18    finally
19    {
20            connection.Close();
21    }
22
23    return table;
24 DSC0008.gif }
而此方法都是这样被我调用的:

1//代码段2
2string cmd = "select * from MaterialClass where MaterialClassCode = {0}";
3cmd = string.Format(cmd, scope);
4DataTable table = new BitAECSqlExe().ExecuteQuery(cmd);
有心的朋友很容易就能看出,如此的代码是非常脆弱的,根本无法应付查询字符串中出现特殊字符的情况(单引号,百分号等)。程序容错性差不说,还容易遭到sql注入的攻击。另外,对于sql操作可能抛出的异常,这里捕获之后就跳转到出错页的方式也是很糟糕的;因为这段底层代码,除了会被页面调用以外,还会被其他一些不是由客户端请求引发的功能所调用(如部署到服务器上的windows服务,处理复杂任务的专用工作线程等),在这些调用环境里HttpContext.Current是没有意义的。实际上,在这种底层的代码里,只能对异常作必要的处理,至于究竟是跳转到一个友好的错误提示界面,还是写入错误日志,应当交给更高层的代码去决定。
  对这部分的重构其实很简单,那就是在进行查询的时候,对于所有参数都以SqlParameter进行封装。重构中新增了方法PrepareCommand,用来得到我们需要的SqlCommand对象。对ExecuteQuery的重构如下:

1//代码段3
2private SqlCommand PrepareCommand(string cmdText, SqlParameter[] cmdParms)
3{
4    if (cmdText == null)
5        throw new ArgumentNullException();
6
7    SqlCommand cmd = new SqlCommand(cmdText, connection);
8    if((cmdParms!=null)&&(cmdParms.Length>0))
9        foreach (SqlParameter param in cmdParms)
10        {
11            cmd.Parameters.Add(param);
12        }
13
14    return cmd;
15}
16
17public DataTable ExecuteQuery(string cmdText, SqlParameter[] sqlParams)
18{
19    if (cmdText == null)
20        return null;
21
22    SqlDataAdapter adapter = new SqlDataAdapter(this.PrepareCommand(cmdText,sqlParams));
23    DataTable table = new DataTable();
24    try
25    {
26        adapter.Fill(table);
27    }
28    catch (SqlException e)
29    {
30        throw e;
31    }
32    finally
33    {
34        if (connection.State != ConnectionState.Open)
35            connection.Close();
36    }
37
38    return table;
39}  上面重构的是ExecuteQuery方法的定义部分,这其实只是重构的开始,因为现有代码中充满了类似代码段2那样的方法调用,都需要改成如下的形式:

1//代码段4
2string cmd = "select * from MaterialClass where MaterialClassCode = @MaterialClassCode and CompanyName = @CompanyName";
3SqlParameter[] SqlParams =
4{
5    new SqlParameter("@MaterialClassCode",MaterialClassCode ),
6    new SqlParameter("@CompanyName",CompanyName )
7}
8DataTable table = new BitAECSqlExe().ExecuteQuery(cmd);  比照一下上面贴出的代码段2和代码段4,它们之间的差异就是我很希望自己能通过正则表达式跨越的鸿沟(一个一个手工去改的话实在太累了,一百多处啊,呵呵)。需要注意的是,查询语句中可能出现的参数个数是不定的,每个文件中可能包含的方法调用的数量也是不定的。本想写一个C#的console小程序来完成这个批量操作,但又总觉得杀鸡用牛刀,后来写了一个简单的perl脚本,利用perl强大的文本处理能力,很容易就实现了这个功能。脚本代码如下:

1use FileHandle;
2use File::Find;
3use strict;
4
5#全局变量
6my $directory = "E:/GEA52_SVN/GEA52/Web";
7#my $directory = "E:/Temp/Perl";
8
9find(\&editFile, $directory);
10
11#使用这个方法来修改每一个代码文件
12#xingyk 20070702
13sub editFile()
14{
15    if ( -f and /.cs?/ )
16    {
17        my $file = $_;
18        open FILE, $file;
19        my @lines = <FILE>;
20        close FILE;
21        
22        my @maArr;
23        for my $line ( @lines )
24        {
25            @maArr = $line =~ /\s+(\w+)\s*={\d}/g;
26            
27            #先替换原有查询字符串
28            $line =~ s/\s+(\w+)\s*={\d}/ $1=\@$1 /g;
29            #接下来添加SqlParameter数组的默认构造器
30            my $sqlParam = "\n\tSqlParameter[] sqlParams = { ";
31            if(@maArr>0)
32            {
33                for(@maArr)
34                {
35                    $sqlParam = $sqlParam."\t\tnew SqlParameter(\"@".$_."\", ".$_."),\n";
36                }
37                $line = $line.$sqlParam."\t\t\t};\n";
38            }
39            
40        }
41
42        open FILE, ">$file";
43        print FILE @lines;
44        close FILE;
45    }
46}  

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-156315-1-1.html 上篇帖子: Perl 多进程文件锁 下篇帖子: perl正则表达式[转]
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表