信息化基础建设 改善代码生成

 

数据库字段映射

当看到一个实体的属性,是否可以马上判断出它对应的数据库字段?

_languageTranslation.KeyText, 比如看到这个KeyText的属性

通常的做法是,去查找实体与数据库字段绑定的代码,以检查这个属性关联的数据库字段,代码可能是这样

public LanguageTranslationEntity ReaderBind(IDataReader dataReader)

{

LanguageTranslationEntity model=new LanguageTranslationEntity ();

object ojb;

model. KeyText =dataReader[“KEY_TEXT"].ToString();

model.Description=dataReader["Description"].ToString();

}

看到KeyText属性对应的数据库字段是KEY_TEXT. 但是,你需要用F12,转到定义,来帮忙查看这个ReaderBind方法,如果加上了接口与实现,还需要额外的搜索才能确定字段来源。

改进的一种办法,是利用C#的Xml注释与智能感知,如下图

clip_image002

在生成的实体文件中,加上Xml注释,当鼠标指向一个属性时,可得到如下的效果

clip_image003

从这个图片中可以看出KeyText映射到表LanguageTransaction的KeyText字段,非常清晰。

适当的修改一下生成实体的代码生成器,给字段加上一段类似于下面的Xml注释,可增强代码的可读性。

<remarks>Mapped on table field: "LanguageTranslation"."KeyText"<br/>

这是我对代码生成器的第一个Enhancement。

 

一组实体文件

实体名是LanguageTranslationEntity,我们通常会生成一个对应的LanguageTranslationEntity.cs文件。

如果要给LanguageTranslationEntity.cs做一下修改,可能加入一些方法,F5,代码运行正常。

如果有一天需要给LanguageTranslationEntity实体对应的数据库表增加一个字段,比如修改进间RevisedDate,这时,需要重新打开代码生成器,再生成一次代码,糟糕,原来写的代码丢失了。因为我们的代码生成器,只是简单的把文件写入到磁盘上去,如果存在原文件,默认的办法是覆盖原来的文件。

这个问题有2个办法解决,改进代码生成器,或是改进生成的文件。

改进代码生成器,把我们写的代码,放到代码文件中指定的区域中,

比如,给生成的文件加上一些标签,在生成代码的时候,如果原来的文件是存在的,需要先提取这些标签中的字符串值,即程序员加入的自定义代码,然后把这些值插入到新生成的代码文件中,比如下面的标签例子

// CODE_REGION_START

自定义的代码逻辑放在这里

// CODE_REGION_END

第二种办法是,利用partial特性,生成2个文件,一个LanguageTranslationEntity.cs,另一个LanguageTranslationEntity.Logic.cs, 第二个文件,只生成一次,以后不重新生成,里面的内容全部放我们的自定义逻辑代码。

 

表名与属性命名

表名是Language,生成的实体名是LanguageEntity,在表名后面加Entity.

如果喜欢把表名写成tblLanguage, 生成实体为LanguageEntity时,需要去掉tbl前缀。

如果把表名写成LANGUAGE,要生成LanguageEntity,则需要转化一下大小写。把首字母大写,其余的小写。

如果表名是ProductionControl,要生成ProductionControlEntity, 也是直接加Entity

如果表名是DeptGroup,默认生成的实体为DeptGroupEntity, 为了可读性,可能需要转化一下,把Dept转成Department,生成的实体名为DepartmentGroupEntity.

如果表名是DeptGrp,生成的DeptGrpEntity可读性就越来越差了。

这时,转化Dept为Department,Grp为Group是必须的。

要改善复合单词的表名对应的实体名,需要建立一个缩写字典表,和一个前缀表,在生成表名对应的实体名时,做替换处理,以增强可读性。

这里还有一个问题,如何判断出DeptGroup是2个单词,一个简写和一个单词,

而DeptGrp是2个单词的缩写,如果缩写恰好又是一个正确英语单词呢?

还没有找到正确的区分单词的办法,折衷的方法是表名写成Dept_Grp,主动用下划线分开表名中的单词,在生成实体名时,只需要简单的Regex.Split就可以了。

字段的命名,以及生成的属性名称,也可参考表名的规则,是同样的原理。

 

接口与实现

表名是Language,生成实体LanguageEntity, 实体文件名也叫LanguageEntity.cs

如果同时加上接口与实现,如何命名文件名? 有以下几种方案参考

方案1 接口文件名 ILanguage.cs , 实现文件名LanguageImplementation.cs

方案2 接口文件名 ILanguageDAL.cs , 实现文件名LanguageDAL.cs

方案3 接口文件名 ILanguageService.cs , 实现文件名LanguageService.cs

方案4 接口文件名 ILanguageManager.cs , 实现文件名LanguageManager.cs

用CodeSmith写模板文件,要改换上面提到的几种写法,非常容易

如果需要为生成的接口支持WCF技术, 生成接口时,要主动接口添加ServiceContract特性,给方法添加OperationContract特性。如下面的例子
[ServiceContract]
public interface IWCFExample
{
    [OperationContract]
    IEntity2 GetCustomer(string customerID);
 
    [OperationContract]
    IEntityCollection2 GetCustomers();
}

如果生成的接口要支持Web Services, 如下面的例子所示,加上WebMethod标签。

[WebService]
public class CustomerService : System.Web.Services.WebService
{
        [WebMethod]
        public IEntity2 GetCustomer(string customerID)
        {
               ……….
        }
}

好了,这些独立的部分考虑到了,用CodeSmith做好各个模板,生成代码起来很轻松

clip_image004

但是,CodeSmith有个问题,就是一次只能生成一段代码,如果我需要为数据库Northwind中所有表(或是指定的表)生成接口和实现文件呢,dirty的办法可以多次的在CodeSmith的输入的表名,生成文件,一个表一个个的做代码生成,再加上同时生成Interface和Manager,10个表*2,工作量是20次,如果是100个表,工作量是100*2, 200次运动。

CodeSmith中有一个功能,就是可以直接调用它的API来运行代码生成,传入模板文件和必要的参数,调用代码就可以生成代码,而不必要运行CodeSmith软件本身。

顺着这个思路,我制作出如下的实用工具

clip_image006

这个工具的目的,就是克服CodeSmith一次不能批量工作的局限。如上图所示,打开一个服务器,选择数据库,左边自动列出它的表名,双击表名或是拖动表名到中间的Listbox中,这里面的表,是要进行代码生成的表,再看右边的选项区,Template列出了指定文件下的所有模板,也就是要进行代码生成的模板,Parameter区域列出选定模板的参数,我使用=号把值填写到后面,下面的TargetFolder是生成的文件放置的目录。

点击OK,一下次为这些表GBCURR Catalog DataSets Event History ModelDrill ModelPerspective Notifications

生成了所有的Template中列出的模板的文件。

表数量是8个,模板数据是7个,点击OK后,生成了7*8,56个文件,效率高。

事实上,在升级.Net Remoting为WCF时,我就是使用这个技巧,一下将所有的接口文件实现成WCF的标准接口。

 

Text to String

在做报表或是数据库操作时,通常需要在查询分析器中写好SQL,如下

SELECT

ItemID, Path, Name, ParentID, Type,

Content,

Intermediate, SnapshotDataID, LinkSourceID,

FROM dbo.Catalog

然后运用SQL拼接技术,写成下面的格式

string sql=" SELECT ItemID, Path, Name, ParentID, Type,"+

" Content, Intermediate, SnapshotDataID, LinkSourceID, "+

" FROM dbo.Catalog";

这个转换的步骤,容易出错,也枯燥。如果有大量的SQL要转化成C#,工作量会相当大。

由于掌握了代码生成技术 ,来看一下这个小程序

clip_image008

把SQL拷贝到上面的窗格中,选择要生成的代码方法(C#或是VB),点Generate Code,

下面的窗格就写好我们需要的代码。

这个小技巧可以省很多拼凑SQL的时间,而你需要付出的,就是写一个不到10行的C#程序。

不可否认,SQL拼凑,在制作复杂的报表中还是相当有用的,复杂的报表要从大量的表中取数,运算,然后生成新的数据集,传送到报表中。用SQL拼凑做数据访问层,显然不是明智的决定,我以为。

posted @ 2011-06-10 09:12  信息化建设  阅读(1846)  评论(6编辑  收藏  举报