先有设计,后有代码,改设计总比改代码更容易一些,改设计的成本更低廉,软件也要按图纸施工,没有图纸的建筑物,将来也不好维护,没有数据库设计的软件更怎么可能好维护呢?

 

1:总希望自己的程序能兼容多种数据库,那就尽量用多种数据库都兼容的数据库字段类型来设计表结构。

 

2:将数据库中的表结构能对应到C#的类型里,然后能读取相应的实体字段、按实体的属性写入数据库表中。

 

3:为了测试大容量并发插入表的测试,设计了2个表结构,其中一个用GUID做主键,生成唯一主键,另一个用自增量或者序列做主键。

 

4:代码生成器里,设置了数据库类型与C#的数据类型的对应关系设置及默认值的关系设置等。

代码
        
///
 
<summary>
        
///
 数据库类型映射关系(数据库类型、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
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 
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为主键模式)

代码
CREATE TABLE [dbo].[UserByGUID](
    [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] [p_w_picpath] 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自增量方式)

代码
CREATE TABLE [dbo].[UserByInt](
    [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] [p_w_picpath] 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方式生成主键、徐列生成主键完全运行正常,惊喜一下。

代码
<?
xml version
=
"
1.0
"
?>
<
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文件下载,请在此下载

 

12:完整的例子程序下载,请在此下载,若有缺少的DLL引用,可以在从目录DotNet.Web.Permission\Resource\External 里进行重新饮用

 

13:在淘宝网店地址 上购买相应的功能软件,此强大的代码生成器仅销售RMB:100元、服务后,请添加技术支持QQ2520 – 56973,索取相应的程序源码、设计文档等等。

 

 

 

  

  

 

 

 

将权限管理、工作流管理做到我能力的极致,一个人只能做好那么很少的几件事情。

About

吉日嘎拉可爱的女儿

吉日嘎拉(蒙古语为吉祥如意),2000年毕业于黑龙江大学计算机系软件专业,目前定居杭州,典型的IT软件土鳖一个,外号“软件包工头”。

 

通用权限管理系统组件(GPM - General Permissions Manager)自2003年开始发布,目前是国内注册用户和免费盗版用户最多的权限管理系统,是各种信息管理系统开发中彻底的权限解决方案。本组件支持多种主流数据库(Oracle、sqlsever、db2、mysql),功能强大,使用方便,代码简洁,思路严谨,被广大支持者称为权限管理系统中的“走火入魔级权限管理系统”。

 

精心维护通用权限管理系统组件(GPM - General Permissions Manager)有8年多,3年的不断推广,20万行经典的业务逻辑积累,经过上万次的调试修正,经历了四百个付费客户,上百软件公司的实战开发。

11年以上开发经验,外企工作5年,上市公司3年,独立经营软件公司2年,主持研发部门管理工作4年以上。

将权限管理、工作流做到我能力的极致,一个人只能做好那么很少的几件事情。

吉日嘎拉,通用权限管理系统组件

QQ:252056973,Mail:jirigala_bao@hotmail.com

 访问者分布

通用权限管理模块的严谨设计定位、精心编码实现、不断维护推广、持续优化改进,主要是为了实现一个可以高度重复利用劳动成果的工具软件并×××给所需的人们,另想成为国人值得骄傲的知名软件功能模块。

可供国内管理类开发人员在日常工作中进行灵活二次开发利用的模块,开发管理类软件的必备工具之一,我们的目标就是让程序员早点儿回家休息。

淘宝店地址: