前言

最近公司需要将原来使用的MSSQL数据库整体迁移至pgsql,需要使用CodeSmith生成IBatisNet的配置文件。按照提示安装了Npgsql.dll后依然无法使用。引发了本次通过反编译修复相关的Bug。主要修复了一下错误:

1、未能加载文件或程序集“Npgsql, Version=2.2.0.0, Culture=neutral, PublicKeyToken=5d8b90d52f46fda7”

2、无法查看列信息

3、缺少表、列自描述

一、使用ILSpy反编译SchemaExplorer.PostgreSQLSchemaProvider.dll

打开ILSpy,将SchemaExplorer.PostgreSQLSchemaProvider.dll附加至ILSpy,如下图所示:

二、针对反编译的代码进行错误修复(详细修复过程略过)。

三、主要修复函数。

GetTables、GetTableColumns、GetTablePrimaryKey、GetTableKeys。因为我所使用的功能仅限于这几个函数所以只针对该相关的方法错误进行了修复。

1、修复表架构缺少描述的Bug

GetTables反编译的关键源码

public TableSchema[] GetTables(string connectionString, DatabaseSchema database)
{
List<TableSchema> list = new List<TableSchema>();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand("select tablename, tableowner from pg_catalog.pg_tables where schemaname = 'public' order by tablename", npgsqlConnection))
{
using (NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
while (npgsqlDataReader.Read())
{
if (npgsqlDataReader.GetString().ToUpper() != "CODESMITH_EXTENDED_PROPERTIES")
{
list.Add(new TableSchema(database, npgsqlDataReader.GetString(), npgsqlDataReader.GetString(), DateTime.MinValue));
}
}
if (!npgsqlDataReader.IsClosed)
{
npgsqlDataReader.Close();
}
}
}
if (npgsqlConnection.State != ConnectionState.Closed)
{
npgsqlConnection.Close();
}
}
return list.ToArray();
}

修复的源码

public TableSchema[] GetTables(string connectionString, DatabaseSchema database)
{
List<TableSchema> list = new List<TableSchema>();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand("select tablename, tableowner,obj_description(relfilenode,'pg_class') as pg_description from pg_catalog.pg_tables as t left join pg_catalog.pg_class as c on t.tablename = c.relname where t.schemaname = 'public' order by t.tablename", npgsqlConnection))
{
using (NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
while (npgsqlDataReader.Read())
{
if (npgsqlDataReader.GetString().ToUpper() != "CODESMITH_EXTENDED_PROPERTIES")
{
list.Add(new TableSchema(database, npgsqlDataReader.GetString(), npgsqlDataReader.GetString(), DateTime.MinValue,new ExtendedProperty[]{
new ExtendedProperty("CS_Description", npgsqlDataReader.GetString() ?? string.Empty, DbType.String, PropertyStateEnum.ReadOnly)
}));
}
}
}
}
}
return list.ToArray();
}

修改前的源码与修改后的源码主要有2个区别:增加了查询表描述的字段、添加扩展属性CS_Description这个属性是关键将可以通过TableSchema.Description读取表描述信息,这里存在一个问题,第二个参数不能为null,如果为null需要转换为空串。

2、修复读取列信息的bug

修改前的代码

public ColumnSchema[] GetTableColumns(string connectionString, TableSchema table)
{
List<ColumnSchema> list = new List<ColumnSchema>();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
string text = string.Format("select column_name, is_nullable, character_maximum_length, numeric_precision, numeric_scale, data_type, udt_name from information_schema.columns where table_schema = 'public' and table_name='{0}'", table.Name);
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand(text, npgsqlConnection))
{
using (NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
while (npgsqlDataReader.Read())
{
bool allowDBNull = npgsqlDataReader.IsDBNull() || npgsqlDataReader.GetString() == "YES";
byte precision = (byte)(npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32());
int size = npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32();
int scale = npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32();
string name = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
string text2 = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
string type = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
list.Add(new ColumnSchema(table, name, PostgreSQLSchemaProvider.GetDbType(type), text2, size, precision, scale, allowDBNull, new ExtendedProperty[]
{
new ExtendedProperty("NpgsqlDbType", PostgreSQLSchemaProvider.GetNativeDbType(text2), DbType.String)
}));
}
if (!npgsqlDataReader.IsClosed)
{
npgsqlDataReader.Close();
}
}
}
if (npgsqlConnection.State != ConnectionState.Closed)
{
npgsqlConnection.Close();
}
}
return list.ToArray();
}

