先有设计,后有代码,改设计总比改代码更容易一些,改设计的成本更低廉,软件也要按图纸施工,没有图纸的建筑物,将来也不好维护,没有数据库设计的软件更怎么可能好维护呢?
1:总希望自己的程序能兼容多种数据库,那就尽量用多种数据库都兼容的数据库字段类型来设计表结构。
2:将数据库中的表结构能对应到C#的类型里,然后能读取相应的实体字段、按实体的属性写入数据库表中。
3:为了测试大容量并发插入表的测试,设计了2个表结构,其中一个用GUID做主键,生成唯一主键,另一个用自增量或者序列做主键。
4:代码生成器里,设置了数据库类型与C#的数据类型的对应关系设置及默认值的关系设置等。
/// 数据库类型映射关系(数据库类型、C#类型、默认值、读取函数)
/// </summary>
string [,] DataTypeMapping = {
{ " NVARCHAR " , " String " , " null " , " ToString " },
{ " CHAR " , " String " , " null " , " ToString " },
{ " INT " , " int " , " 0 " , " ToInt " },
{ " INTEGER " , " int " , " 0 " , " ToInt " },
{ " NUMERIC " , " Double " , " 0 " , " ToDouble " },
{ " FLOAT " , " Double " , " 0 " , " ToDouble " },
{ " DATE " , " DateTime? " , " null " , " ToDateTime " },
{ " BLOB " , " Byte[] " , " null " , " ToByte " },
{ " BFILE " , " Byte[] " , " null " , " ToByte " },
{ " IMAGE " , " Byte[] " , " null " , " ToByte " }
};
/// <summary>
/// 获取字段的类型
/// </summary>
/// <param name="fieldDataType"> 数据库字段类型 </param>
/// <returns> 类型 </returns>
private string GetDataType( string fieldDataType, ref string defaultValue)
{
// 这是默认值
string returnValue = typeof ( string ).Name.ToString();
defaultValue = " null " ;
// 这个是差找对比
for ( int i = 0 ; i < DataTypeMapping.GetLength( 0 ); i ++ )
{
if (fieldDataType.IndexOf(DataTypeMapping[i, 0 ]) >= 0 )
{
returnValue = DataTypeMapping[i, 1 ];
defaultValue = DataTypeMapping[i, 2 ];
// 不循环了,提高效率
break ;
}
}
return returnValue;
}
private string GetDataType( string fieldDataType)
{
// 这是默认值
string returnValue = typeof ( string ).Name.ToString();
// 这个是差找对比
for ( int i = 0 ; i < DataTypeMapping.GetLength( 0 ); i ++ )
{
if (fieldDataType.IndexOf(DataTypeMapping[i, 0 ]) >= 0 )
{
returnValue = DataTypeMapping[i, 1 ];
// 不循环了,提高效率
break ;
}
}
return returnValue;
}
private string GetColumnDataType(XmlNode xmlNode, string columnName)
{
string fieldDataType = string .Empty;
for ( int i = 0 ; i < xmlNode.ChildNodes.Count; i ++ )
{
if (((XmlNode)xmlNode.ChildNodes[i]).LocalName.Equals( " Columns " ))
{
for ( int j = 0 ; j < xmlNode.ChildNodes[i].ChildNodes.Count; j ++ )
{
string field = xmlNode.ChildNodes[i].ChildNodes[j].ChildNodes[ 2 ].InnerText;
if (field.Equals(columnName))
{
for ( int z = 0 ; z < xmlNode.ChildNodes[i].ChildNodes[j].ChildNodes.Count; z ++ )
{
if (xmlNode.ChildNodes[i].ChildNodes[j].ChildNodes[z].LocalName.Equals( " DataType " ))
{
// 字段类型大写
fieldDataType = xmlNode.ChildNodes[i].ChildNodes[j].ChildNodes[z].InnerText.ToUpper();
break ;
}
}
break ;
}
}
break ;
}
}
return GetDataType(fieldDataType);
}
private string GetConvertFunction( string fieldDataType)
{
// 这是默认值
string returnValue = " ToString " ;
// 这个是差找对比
for ( int i = 0 ; i < DataTypeMapping.GetLength( 0 ); i ++ )
{
if (fieldDataType.IndexOf(DataTypeMapping[i, 0 ]) >= 0 )
{
returnValue = DataTypeMapping[i, 3 ];
// 不循环了,提高效率
break ;
}
}
return returnValue;
}
5:接下来需要用代码生成器生成相应的代码,这时候比较麻烦的事情有以下几个:
A:guid做主键时,为了兼容多种数据库,用了字符类型字段,用自增量时,主键为整数类型,这里需要有一定的技术水平需要处理一下。
B:用自增量做主键时,不同的数据库的处理方式不一样,这时候需要考虑写同一套代码,能兼容多种数据库的问题,程序的写法是一样同时能能支持多种数据库。
6:为了测试多种数据库上的兼容性,现在以 Oracle、SQLServer 为主要目标来进行测试,创建数据库的脚本如下:
UserByGUID.Oracle.SQL (Oracle按GUID为主键模式)
create table USERBYGUID
(
ID NVARCHAR2( 50 ),
FULLNAME NVARCHAR2( 50 ),
SALARY NUMBER( 10 , 2 ) default 0 ,
AGE NUMBER( 2 ) default 0 ,
BIRTHDAY DATE,
PHOTO BLOB,
ALLOWEDIT NUMBER( 1 ) default 1 ,
ALLOWDELETE NUMBER( 1 ) default 1 ,
ENABLED NUMBER( 1 ) default 1 ,
DELETEMARK NUMBER( 1 ) default 0 ,
DESCRIPTION NVARCHAR2( 200 ),
CREATEDATE DATE default sysdate,
CREATEUSERID NVARCHAR2( 50 ),
CREATEUSERREALNAME NVARCHAR2( 50 ),
MODIFYDATE DATE default sysdate,
MODIFYUSERID NVARCHAR2( 50 ),
MODIFYUSERREALNAME NVARCHAR2( 50 )
);
UserByInt.Oracle.SQL (Oracle按序列为主键模式)
create sequence SEQ_USERBYINT
minvalue 1
maxvalue 999999999999999999999999999
start with 21
increment by 1
cache 20 ;
-- Create table
create table USERBYINT
(
ID NUMBER,
FULLNAME NVARCHAR2( 50 ),
SALARY NUMBER( 10 , 2 ) default 0 ,
AGE NUMBER( 2 ) default 0 ,
BIRTHDAY DATE,
PHOTO BLOB,
ALLOWEDIT NUMBER( 1 ) default 1 ,
ALLOWDELETE NUMBER( 1 ) default 1 ,
ENABLED NUMBER( 1 ) default 1 ,
DELETEMARK NUMBER( 1 ) default 0 ,
DESCRIPTION NVARCHAR2( 200 ),
CREATEDATE DATE default sysdate,
CREATEUSERID NVARCHAR2( 50 ),
CREATEUSERREALNAME NVARCHAR2( 50 ),
MODIFYDATE DATE default sysdate,
MODIFYUSERID NVARCHAR2( 50 ),
MODIFYUSERREALNAME NVARCHAR2( 50 )
);
UserByGUID.SQLServer.SQL (SQLServer按GUID为主键模式)
[Id] [nvarchar]( 50 ) NOT NULL,
[FullName] [nvarchar]( 50 ) NULL,
[Salary] [numeric]( 10 , 2 ) NULL DEFAULT (( 0 )),
[Age] [ int ] NULL DEFAULT (( 0 )),
[Birthday] [smalldatetime] NULL DEFAULT (getdate()),
[Photo] [image] NULL,
[AllowEdit] [ int ] NULL DEFAULT (( 1 )),
[AllowDelete] [ int ] NULL DEFAULT (( 1 )),
[Enabled] [ int ] NULL DEFAULT (( 1 )),
[DeleteMark] [ int ] NULL DEFAULT (( 0 )),
[Description] [nvarchar]( 50 ) NULL,
[CreateDate] [smalldatetime] NULL DEFAULT (getdate()),
[CreateUserId] [nvarchar]( 50 ) NULL,
[CreateUserRealname] [nvarchar]( 50 ) NULL,
[ModifyDate] [smalldatetime] NULL DEFAULT (getdate()),
[ModifyUserId] [nvarchar]( 50 ) NULL,
[ModifyUserRealname] [nvarchar]( 50 ) NULL,
CONSTRAINT [PK_USERBYGUID] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
UserByInt.SQLServer.SQL (SQLServer自增量方式)
[Id] [ int ] IDENTITY( 1 , 1 ) NOT NULL,
[FullName] [nvarchar]( 50 ) NULL,
[Salary] [numeric]( 10 , 2 ) NULL DEFAULT (( 0 )),
[Age] [ int ] NULL DEFAULT (( 0 )),
[Birthday] [smalldatetime] NULL DEFAULT (getdate()),
[Photo] [image] NULL,
[AllowEdit] [ int ] NULL DEFAULT (( 1 )),
[AllowDelete] [ int ] NULL DEFAULT (( 1 )),
[Enabled] [ int ] NULL DEFAULT (( 1 )),
[DeleteMark] [ int ] NULL DEFAULT (( 0 )),
[Description] [nvarchar]( 50 ) NULL,
[CreateDate] [smalldatetime] NULL DEFAULT (getdate()),
[CreateUserId] [nvarchar]( 50 ) NULL,
[CreateUserRealname] [nvarchar]( 50 ) NULL,
[ModifyDate] [smalldatetime] NULL DEFAULT (getdate()),
[ModifyUserId] [nvarchar]( 50 ) NULL,
[ModifyUserRealname] [nvarchar]( 50 ) NULL,
CONSTRAINT [PK_USERBYINT] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
7:用代码生成器,生成相关的类代码:
8:代码复制到工程文件里的效果如下:
9:编写自动化测试程序如下
// All Rights Reserved , Copyright (C) 2010 , Jirisoft , Ltd.
// ------------------------------------------------------------
using System;
using System.IO;
namespace DotNet.Web.Permission
{
using DotNet.Utilities;
/// <remarks>
/// SQLServerExample
/// 多种数据库兼容的实现方法,只写一套程序在多种数据库上执行例子程序
///
/// 修改纪录
///
/// 版本:1.0 2010.06.20 JiRiGaLa 写好例子程序方便别人学习。
///
/// 版本:1.0
/// <author>
/// <name> JiRiGaLa </name>
/// <date> 2010.06.20 </date>
/// </author>
/// </remarks>
public partial class SQLServerExample : System.Web.UI.Page
{
protected void Page_Load( object sender, EventArgs e)
{
string id = string .Empty;
// 按GUID方式添加数据
id = this .AddEntityByGUID();
Page.Response.Write( " :GUID: " + id + " <br> " );
// 按自增量方式添加数据
id = this .AddEntityByIdentity();
Page.Response.Write( " :Identity: " + id + " <br> " );
}
/// <summary>
/// 读取图片文件
/// </summary>
/// <param name="fileName"> 文件名 </param>
/// <returns> 字节 </returns>
private byte [] GetFile( string fileName)
{
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read);
BinaryReader binaryReader = new BinaryReader(fileStream);
byte [] file = binaryReader.ReadBytes((( int )fileStream.Length));
binaryReader.Close();
fileStream.Close();
return file;
}
/// <summary>
/// 添加实体
/// </summary>
/// <returns> 主键 </returns>
private string AddEntityByGUID()
{
// 这个是管理器
UserByGUIDManager userByGUIDManager = new UserByGUIDManager();
// 不要自增量
// userByGUIDManager.Identity = false;
// 这个是实体
UserByGUIDEntity userByGUIDEntity = new UserByGUIDEntity();
userByGUIDEntity.Id = BaseBusinessLogic.NewGuid();
userByGUIDEntity.FullName = " 吉日嘎拉 " ;
userByGUIDEntity.Salary = 15000.00 ;
userByGUIDEntity.Age = 33 ;
userByGUIDEntity.AllowDelete = 1 ;
userByGUIDEntity.AllowEdit = 1 ;
userByGUIDEntity.Birthday = new DateTime( 1978 , 5 , 19 );
userByGUIDEntity.DeleteMark = 0 ;
userByGUIDEntity.Enabled = 1 ;
userByGUIDEntity.Photo = this .GetFile( @" C:\Users\jirigala\Pictures\01.jpg " );
// 这里是添加操作
return userByGUIDManager.Add(userByGUIDEntity);
}
/// <summary>
/// 添加实体
/// </summary>
/// <returns> 主键 </returns>
private string AddEntityByIdentity()
{
// 这个是管理器
UserByIntManager userByIntManager = new UserByIntManager();
// 是要自增量
// userByIntManager.Identity = true;
// 不用返回
// userByIntManager.ReturnId = false;
// 这个是实体
UserByIntEntity userByIntEntity = new UserByIntEntity();
userByIntEntity.FullName = " 吉日嘎拉 " ;
userByIntEntity.Salary = 15000.00 ;
userByIntEntity.Age = 33 ;
userByIntEntity.AllowDelete = 1 ;
userByIntEntity.AllowEdit = 1 ;
userByIntEntity.Birthday = new DateTime( 1978 , 5 , 19 );
userByIntEntity.DeleteMark = 0 ;
userByIntEntity.Enabled = 1 ;
userByIntEntity.Photo = this .GetFile( @" C:\Users\jirigala\Pictures\01.jpg " );
// 这里是添加操作
return userByIntManager.Add(userByIntEntity, true );
}
}
}
10:同样的程序,修改配置文件,连接到Oracle数据库上,GUID方式生成主键、徐列生成主键完全运行正常,惊喜一下。
< configuration >
< appSettings >
< add key = " RunMode " value = " Local " />
< add key = " ServiceFactory " value = " ServiceFactory " />
< add key = " ServicePath " value = " DotNet.Service " />
< add key = " DbHelperAssmely " value = " DotNet.DbUtilities " />
< add key = " DataBaseType " value = " Sqlserver " />
< add key = " DbHelperClass " value = " DotNet.DbUtilities.SqlHelper " />
< add key = " UserCenterConnection " value = " Server=JIRIGALA-PC;Database=UserCenterV30;Uid=sa;Pwd=sa; " />
<!--
< add key = " DataBaseType " value = " Oracle " />
< add key = " DbHelperClass " value = " DotNet.DbUtilities.OracleHelper " />
< add key = " UserCenterConnection " value = " Data Source = FDAZTC;user id = ztc;password = ztc " />
-->
< add key = " BusinessDBConnection " value = " Data Source=JIRIGALA-PC\SQLEXPRESS;Initial Catalog=ConvenienceServices;Integrated Security=SSPI; " />
< add key = " CustomerCompanyName " value = " 权限学习 " />
< add key = " SoftName " value = " Water " />
< add key = " SoftFullName " value = " 通用权限管理系统 " />
< add key = " CompanyFullName " value = " 杭州吉日软件 " />
< add key = " Update " value = " 2010.06.20 " />
< add key = " BugFeedback " value = " JiRiGaLa_Bao@hotmail.com " />
</ appSettings >
< connectionStrings >
< add name = " Sqlserver " connectionString = " Server=JIRIGALA-PC;Database=UserCenterV30;Uid=sa;Pwd=sa; " providerName = " DotNet.DbUtilities.SqlHelper " />
</ connectionStrings >
< system.web >
< compilation debug = " true " >
</ compilation >
< authentication mode = " Windows " />
< customErrors mode = " Off " />
</ system.web >
</ configuration >
11:PowerDesigner设计的PDM文件下载,请在此下载
/Files/jirigala/CodeBuilder.pdm.rar
12:完整的例子程序下载,请在此下载,若有缺少的DLL引用,可以在从目录DotNet.Web.Permission\Resource\External 里进行重新饮用
/Files/jirigala/DotNet.Web.Permission.rar
13:在淘宝网店地址 http://shop59297253.taobao.com/ 上购买相应的功能软件,此强大的代码生成器仅销售RMB:100元、服务后,请添加技术支持QQ:2520 – 56973,索取相应的程序源码、设计文档等等。
本文转自jirigala_bao 51CTO博客,原文链接:http://blog.51cto.com/jirigala/806795