C# 读取数据库表结构工具设计与实现

一、系统概述

读取数据库表结构是数据库管理、代码生成(如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 多数据库兼容策略

通过抽象工厂模式封装不同数据库的查询逻辑,核心步骤:

  1. 根据数据库类型(如SQLServerMySQL)选择对应的连接字符串查询模板
  2. 使用DbProviderFactory创建通用数据库对象(DbConnectionDbCommand);
  3. 执行参数化查询,避免SQL注入。

三、实现步骤与代码

3.1 开发环境

  • 语言:C# 9.0+
  • 框架:.NET 6.0(跨平台)
  • 依赖System.Data.Common通用ADO.NET)、数据库驱动(如Microsoft.Data.SqlClientMySqlConnector

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;"
  • 查询语法差异:部分数据库(如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)和高扩展性(可添加索引、外键等查询)。代码模块化设计,便于集成至开发工具(如数据库文档生成器)或业务系统。

相关推荐
白露与泡影2 小时前
从 BIO 到 epoll:高并发 I/O 模型演进与本质分析
java·服务器·数据库
Jinuss2 小时前
源码分析之React中的useImperativeHandle
开发语言·前端·javascript
csdn2015_2 小时前
HashSet 和 LinkedHashSet 区别
java·开发语言
知识分享小能手2 小时前
MongoDB入门学习教程,从入门到精通,MongoDB副本集的核心机制(11)
数据库·学习·mongodb
一 乐2 小时前
剧场管理系统|基于springboot + vue剧场管理系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·剧场管理系统
CoderCodingNo2 小时前
【GESP】C++五级练习题 luogu-P1102 A-B 数对
开发语言·c++·算法
阿坤带你走近大数据2 小时前
Oracle里的MINUS是什么
数据库·oracle
Circ.2 小时前
文本相似性对比python代码
开发语言·python·相似度
佩亚诺余项.2 小时前
SQL Server 系统视图深度应用:批量检索含关键字的存储过程与数据表字段
数据库