修改后的代码

public ColumnSchema[] GetTableColumns(string connectionString, TableSchema table)
{
List<ColumnSchema> list = new List<ColumnSchema>();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
string text = string.Format("select column_name, is_nullable, character_maximum_length, numeric_precision, numeric_scale, data_type, udt_name,col_description(b.attrelid,b.attnum) as pg_description from information_schema.columns as a join pg_attribute as b on a.column_name=b.attname join pg_class as c on a.table_name=c.relname and b.attrelid = c.oid where b.attnum>0 and a.table_schema = 'public' and a.table_name='{0}'", table.Name);
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand(text, npgsqlConnection))
{
using (NpgsqlDataReader npgsqlDataReader = npgsqlCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
while (npgsqlDataReader.Read())
{
bool allowDBNull = npgsqlDataReader.IsDBNull() || npgsqlDataReader.GetString() == "YES";
byte precision = (byte)(npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32());
int size = npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32();
int scale = npgsqlDataReader.IsDBNull() ? : npgsqlDataReader.GetInt32();
string name = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
string text2 = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
string type = npgsqlDataReader.IsDBNull() ? string.Empty : npgsqlDataReader.GetString();
list.Add(new ColumnSchema(table, name, PostgreSQLSchemaProvider.GetDbType(type), text2, size, precision, scale, allowDBNull, new ExtendedProperty[]
{
new ExtendedProperty("NpgsqlDbType", PostgreSQLSchemaProvider.GetNativeDbType(text2), DbType.String),
new ExtendedProperty("CS_Description",npgsqlDataReader.GetString()?? string.Empty, DbType.String)
}));
}
if (!npgsqlDataReader.IsClosed)
{
npgsqlDataReader.Close();
}
}
}
}
return list.ToArray();
}

修改前的源码与修改后的源码主要有2个区别:增加了查询表描述的字段、添加扩展属性CS_Description这个属性是关键将可以通过ColumnSchema.Description读取表描述信息,这里存在一个问题,第二个参数不能为null,如果为null需要转换为空串。

三、修复主键信息

