码迷,mamicode.com
首页 > 其他好文 > 详细

对数据访问层的重构(及重构中Perl的应用)

时间:2014-09-17 18:10:02      阅读:263      评论:0      收藏:0      [点我收藏+]

标签:blog   http   io   os   使用   ar   for   文件   数据   

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

 1bubuko.com,布布扣//代码段1
 2bubuko.com,布布扣public DataTable ExecuteQuery(string cmdText)
 3bubuko.com,布布扣{
 4bubuko.com,布布扣    if (cmdText == null)
 5bubuko.com,布布扣        return null;
 6bubuko.com,布布扣
 7bubuko.com,布布扣    SqlDataAdapter adapter = new SqlDataAdapter(cmdText, connection);
 8bubuko.com,布布扣    DataTable table = new DataTable();
 9bubuko.com,布布扣    try
10bubuko.com,布布扣    {
11bubuko.com,布布扣        adapter.Fill(table);
12bubuko.com,布布扣    }
13bubuko.com,布布扣    catch (SqlException e)
14bubuko.com,布布扣    {
15bubuko.com,布布扣
16bubuko.com,布布扣        HttpContext.Current.Response.Redirect(string.format("~/ErrorPage?ErrorString={0}", HttpContext.Current.Server.UrlEncode(e.Message)));
17bubuko.com,布布扣    }
18bubuko.com,布布扣    finally
19bubuko.com,布布扣    {
20bubuko.com,布布扣            connection.Close();
21bubuko.com,布布扣    }
22bubuko.com,布布扣
23bubuko.com,布布扣    return table;
24bubuko.com,布布扣}


而此方法都是这样被我调用的:

1bubuko.com,布布扣//代码段2
2bubuko.com,布布扣string cmd = "select * from MaterialClass where MaterialClassCode = {0}";
3bubuko.com,布布扣cmd = string.Format(cmd, scope);
4bubuko.com,布布扣DataTable table = new BitAECSqlExe().ExecuteQuery(cmd);


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

 1bubuko.com,布布扣//代码段3
 2bubuko.com,布布扣private SqlCommand PrepareCommand(string cmdText, SqlParameter[] cmdParms)
 3bubuko.com,布布扣{
 4bubuko.com,布布扣    if (cmdText == null)
 5bubuko.com,布布扣        throw new ArgumentNullException();
 6bubuko.com,布布扣
 7bubuko.com,布布扣    SqlCommand cmd = new SqlCommand(cmdText, connection);
 8bubuko.com,布布扣    if((cmdParms!=null)&&(cmdParms.Length>0))
 9bubuko.com,布布扣        foreach (SqlParameter param in cmdParms)
10bubuko.com,布布扣        {
11bubuko.com,布布扣            cmd.Parameters.Add(param);
12bubuko.com,布布扣        }
13bubuko.com,布布扣
14bubuko.com,布布扣    return cmd;
15bubuko.com,布布扣}
16bubuko.com,布布扣
17bubuko.com,布布扣public DataTable ExecuteQuery(string cmdText, SqlParameter[] sqlParams)
18bubuko.com,布布扣{
19bubuko.com,布布扣    if (cmdText == null)
20bubuko.com,布布扣        return null;
21bubuko.com,布布扣
22bubuko.com,布布扣    SqlDataAdapter adapter = new SqlDataAdapter(this.PrepareCommand(cmdText,sqlParams));
23bubuko.com,布布扣    DataTable table = new DataTable();
24bubuko.com,布布扣    try
25bubuko.com,布布扣    {
26bubuko.com,布布扣        adapter.Fill(table);
27bubuko.com,布布扣    }
28bubuko.com,布布扣    catch (SqlException e)
29bubuko.com,布布扣    {
30bubuko.com,布布扣        throw e;
31bubuko.com,布布扣    }
32bubuko.com,布布扣    finally
33bubuko.com,布布扣    {
34bubuko.com,布布扣        if (connection.State != ConnectionState.Open)
35bubuko.com,布布扣            connection.Close();
36bubuko.com,布布扣    }
37bubuko.com,布布扣
38bubuko.com,布布扣    return table;
39bubuko.com,布布扣}

  上面重构的是ExecuteQuery方法的定义部分,这其实只是重构的开始,因为现有代码中充满了类似代码段2那样的方法调用,都需要改成如下的形式:

1bubuko.com,布布扣//代码段4
2bubuko.com,布布扣string cmd = "select * from MaterialClass where MaterialClassCode = @MaterialClassCode and CompanyName = @CompanyName";
3bubuko.com,布布扣SqlParameter[] SqlParams = 
4bubuko.com,布布扣
5bubuko.com,布布扣    new SqlParameter("@MaterialClassCode",MaterialClassCode ),
6bubuko.com,布布扣    new SqlParameter("@CompanyName",CompanyName )
7bubuko.com,布布扣}
8bubuko.com,布布扣DataTable table = new BitAECSqlExe().ExecuteQuery(cmd);

   比照一下上面贴出的代码段2和代码段4,它们之间的差异就是我很希望自己能通过正则表达式跨越的鸿沟(一个一个手工去改的话实在太累了,一百多处啊,呵呵)。需要注意的是,查询语句中可能出现的参数个数是不定的,每个文件中可能包含的方法调用的数量也是不定的。本想写一个C#的console小程序来完成这个批量操作,但又总觉得杀鸡用牛刀,后来写了一个简单的perl脚本,利用perl强大的文本处理能力,很容易就实现了这个功能。脚本代码如下:

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

 

对数据访问层的重构(及重构中Perl的应用)

标签:blog   http   io   os   使用   ar   for   文件   数据   

原文地址:http://www.cnblogs.com/yihaha/p/3977547.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!