按Sybase的PowerDesigner工具设计的数据库模型 ---> 解析生成能兼容多种数据库的相应的C#底层代码
2010-06-20 23:20 通用C#系统架构 阅读(2712) 评论(2) 编辑 收藏 举报先有设计,后有代码,改设计总比改代码更容易一些,改设计的成本更低廉,软件也要按图纸施工,没有图纸的建筑物,将来也不好维护,没有数据库设计的软件更怎么可能好维护呢?
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,索取相应的程序源码、设计文档等等。
一步步教你如何用疯狂.NET架构中的通用权限系统 -- 如何控制用户显示的菜单权限
一步步教你如何用疯狂.NET架构中的通用权限系统 -- 在页面中的调用权限讲解
一步步教你如何用疯狂.NET架构中的通用权限系统 -- 数据集权限的调用权限讲解
一步步教你如何用疯狂.NET架构中的通用权限系统 -- 分级管理
一步步教你如何用疯狂.NET架构中的通用权限系统 -- 分级授权
疯狂.NET 通用权限设计 C\S后台管理,B\S前台调用源码样例程序源码下载之 --- 操作权限
疯狂.NET 通用权限设计 C\S后台管理,B\S前台调用源码样例程序源码下载之 --- 角色权限
疯狂.NET 通用权限设计 C\S后台管理,B\S前台调用源码样例程序源码下载之 --- 数据集权限