因为在页面加载列时,同时会根据表属性去加载列的主键,外键属性。

        public TableKeySchema[] GetTableKeys(string connectionString, TableSchema table)
{
List<TableKeySchema> list = new List<TableKeySchema>();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
string text = string.Format("SELECT constraint_name as constrname FROM information_schema.table_constraints WHERE table_name = '{0}' AND constraint_type = 'FOREIGN KEY' AND constraint_schema='public'", table.Name);
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand(text, npgsqlConnection))
{
string text2 = string.Format("SELECT px.conname as constrname, att.attname as colname, fore.relname as reftabname, fatt.attname as refcolname, CASE px.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS on_update, CASE px.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS on_delete, CASE px.contype WHEN 'p' THEN true WHEN 'f' THEN false END as IsPrimaryKey from pg_constraint px left join pg_class home on (home.oid = px.conrelid) left join pg_class fore on (fore.oid = px.confrelid) left join pg_attribute att on (att.attrelid = px.conrelid AND att.attnum = ANY(px.conkey)) left join pg_attribute fatt on (fatt.attrelid = px.confrelid AND fatt.attnum = ANY(px.confkey)) where (home.relname = '{0}') and px.contype = 'f' order by constrname", table.Name);
using (NpgsqlCommand npgsqlCommand2 = new NpgsqlCommand(text2, npgsqlConnection))
{
NpgsqlDataAdapter npgsqlDataAdapter = new NpgsqlDataAdapter(npgsqlCommand);
DataSet dataSet = new DataSet();
npgsqlDataAdapter.Fill(dataSet, "constraint");
npgsqlDataAdapter.SelectCommand = npgsqlCommand2;
npgsqlDataAdapter.Fill(dataSet, "keys");
if (dataSet.Tables[].Rows.Count > )
{
dataSet.Relations.Add("Contraint_to_Keys", dataSet.Tables[].Columns["constrname"], dataSet.Tables[].Columns["constrname"]);
foreach (DataRow dataRow in dataSet.Tables[].Rows)
{
string name = dataRow["constrname"].ToString();
DataRow[] childRows = dataRow.GetChildRows("Contraint_to_Keys");
string[] array = new string[childRows.Length];
string[] array2 = new string[childRows.Length];
string name2 = table.Name;
string primaryKeyTable = childRows[]["reftabname"].ToString();
for (int i = ; i < childRows.Length; i++)
{
array2[i] = childRows[i]["colname"].ToString();
array[i] = childRows[i]["refcolname"].ToString();
}
list.Add(new TableKeySchema(table.Database, name, array2, name2, array, primaryKeyTable));
}
}
}
}
string text3 = string.Format("SELECT px.conname as constrname FROM pg_constraint px left join pg_class fore on fore.oid = px.confrelid where fore.relname = '{0}'", table.Name);
using (NpgsqlCommand npgsqlCommand3 = new NpgsqlCommand(text3, npgsqlConnection))
{
string text4 = string.Format("SELECT px.conname as constrname, fatt.attname as colname, home.relname as reftabname, att.attname as refcolname, CASE px.confupdtype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS on_update, CASE px.confdeltype WHEN 'a' THEN 'NO ACTION' WHEN 'r' THEN 'RESTRICT' WHEN 'c' THEN 'CASCADE' WHEN 'n' THEN 'SET NULL' WHEN 'd' THEN 'SET DEFAULT' END AS on_delete, CASE px.contype WHEN 'p' THEN true WHEN 'f' THEN false END as IsPrimaryKey from pg_constraint px left join pg_class home on (home.oid = px.conrelid) left join pg_class fore on (fore.oid = px.confrelid) left join pg_attribute att on (att.attrelid = px.conrelid AND att.attnum = ANY(px.conkey)) left join pg_attribute fatt on (fatt.attrelid = px.confrelid AND fatt.attnum = ANY(px.confkey)) where (fore.relname = '{0}') order by constrname", table.Name);
using (NpgsqlCommand npgsqlCommand4 = new NpgsqlCommand(text4, npgsqlConnection))
{
NpgsqlDataAdapter npgsqlDataAdapter2 = new NpgsqlDataAdapter();
DataSet dataSet2 = new DataSet();
npgsqlDataAdapter2.SelectCommand = npgsqlCommand3;
npgsqlDataAdapter2.Fill(dataSet2, "constraint");
npgsqlDataAdapter2.SelectCommand = npgsqlCommand4;
npgsqlDataAdapter2.Fill(dataSet2, "keys");
if (dataSet2.Tables[].Rows.Count > )
{
dataSet2.Relations.Add("Contraint_to_Keys", dataSet2.Tables[].Columns["constrname"], dataSet2.Tables[].Columns["constrname"]);
foreach (DataRow dataRow2 in dataSet2.Tables[].Rows)
{
string name3 = dataRow2["constrname"].ToString();
DataRow[] childRows2 = dataRow2.GetChildRows("Contraint_to_Keys");
string[] array3 = new string[childRows2.Length];
string[] array4 = new string[childRows2.Length];
string foreignKeyTable = childRows2[]["reftabname"].ToString();
string name4 = table.Name;
for (int j = ; j < childRows2.Length; j++)
{
array4[j] = childRows2[j]["refcolname"].ToString();
array3[j] = childRows2[j]["colname"].ToString();
}
list.Add(new TableKeySchema(table.Database, name3, array4, foreignKeyTable, array3, name4));
}
}
}
}
}
return list.ToArray();
} public PrimaryKeySchema GetTablePrimaryKey(string connectionString, TableSchema table)
{
PrimaryKeySchema result = null;
DataSet ds = new DataSet();
using (NpgsqlConnection npgsqlConnection = new NpgsqlConnection(connectionString))
{
npgsqlConnection.Open();
string text = string.Format("select constraint_name from information_schema.table_constraints where constraint_schema='public' and table_name='{0}' and constraint_type='PRIMARY KEY'", table.Name);
using (NpgsqlCommand npgsqlCommand = new NpgsqlCommand(text, npgsqlConnection))
{
using (NpgsqlDataAdapter nda = new NpgsqlDataAdapter(npgsqlCommand))
{
nda.Fill(ds, "table_constraints");
} } string text2 = string.Format("select px.conname as ConstraintName, att.attname as ColumnName from pg_constraint px inner join pg_class home on (home.oid = px.conrelid) left join pg_attribute att on (att.attrelid = px.conrelid AND att.attnum = ANY(px.conkey)) where (home.relname = '{0}') and px.contype = 'p'", table.Name); using (NpgsqlCommand npgsqlCommand2 = new NpgsqlCommand(text2, npgsqlConnection))
{
using (NpgsqlDataAdapter nda = new NpgsqlDataAdapter(npgsqlCommand2))
{
nda.Fill(ds, "pg_constraint");
} }
foreach (DataRow item in ds.Tables["table_constraints"].Rows)
{
List<string> list = new List<string>();
foreach (DataRow item2 in ds.Tables["pg_constraint"].Rows)
{
list.Add(item2.Field<string>("ColumnName"));
}
result = new PrimaryKeySchema(table, item.Field<string>("constraint_name"), list.ToArray()); } }
return result;
}

