用T4模版生成POCO类代码,简单,但要求数据库定义一定要有规律,否则就没有实际意义了。这里,我们做如下规定:
1、数据库的表名,全部小写,各个单词之间以“_”(下划线)分割,且第一个单词为前缀。
2、表中各个字段,全部小写,各个单词之间以“_”(下划线)分割,表最好能够有create_time,create_by,update_time,update_time,version_no,is_valid。
生成的POCO规定:
1、类的名称,去掉前缀及分割符,各个单词的首字母大写,采用Pascial规范。
2、类中属性的名称,去掉分割符,首字符小写其余大写,采用Camel规范。
3、类中属性的数据类别,全部采用结构类型,且做以下转换
A、sbyte、bool、boolean、int、integer、Integer、Int16、short、Int32、Nullable<sbyte>、Nullable<bool>、Nullable<boolean>、Nullable<int>、Nullable<integer>、Nullable<Integer>、Nullable<Int16>、Nullable<short>、Nullable<Int32>,全部转换成Integer
B、long、Long、Nullable<long>、Nullable<Long>,全部转换成Long
C、float、Float、decimal、Decimal、Nullable<float>、Nullable<Float>、Nullable<decimal>、Nullable<Decimal>,全部转换成Double
D、string、String,全部转化成String
E、date、time、datetime、timestamp、Nullable<date>、Nullable<time>、Nullable<datetime>、Nullable<timestamp>,全部转换成String;其实,多平台开发时,这些字段根本不应该出现,直接用时间戳(当前百万秒-1970-1-1 00:00:00)
F、byte[]二进制数据,不变
备 注:
A、text,在EntityFramework(简称EF)中,已经转化成String,长度max(2GB);
B、binary、blob、mediumblob、tinyblob、varbinary,在EF中已经转换成byte[]
下面,我们开始用T4模版生成POCO类代码之旅
第一步,在“解决方案JavaGenerate”中添加类库,用于存放model的模版及相应文件,我们命名这个类库为JavaModels
点击“解决方案JavaGenerate”,右键,选择“添加 ”--〉“新建项目”,再选择"类库",名称中输入JavaModels。返回后,在“解决方案JavaGenerate”中增加了一个叫JavaModels的项目,且自带了一个class.cs的类,我们点击它,再点右键删除它,不用它。如图3-1,注意红色方框,特别是要选中.NET Framework4
图3-1
第二步,增加t4空模版
在解决方案管理器中,选择JavaModels项目,点击右键,选择“添加 ”--〉“新建项”,在弹出的窗体中做图3-2的选择和输入项。
图3-2
第三步,修改模版,我直接贴一个,然后慢慢解释
<#@ template language="C#" debug="false" hostspecific="true"#>
<#@ include file="EF.Utility.CS.ttinclude"#>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE"#>
<#@
output extension=".cs"#><#
CodeGenerationTools code = new CodeGenerationTools(this);
MetadataLoader loader = new MetadataLoader(this);
CodeRegion region = new CodeRegion(this, 1);
MetadataTools ef = new MetadataTools(this);
string inputFile = @"..\EDMX\dblxh.edmx";//EDMX项目中dblxh.edmx的路径,根据项目修改
MetadataWorkspace metadataWorkspace = null;
bool allMetadataLoaded =loader.TryLoadAllMetadata(inputFile, out metadataWorkspace);
EdmItemCollection ItemCollection = (EdmItemCollection)metadataWorkspace.GetItemCollection(DataSpace.CSpace);
EntityFrameworkTemplateFileManager fileManager = EntityFrameworkTemplateFileManager.Create(this);
// 发出文件
foreach (EntityType entity in ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name))
{
string filePascialName=getModelsPascialName(entity.Name);//Pascial风格的类名称
string fileCamelName=getModelsCamelName(entity.Name);//Camel风格的类名称
fileManager.StartNewFile(filePascialName+ ".java");//输出的类文件名称,及开始输出文件
#>
package com.jiahe.rest.demo2.models;
/*********************************************************************************
* Copyright (c) ZDSOFT LIMITED 2012 All Rights Reserved
* 系统名称:
* 程序模块文件名称:<#=filePascialName+ ".java"#>
* 摘要:
*********************************************************************************/
import java.io.Serializable;
/*********************************************************************************
*
* <pre>
* [版本说明]
* 1.0 2012/08/30 初版
* </pre>
* @version 1.0 2013/5/16
* @author lxh
*********************************************************************************/
public class <#=filePascialName#> implements Serializable {
private static final long serialVersionUID = 1L;
<#
//定义实体的私有属性
//循环实体的每一个属性
//getPropertyType,得到属性的数据类型
//getPropertyCamelName 得到属性的Camel风格的名称
foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity))
{
#>
private <#=getPropertyType(code.Escape(edmProperty.TypeUsage))#> <#=getPropertyCamelName(edmProperty.Name)#>;
<#}#>
<#
//定义实体私有属性的get/set
//循环实体的每一个属性
//getPropertyType,得到属性的数据类型
//getPropertyCamelName 得到属性的Camel风格的名称
//getPropertyPascialName 得到属性的Pascial风格的名称
foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity))
{#>
public void set<#=getPropertyPascialName(edmProperty.Name)#>(<#=getPropertyType(code.Escape(edmProperty.TypeUsage))#> <#=getPropertyCamelName(edmProperty.Name)#>)
{
this.<#=getPropertyCamelName(edmProperty.Name)#>=<#=getPropertyCamelName(edmProperty.Name)#>;
}
public <#=getPropertyType(code.Escape(edmProperty.TypeUsage))#> get<#=getPropertyPascialName(edmProperty.Name)#>()
{
return this.<#=getPropertyCamelName(edmProperty.Name)#>;
}
<#}#>
<#
//定义实体的toString
//循环实体的每一个属性
//getPropertyType,得到属性的数据类型
//getPropertyCamelName 得到属性的Camel风格的名称
//getPropertyPascialName 得到属性的Pascial风格的名称
string toStr=string.Empty;
foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity))
toStr+="+ \", "+getPropertyCamelName(edmProperty.Name)+"=\"+"+getPropertyCamelName(edmProperty.Name);
toStr=toStr.Substring(4);
#>
@Override
public String toString() {
return "<#=filePascialName#> [<#= toStr #> + "]";
}
<#
//定义默认构造函数
#>
public <#=filePascialName#>() {
super();
}
<#
//定义参数构造函数
toStr=string.Empty;
foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity))
toStr+=getPropertyType(code.Escape(edmProperty.TypeUsage))+" "+getPropertyCamelName(edmProperty.Name);
#>
public <#=filePascialName#>(<#=toStr#>)
{
super();
<#foreach (EdmProperty edmProperty in entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity)){#>
this.<#= getPropertyCamelName(edmProperty.Name)#>=<#=getPropertyCamelName(edmProperty.Name)#>;
<#}#>
}
<#
}
fileManager.Process();
#>
<#+
//得到类的Pascial风格名称
string getModelsPascialName(string source)
{
string[] s=source.Split('_');
for(int i=0;i<s.Length;i++)
{
string s1=s[i].Substring(0,1).ToUpper();
string s2=s[i].Substring(1);
s[i]=string.Concat(s1,s2);
}
string result=string.Empty;
for(int i=1;i<s.Length;i++)
{
result=string.Concat(result,s[i]);
}
return result;
}
#>
<#+
//得到类的Camel风格名称
string getModelsCamelName(string source)
{
string[] s=source.Split('_');
for(int i=0;i<s.Length;i++)
{
string s1=s[i].Substring(0,1).ToUpper();
string s2=s[i].Substring(1);
s[i]=string.Concat(s1,s2);
}
string result=string.Empty;
for(int i=1;i<s.Length;i++)
{
result=string.Concat(result,s[i]);
}
string s11=result.Substring(0,1).ToLower();
string s12=result.Substring(1);
return string.Concat(s11,s12);
}
#>
<#+
//得到属性的Pascial风格名称
string getPropertyPascialName(string source)
{
string[] s=source.Split('_');
for(int i=0;i<s.Length;i++)
{
string s1=s[i].Substring(0,1).ToUpper();
string s2=s[i].Substring(1);
s[i]=string.Concat(s1,s2);
}
return string.Concat(s);
}
//得到属性的Camel风格名称
string getPropertyCamelName(string source)
{
string[] s=source.Split('_');
for(int i=0;i<s.Length;i++)
{
string s1=s[i].Substring(0,1).ToUpper();
string s2=s[i].Substring(1);
s[i]=string.Concat(s1,s2);
}
string result=string.Concat(s);
string s11=result.Substring(0,1).ToLower();
string s12=result.Substring(1);
return string.Concat(s11,s12);
}
//数据类型转换
string getPropertyType(string source)
{
string result=string.Empty;
if (source=="int") result="Integer";
if (source=="integer") result="Integer";
if (source=="Integer") result="Integer";
if (source=="byte") result="Integer";
if (source=="sbyte") result="Integer";
if (source=="bool") result="Integer";
if (source=="Int16") result="Integer";
if (source=="short") result="Integer";
if (source=="Int32") result="Integer";
if (source=="Nullable<int>") result="Integer";
if (source=="Nullable<integer>") result="Integer";
if (source=="Nullable<Integer>") result="Integer";
if (source=="Nullable<byte>") result="Integer";
if (source=="Nullable<sbyte>") result="Integer";
if (source=="Nullable<bool>") result="Integer";
if (source=="Nullable<boolean>") result="Integer";
if (source=="Nullable<Int16>") result="Integer";
if (source=="Nullable<short>") result="Integer";
if (source=="Nullable<Int32>") result="Integer";
if (source=="Int64") result="Long";
if (source=="long") result="Long";
if (source=="Long") result="Long";
if (source=="Nullable<Int64>") result="Long";
if (source=="Nullable<long>") result="Long";
if (source=="Nullable<Long>") result="Long";
if (source=="float") result="Double";
if (source=="Float") result="Double";
if (source=="decimal") result="Double";
if (source=="Decimal") result="Double";
if (source=="Nullable<float>") result="Double";
if (source=="Nullable<Float>") result="Double";
if (source=="Nullable<decimal>") result="Double";
if (source=="Nullable<Decimal>") result="Double";
if (source=="byte[]") result="byte[]";
if (source=="string") result="String";
if (source=="String") result="String";
if (source=="System.Date") result="String";
if (source=="System.Time") result="String";
if (source=="System.DateTime") result="String";
if (source=="Nullable<System.Date>") result="String";
if (source=="Nullable<System.Time>") result="String";
if (source=="Nullable<System.DateTime>") result="String";
return result;
}
#>
把上面模版拷贝到JavaModels.tt中,保存,没有报错就会在“解决方案资源管理器”看到JavaModels.tt下生成了各个model;报错,那么就是EDMX项目添加的时候没有注意框架选择,把EDMX项目删除,按照图3-1的样式建立EDMX,再建立ADO.NET实体数据模型就可以。
模版说明:
一、标签符号说明
1、标签实际只有一种,以<#开始,以#>结束。然后进行扩展,在<#开始再添加运算符就实现了不同的扩展。
2、<#@.....#>,表示引用说明。基本是死的,不用记住,每次拷贝就行,其实望文就能生意。
3、<#=tttt#>,表示取ttt的值。ttt,可以是一个变量,也可以是一个方法。
4、<#+ ....#>,表示定义一个或一些方法。
注意:标签不支持嵌套。多读几个模版,你就明白了。
二、模版结构
1、模版基本由三个部分组成:引用部分,输入文件部分,公共方法部分。
2、引用部分,除ADO.NET实体数据模型文件string inputFile = @"..\EDMX\dblxh.edmx";需要修改外,其余基本不用修改。
3、输出文件部分,由于输出文件的不一致,基本都需要修改。
4、公共部分,需要多少就写,只要会java,c++的,都能够编写,它基本参照c++的语法。
三、模版语法
1、模版语法,是标准的C#语法,包括Linq的Lamada。lambda,java马上也支持,非常简单。
例如:
A、entity.Properties.Where(p => p.TypeUsage.EdmType is PrimitiveType && p.DeclaringType == entity)
表示对象entity集合查询出满足Properties.TypeUsage.EdmType is PrimitiveType且Properties.DeclaringType == entity的子集。
在EF模版中,这个表达式是查询出实体类的本来属性。
B、ItemCollection.GetItems<EntityType>().OrderBy(e => e.Name)
表示对集合按照name排序.在EF中,表示获得所有的实体类且按名称排序。
2、标签符号内的内容,不输出到文件,其余的按照顺序依次输出。把上面的javamodels.tt文件和输出的XXXX.java文件对比,就明白。