一、系统概述
读取数据库表结构是数据库管理、代码生成(如ORM模型)、数据迁移等场景的基础需求。本工具基于 C# 语言和 ADO.NET 框架,支持多数据库兼容(SQL Server、MySQL、PostgreSQL),通过查询数据库系统元数据(如INFORMATION_SCHEMA)获取表的列信息(名称、数据类型、约束)、主键/外键、索引等结构,输出为结构化数据(如DataTable、JSON)或可视化报告。工具具备低侵入性(无需数据库驱动额外配置)、高扩展性(支持自定义查询)特点,适用于开发调试、数据库文档生成等场景。
二、核心设计思路
2.1 元数据来源
不同数据库通过系统表/视图暴露元数据,核心查询对象包括:
- 列信息 :
INFORMATION_SCHEMA.COLUMNS(通用)、sys.columns(SQL Server)、information_schema.columns(MySQL/PostgreSQL) - 主键信息 :
INFORMATION_SCHEMA.KEY_COLUMN_USAGE(通用)、sys.key_constraints(SQL Server) - 外键信息 :
INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS(通用) - 索引信息 :
sys.indexes(SQL Server)、pg_indexes(PostgreSQL)
2.2 多数据库兼容策略
通过抽象工厂模式封装不同数据库的查询逻辑,核心步骤:
- 根据数据库类型(如
SQLServer、MySQL)选择对应的连接字符串 和查询模板; - 使用
DbProviderFactory创建通用数据库对象(DbConnection、DbCommand); - 执行参数化查询,避免SQL注入。
三、实现步骤与代码
3.1 开发环境
- 语言:C# 9.0+
- 框架:.NET 6.0(跨平台)
- 依赖 :
System.Data.Common(通用ADO.NET)、数据库驱动(如Microsoft.Data.SqlClient、MySqlConnector)
3.2 核心类设计
3.2.1 数据库类型枚举
csharp
public enum DatabaseType
{
SqlServer, // SQL Server
MySQL, // MySQL
PostgreSQL, // PostgreSQL
Oracle // Oracle(预留)
}
3.2.2 表结构信息模型
csharp
// 列信息
public class ColumnInfo
{
public string TableName { get; set; } // 表名
public string ColumnName { get; set; } // 列名
public string DataType { get; set; } // 数据类型(如int、nvarchar(50))
public int MaxLength { get; set; } // 最大长度
public bool IsNullable { get; set; } // 是否允许NULL
public string DefaultValue { get; set; } // 默认值
public int OrdinalPosition { get; set; } // 列顺序
}
// 主键信息
public class PrimaryKeyInfo
{
public string TableName { get; set; }
public string ColumnName { get; set; }
public int KeyOrder { get; set; } // 主键顺序(复合主键)
}
// 表结构汇总
public class TableSchema
{
public string TableName { get; set; }
public List<ColumnInfo> Columns { get; set; } = new();
public List<PrimaryKeyInfo> PrimaryKeys { get; set; } = new();
}
3.3 核心功能实现
3.3.1 数据库连接与查询(通用方法)
csharp
using System.Data.Common;
using Microsoft.Data.SqlClient; // SQL Server驱动
using MySqlConnector; // MySQL驱动
public class DbSchemaReader
{
private readonly string _connectionString;
private readonly DatabaseType _dbType;
public DbSchemaReader(string connectionString, DatabaseType dbType)
{
_connectionString = connectionString;
_dbType = dbType;
}
// 创建数据库连接
private DbConnection CreateConnection()
{
return _dbType switch
{
DatabaseType.SqlServer => new SqlConnection(_connectionString),
DatabaseType.MySQL => new MySqlConnection(_connectionString),
_ => throw new NotSupportedException($"不支持的数据库类型: {_dbType}")
};
}
// 执行查询并返回DataTable
public DataTable ExecuteQuery(string sql)
{
using var conn = CreateConnection();
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
using var adapter = GetDataAdapter(cmd);
var dt = new DataTable();
adapter.Fill(dt);
return dt;
}
// 获取数据库适配器(适配不同数据库)
private DbDataAdapter GetDataAdapter(DbCommand cmd)
{
return _dbType switch
{
DatabaseType.SqlServer => new SqlDataAdapter((SqlCommand)cmd),
DatabaseType.MySQL => new MySqlDataAdapter((MySqlCommand)cmd),
_ => throw new NotSupportedException()
};
}
}
3.3.2 读取表列信息(以SQL Server为例)
csharp
// 获取指定表的所有列信息
public List<ColumnInfo> GetColumns(string tableName)
{
string sql = @"
SELECT
c.TABLE_NAME AS TableName,
c.COLUMN_NAME AS ColumnName,
c.DATA_TYPE AS DataType,
c.CHARACTER_MAXIMUM_LENGTH AS MaxLength,
CASE WHEN c.IS_NULLABLE = 'YES' THEN 1 ELSE 0 END AS IsNullable,
c.COLUMN_DEFAULT AS DefaultValue,
c.ORDINAL_POSITION AS OrdinalPosition
FROM INFORMATION_SCHEMA.COLUMNS c
WHERE c.TABLE_NAME = @TableName
ORDER BY c.ORDINAL_POSITION";
using var conn = CreateConnection();
conn.Open();
using var cmd = conn.CreateCommand();
cmd.CommandText = sql;
cmd.Parameters.Add(new SqlParameter("@TableName", tableName));
using var reader = cmd.ExecuteReader();
var columns = new List<ColumnInfo>();
while (reader.Read())
{
columns.Add(new ColumnInfo
{
TableName = reader["TableName"].ToString(),
ColumnName = reader["ColumnName"].ToString(),
DataType = reader["DataType"].ToString(),
MaxLength = reader["MaxLength"] == DBNull.Value ? 0 : Convert.ToInt32(reader["MaxLength"]),
IsNullable = Convert.ToBoolean(reader["IsNullable"]),
DefaultValue = reader["DefaultValue"]?.ToString(),
OrdinalPosition = Convert.ToInt32(reader["OrdinalPosition"])
});
}
return columns;
}
3.3.3 读取主键信息(通用方法)
csharp
// 获取指定表的主键列
public List<PrimaryKeyInfo> GetPrimaryKeys(string tableName)
{
string sql = @"
SELECT
kcu.TABLE_NAME AS TableName,
kcu.COLUMN_NAME AS ColumnName,
kcu.ORDINAL_POSITION AS KeyOrder
FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS tc
ON kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
WHERE tc.TABLE_NAME = @TableName
AND tc.CONSTRAINT_TYPE = 'PRIMARY KEY'
ORDER BY kcu.ORDINAL_POSITION";
// 执行查询(类似GetColumns方法,略)
// ...
}
3.3.4 整合表结构(完整示例)
csharp
// 获取指定表的所有结构信息
public TableSchema GetTableSchema(string tableName)
{
var schema = new TableSchema { TableName = tableName };
schema.Columns = GetColumns(tableName);
schema.PrimaryKeys = GetPrimaryKeys(tableName);
return schema;
}
参考代码 C#-读取数据库表结构 www.youwenfan.com/contentcss/123124.html
四、关键技术点
4.1 多数据库适配
- 连接字符串差异 :
- SQL Server:
"Server=.;Database=TestDB;User Id=sa;Password=123456;" - MySQL:
"Server=localhost;Database=TestDB;Uid=root;Pwd=123456;"
- SQL Server:
- 查询语法差异:部分数据库(如Oracle)的系统表名称不同,需调整SQL模板。
4.2 性能优化
- 批量查询 :通过
INFORMATION_SCHEMA一次性获取所有表结构,避免多次查询; - 缓存机制 :对频繁访问的表结构缓存结果(如用
MemoryCache)。
4.3 异常处理
- 连接失败 :捕获
DbException,提示"数据库连接失败,请检查连接字符串"; - 表不存在 :查询前先判断表是否存在(如
SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = @TableName)。
五、扩展功能
5.1 可视化报告(JSON/HTML)
将TableSchema对象序列化为JSON或HTML,示例:
csharp
// 序列化为JSON
var json = JsonSerializer.Serialize(schema, new JsonSerializerOptions { WriteIndented = true });
// 生成HTML表格
string html = $"<h1>{schema.TableName} 结构</h1><table border='1'>...";
5.2 代码生成(ORM模型)
根据表结构自动生成C#实体类:
csharp
// 生成实体类代码
string GenerateEntityClass(TableSchema schema)
{
var sb = new StringBuilder();
sb.AppendLine($"public class {schema.TableName}");
sb.AppendLine("{");
foreach (var col in schema.Columns)
{
string type = MapDbTypeToCSharp(col.DataType);
sb.AppendLine($" public {type} {col.ColumnName} {{ get; set; }}");
}
sb.AppendLine("}");
return sb.ToString();
}
// 数据库类型映射C#类型
private string MapDbTypeToCSharp(string dbType)
{
return dbType.ToLower() switch
{
"int" => "int",
"nvarchar" => "string",
"datetime" => "DateTime",
_ => "object"
};
}
六、总结
本工具通过ADO.NET和系统元数据查询实现了数据库表结构的读取,支持多数据库兼容和结构化输出。核心优势在于低侵入性(无需数据库特定API)和高扩展性(可添加索引、外键等查询)。代码模块化设计,便于集成至开发工具(如数据库文档生成器)或业务系统。