将程序重新编译,替换原来的DLL。完成

四、补丁包及源码下载:

需要的朋友资助1分的CSDN资源分,辛苦劳动的奖励

CodeSmith7代码生成器针对PostgreSQL数据库无法使用的Bug修复全过程的更多相关文章

  1. Java代码生成器加入postgresql数据库、HikariCP连接池、swagger2支持!

    目录 前言 PostgreSql VS MySql HikariCP VS Druid Swagger2 自定义参数配置一览 结语 前言   最近几天又抽时间给代码生成器增加了几个新功能(预计今晚发布 ...

  2. postgresql数据库primary key约束/not null约束/unique约束及default值的添加与删除、列的新增/删除/重命名/数据类型的更改

    如果在建表时没有加primary key约束.not null约束.unique约束.default值,而是创建完表之后在某个字段添加的话 1.primary key约束的添加与删除 给red_pac ...

  3. TPC-H生成.tbl文件导入postgresql数据库的坑

    数据库project好好的不用主流的MySQL和Microsoft server而要求用听都没听过的postgresql (当然,可能你三个都没听过) 这里的坑主要是把生成的那八张.tbl的表导入pg ...

  4. ubuntu 下搭建一个python3的虚拟环境(用于django配合postgresql数据库开发)

     #安装python pip  (在物理环境中安装) sudo apt-get install python-pip       sudo apt-get install python3-pipsud ...

  5. 关于PDF.NET开发框架对Mysql Sqlite PostgreSQL数据库分页支持的个人看法

    关于PDF.NET开发框架的名字由来  在设计www.pwmis.com站点的时候,考虑到架构的兼容性和将来升级的可能性,最重要的是没有足够的时间去为网站添加和维护很多复杂的程序,所以在借鉴前人成功经 ...

  6. 从运维的角度分析使用阿里云数据库RDS的必要性--你不应该在阿里云上使用自建的MySQL/SQL Server/Oracle/PostgreSQL数据库

    开宗明义,你不应该在阿里云上使用自建的MySQL or SQL Server数据库,对了,还有Oracle or PostgreSQL数据库. 云数据库 RDS(Relational Database ...

  7. PostgreSQL数据库资料(转)

    PostgreSQL数据库资料 转自:http://blog.csdn.net/postgrechina/article/details/49132791 推荐书籍: 概念书籍: <Postgr ...

  8. 扩展我们的分析处理服务(Smartly.io):使用 Citus 对 PostgreSQL 数据库进行分片

    原文:Scaling Our Analytical Processing Service: Sharding a PostgreSQL Database with Citus 在线广告商正在根据绩效数 ...

  9. MySQL&SQL server&Oracle&Access&PostgreSQL数据库sql注入详解

    判断数据库的类型 当我们通过一些测试,发现存在SQL注入之后,首先要做的就是判断数据库的类型. 常用的数据库有MySQL.Access.SQLServer.Oracle.PostgreSQL.虽然绝大 ...

随机推荐

  1. 【jq】c#零基础学习之路(1)Hello World!

    从今天起我会持续发表,这个就是一个日记型的,学习编程是枯燥的,况且我们还是零基础. 学前准备 1.编译环境 vs2010.vs2012.vs2015...(本人用的是vs2010旗舰版).vs2010 ...

  2. 十分钟搞定微信企业帐号“echostr校验失败,请您检查是否正确解密并输出明文echostr”

    问题域:在这里我们只解决密文可以正确解密,但微信验证提示“echostr校验失败,请您检查是否正确解密并输出明文echostr”的问题. 干货:没有正确验证的原因是:你给微信返回的是字符串,而微信需要 ...

  3. 网易Ubuntu镜像使用帮助(ubuntu15.10 修改源)

    原文位置 以Wily(15.10)为例, 编辑/etc/apt/sources.list文件, 在文件最前面添加以下条目(操作前请做好相应备份) deb http://mirrors.163.com/ ...

  4. PHP常用的文件操作函数集锦

    以下是个人总结的PHP文件操作函数.当然,这只是部分,还有很多,我没有列出来. 一 .解析路径: 1 获得文件名:basename();给出一个包含有指向一个文件的全路径的字符串,本函数返回基本的文件 ...

  5. io.sort.spill.percent调整

    引言 MapReduce作出保证:进入每个Reducer的数据行都是有序的(根据数据行的键值进行排序).MapReduce将Mapper的输出进行排序并传递给Reducer作为输入的过程称为Shuff ...

  6. 听桶哥讲session和cookie

    首先,cookie和session是什么关系? 他们的关系很简单,利用和被利用的关系. 话说,由于http协议的无状态特性,同一client两个不同的请求之间完全独立,没有很好的办法进行一些数据共享, ...

  7. 视图(View) – ASP.NET MVC 4 系列

           精心编写的整洁代码是开发一个可维护 Web 应用程序的基础.但用户在浏览器中访问时,这些工作他们是看不见的.用户对应用程序的第一印象,以及与应用程序的整个交互过程都是从视图开始的.    ...

  8. CentOS源 Ubuntu 源 OpenSUSE-----持续汇总

    CentOS 基础(常用)的源:http://dl.fedoraproject.org/pub/epel/epel-release-latest-5.noarch.rpmhttp://dl.fedor ...

  9. GitLab常见使用方法

    1.GitLab配置 git config --global user.name "xxx" -- 配置用户名,上传本地 repository 到服务器上的时候,在 Github ...

  10. 《Javascript高级程序设计第3版》精华总结

    一.JavaScript简介   1.1 javascript简史 1.2 javascript实现 + javascript是一种专为网页交互而设计的一种脚本语言,javascript由三大部分组成 ...