按Sybase的PowerDesigner工具设计的数据库模型 ---> 解析生成能兼容多种数据库的相应的C#底层代码

简介:

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

 

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] [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自增量方式)

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

代码
<? 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文件下载,请在此下载

/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元、服务后,请添加技术支持QQ2520 – 56973,索取相应的程序源码、设计文档等等。

 


本文转自jirigala_bao 51CTO博客,原文链接:http://blog.51cto.com/jirigala/806795

相关文章
|
人工智能 数据挖掘 API
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
1208 21
基于neo4j数据库和dify大模型框架的rag模型搭建——后续补充
|
Java 数据库 Docker
基于neo4j数据库和dify大模型框架的rag模型搭建
基于neo4j数据库和dify大模型框架的rag模型搭建
4072 35
|
存储 缓存 自然语言处理
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
456 8
评论功能开发全解析:从数据库设计到多语言实现-优雅草卓伊凡
|
存储 关系型数据库 数据库
高性能云盘:一文解析RDS数据库存储架构升级
性能、成本、弹性,是客户实际使用数据库过程中关注的三个重要方面。RDS业界率先推出的高性能云盘(原通用云盘),是PaaS层和IaaS层的深度融合的技术最佳实践,通过使用不同的存储介质,为客户提供同时满足低成本、低延迟、高持久性的体验。
|
机器学习/深度学习 人工智能 JSON
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
Resume Matcher 是一款开源AI简历优化工具,通过解析简历和职位描述,提取关键词并计算文本相似性,帮助求职者优化简历内容,提升通过自动化筛选系统(ATS)的概率,增加面试机会。
1879 18
Resume Matcher:增加面试机会!开源AI简历优化工具,一键解析简历和职位描述并优化
|
存储 人工智能 API
离线VS强制登录?Apipost与Apifox的API工具理念差异深度解析
在代码开发中,工具是助手还是枷锁?本文通过对比Apipost和Apifox在断网环境下的表现,探讨API工具的选择对开发自由度的影响。Apifox强制登录限制了离线使用,而Apipost支持游客模式与本地存储,尊重开发者数据主权。文章从登录策略、离线能力、协作模式等方面深入分析,揭示工具背后的设计理念与行业趋势,帮助开发者明智选择,掌握数据控制权并提升工作效率。
1235 19
|
数据采集 存储 调度
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
在Python网页抓取领域,BeautifulSoup和Scrapy是两款备受推崇的工具。BeautifulSoup易于上手、灵活性高,适合初学者和简单任务;Scrapy则是一个高效的爬虫框架,内置请求调度、数据存储等功能,适合大规模数据抓取和复杂逻辑处理。两者结合使用可以发挥各自优势,例如用Scrapy进行请求调度,用BeautifulSoup解析HTML。示例代码展示了如何在Scrapy中设置代理IP、User-Agent和Cookies,并使用BeautifulSoup解析响应内容。选择工具应根据项目需求,简单任务选BeautifulSoup,复杂任务选Scrapy。
549 1
BeautifulSoup VS Scrapy:如何选择适合的HTML解析工具?
|
JSON 监控 物联网
WebSocket 调试全攻略:核心解析、工具选择与对比!
WebSocket 是一种全双工、实时交互的网络通信协议,适用于即时通信、实时数据流、多人协作、IoT 等场景。调试 WebSocket 时,工具应具备握手管理、实时消息收发、自定义 Header、消息大小告警、分组管理、多连接支持和断线重现等功能。主流调试工具如 Postman、ApiPost 和 ApiFox 各有优劣:Postman 界面友好适合基础调试;ApiPost 支持高级功能如消息分组和自动重连;ApiFox 则强化了多连接支持。选择工具时需根据具体需求和团队熟悉度决定。
|
数据可视化 测试技术 API
前后端分离开发:如何高效调试API?有工具 vs 无工具全解析
在前后端分离开发中,API调试至关重要。本文探讨有无调试工具时如何高效调试API,重点分析Postman、Swagger等工具优势及无工具代码调试方法。通过实际场景如用户登录接口,对比两者特性。同时介绍Apipost-Hepler(IDEA插件),将可视化与代码调试结合,提供全局请求头配置、历史记录保存等功能,优化团队协作与开发效率,助力API调试进入全新阶段。
|
数据可视化 测试技术 API
前后端分离开发:如何高效调试API?有工具 vs 无工具全解析
在前后端分离的开发模式中,API 调试的效率直接影响项目的质量和交付速度。通过本文的对比分析,我们可以看到无工具调试模式虽具备灵活性和代码复用能力,但在操作便利性和团队协作上稍显不足。而传统的外部调试工具带来了可视化、高效协作与扩展性,却可能存在工具切换带来的开发链路断层问题。Apipost-Hepler 融合了两者的优势,让开发者无需离开熟悉的 IDEA 环境,就能享受可视化调试工具的强大功能。
610 5

推荐镜像

更多
  • DNS