随笔20250721 PostgreSQL实体类生成器

我来帮你创建一个C#程序,从PostgreSQL数据库读取表结构并生成对应的实体类文件。我已经创建了一个完整的PostgreSQL实体类生成器。这个程序包含以下主要功能:

主要特性

  1. 数据库连接: 使用Npgsql连接PostgreSQL数据库
  2. 表结构读取: 自动读取所有表的结构信息
  3. 类型映射: 将PostgreSQL数据类型映射为C#数据类型
  4. 实体生成: 为每个表生成对应的C#实体类
  5. 文件导出: 将生成的类保存到指定文件夹

使用方法

  1. 安装NuGet包:

    Install-Package Npgsql
    
  2. 配置连接字符串: 修改Main方法中的连接字符串:

    var connectionString = "Host=localhost;Database=your_database;Username=your_username;Password=your_password;";
    
  3. 设置输出路径:

    var outputPath = @"C:\GeneratedEntities";
    
  4. 运行程序: 执行后会自动生成所有表的实体类

生成的实体类特点

  • 包含完整的Data Annotations特性
  • 主键字段标记为[Key]
  • 字段映射使用[Column]特性
  • 支持可空类型
  • 字符串长度限制
  • 帕斯卡命名法(下划线转换)

支持的数据类型

  • 整数类型:int, long, short
  • 浮点类型:float, double, decimal
  • 文本类型:string
  • 日期时间:DateTime, DateTimeOffset, TimeSpan
  • 其他:bool, Guid, byte[]

生成的实体类可以直接用于Entity Framework Core或其他ORM框架。

1.try cath 写在哪里? 写在 ViewModel层 Servace层最多使用自定义异常业务异常进行处理(传给ViewModel层处理), DAO层进行数据库操作流水账式,但是要做好资源释放操作
2.DbHelp 是什么模式?单例?释放需要手动释放?单例模式(和项目的整个声明周期一起,关了就完蛋了),不需要关闭(和项目的整个声明周期一起,关了就完蛋了),无法批量插入是因为 表结构还没完全构建完成,解决方法,先插入第一条来“预热”连接,如果还有后续的数据,就直接进行批量插入.public async Task InitTestOrdersAsync(){await _db.DeleteTableAsync<Orders>();await _db.CreateTableAsync<Orders>();var mockOrders = new List<Orders>();// ... (生成 mockOrders 的代码) ...if (mockOrders.Any()){// 1. 先插入第一条来“预热”连接await _db.InsertAsync(mockOrders.First());// 2. 再批量插入剩下的数据var remainingOrders = mockOrders.Skip(1).ToList();if(remainingOrders.Any()){await _db.InsertAllAsync(remainingOrders);}}}3.弄清 异步和非异步方法的区别,以及使用场景
只要底层(DAO 和 HttpClient)是异步的,Service 层 和 ViewModel 层也都必须是异步的!也就是说:要一路 async 到顶层。
| 层级                            | 是否 async | 原因                    |
| ----------------------------- | -------- | --------------------- |
| DAO(使用 SQLiteAsyncConnection) | ✅ 必须异步   | SQLite 是 IO,使用异步 API  |
| 调用 DAO 的 Service              | ✅ 必须异步   | 调用异步方法 → 必须用 `await`  |
| 调用 Service 的 ViewModel        | ✅ 必须异步   | 继续 `await` service 结果 || 情况               | 是否 async    |
| ---------------- | ----------- |
| 方法内部没有任何异步调用     | ❌ 不需要 async |
| 方法只是封装计算逻辑、纯内存操作 | ❌ 不需要 async |你用的是 SQLiteAsyncConnection + HttpClient 这样的异步库,整个调用链(DAO → Service → ViewModel)都必须使用 async/await 才是正确做法。🎯 为什么 .Result 或 .Wait() 会“把线程卡住”?
原因是:
.Result 和 .Wait() 是同步阻塞方法,会强制当前线程“原地等到任务完成”,不能做别的事,也不会释放线程。4.创建一个读取postSQL数据库的工具,生成实体类5432

PostgreSQLEntityGenerator.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Text;
using Npgsql;namespace ConsoleApp1
{public class EntityGenerator{private readonly string _connectionString;private readonly string _outputPath;public EntityGenerator(string connectionString, string outputPath){_connectionString = connectionString;_outputPath = outputPath;}public void GenerateEntities(){try{// 确保输出目录存在if (!Directory.Exists(_outputPath)){Directory.CreateDirectory(_outputPath);}using (var connection = new NpgsqlConnection(_connectionString)){connection.Open();// 获取所有表名var tables = GetTableNames(connection);foreach (var tableName in tables){Console.WriteLine($"正在生成实体类: {tableName}");GenerateEntityForTable(connection, tableName);}}Console.WriteLine($"实体类生成完成!输出路径: {_outputPath}");}catch (Exception ex){Console.WriteLine($"生成实体类时发生错误: {ex.Message}");throw;}}private List<string> GetTableNames(NpgsqlConnection connection){var tables = new List<string>();const string sql = @"SELECT table_name FROM information_schema.tables WHERE table_schema = 'public' AND table_type = 'BASE TABLE'ORDER BY table_name";using (var command = new NpgsqlCommand(sql, connection))using (var reader = command.ExecuteReader()){while (reader.Read()){tables.Add(reader.GetString("table_name"));}}return tables;}private void GenerateEntityForTable(NpgsqlConnection connection, string tableName){var columns = GetTableColumns(connection, tableName);var entityCode = GenerateEntityCode(tableName, columns);var fileName = $"{ToPascalCase(tableName)}.cs";var filePath = Path.Combine(_outputPath, fileName);File.WriteAllText(filePath, entityCode, Encoding.UTF8);}private List<ColumnInfo> GetTableColumns(NpgsqlConnection connection, string tableName){var columns = new List<ColumnInfo>();const string sql = @"SELECT c.column_name,c.data_type,c.is_nullable,c.column_default,c.character_maximum_length,c.numeric_precision,c.numeric_scale,CASE WHEN pk.column_name IS NOT NULL THEN true ELSE false END as is_primary_keyFROM information_schema.columns cLEFT JOIN (SELECT ku.column_nameFROM information_schema.table_constraints tcJOIN information_schema.key_column_usage kuON tc.constraint_name = ku.constraint_nameAND tc.table_schema = ku.table_schemaWHERE tc.constraint_type = 'PRIMARY KEY'AND tc.table_name = @tableNameAND tc.table_schema = 'public') pk ON c.column_name = pk.column_nameWHERE c.table_name = @tableNameAND c.table_schema = 'public'ORDER BY c.ordinal_position";using (var command = new NpgsqlCommand(sql, connection)){command.Parameters.AddWithValue("@tableName", tableName);using (var reader = command.ExecuteReader()){while (reader.Read()){columns.Add(new ColumnInfo{Name = reader.GetString("column_name"),DataType = reader.GetString("data_type"),IsNullable = reader.GetString("is_nullable") == "YES",DefaultValue = reader.IsDBNull("column_default") ? null : reader.GetString("column_default"),MaxLength = reader.IsDBNull("character_maximum_length") ? (int?)null : reader.GetInt32("character_maximum_length"),Precision = reader.IsDBNull("numeric_precision") ? (int?)null : reader.GetInt32("numeric_precision"),Scale = reader.IsDBNull("numeric_scale") ? (int?)null : reader.GetInt32("numeric_scale"),IsPrimaryKey = reader.GetBoolean("is_primary_key")});}}}return columns;}private string GenerateEntityCode(string tableName, List<ColumnInfo> columns){var sb = new StringBuilder();var className = ToPascalCase(tableName);// 添加using语句sb.AppendLine("using System;");sb.AppendLine("using System.ComponentModel.DataAnnotations;");sb.AppendLine("using System.ComponentModel.DataAnnotations.Schema;");sb.AppendLine();// 添加命名空间sb.AppendLine("namespace Entities");sb.AppendLine("{");// 添加Table特性sb.AppendLine($"    [Table(\"{tableName}\")]");sb.AppendLine($"    public class {className}");sb.AppendLine("    {");// 生成属性foreach (var column in columns){GenerateProperty(sb, column);}sb.AppendLine("    }");sb.AppendLine("}");return sb.ToString();}private void GenerateProperty(StringBuilder sb, ColumnInfo column){var propertyName = ToPascalCase(column.Name);var csharpType = GetCSharpType(column);// 添加注释sb.AppendLine();sb.AppendLine($"        /// <summary>");sb.AppendLine($"        /// {column.Name}");sb.AppendLine($"        /// </summary>");// 添加特性if (column.IsPrimaryKey){sb.AppendLine("        [Key]");}sb.AppendLine($"        [Column(\"{column.Name}\")]");if (!column.IsNullable && csharpType != "string"){sb.AppendLine("        [Required]");}if (column.MaxLength.HasValue && csharpType == "string"){sb.AppendLine($"        [MaxLength({column.MaxLength.Value})]");}// 生成属性sb.AppendLine($"        public {csharpType} {propertyName} {{ get; set; }}");}private string GetCSharpType(ColumnInfo column){var baseType = column.DataType.ToLower() switch{"integer" or "int4" => "int","bigint" or "int8" => "long","smallint" or "int2" => "short","boolean" or "bool" => "bool","real" or "float4" => "float","double precision" or "float8" => "double","numeric" or "decimal" => "decimal","text" or "varchar" or "character varying" or "char" or "character" => "string","timestamp" or "timestamp without time zone" => "DateTime","timestamp with time zone" or "timestamptz" => "DateTimeOffset","date" => "DateTime","time" or "time without time zone" => "TimeSpan","uuid" => "Guid","json" or "jsonb" => "string","bytea" => "byte[]",_ => "object"};// 如果字段可为空且不是引用类型,添加?if (column.IsNullable && baseType != "string" && baseType != "byte[]" && baseType != "object"){return baseType + "?";}return baseType;}private string ToPascalCase(string input){if (string.IsNullOrEmpty(input))return input;var parts = input.Split('_', '-');var sb = new StringBuilder();foreach (var part in parts){if (!string.IsNullOrEmpty(part)){sb.Append(char.ToUpper(part[0]));if (part.Length > 1)sb.Append(part[1..].ToLower());}}return sb.ToString();}}public class ColumnInfo{public string Name { get; set; }public string DataType { get; set; }public bool IsNullable { get; set; }public string DefaultValue { get; set; }public int? MaxLength { get; set; }public int? Precision { get; set; }public int? Scale { get; set; }public bool IsPrimaryKey { get; set; }}
}

Program.cs

using ConsoleApp1;try
{// 配置数据库连接字符串var connectionString = "Host=localhost;Database=postgres;Username=postgres;Password=123456;";// 配置输出路径var outputPath = @"C:\MySoft\PostgreSQL\Models";// 创建生成器实例var generator = new EntityGenerator(connectionString, outputPath);// 生成实体类generator.GenerateEntities();Console.WriteLine("按任意键退出...");Console.ReadKey();
}
catch (Exception ex)
{Console.WriteLine($"程序执行出错: {ex.Message}");Console.WriteLine("按任意键退出...");Console.ReadKey();
}
Console.WriteLine("Hello, World!");

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89997.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

B树、B-树与B+树

B树、B-tree与B树 在计算机科学&#xff0c;尤其是数据库和文件系统的领域中&#xff0c;B树、B-tree和B树是理解数据如何被高效存储和检索的关键。它们之间关系紧密&#xff0c;但功能和应用上又存在着决定性的差异。 一、 核心概念澄清&#xff1a;B树就是B-tree 首先需要明确…

视频格式转换工厂v3.2.5,集音视频、图片处理78MB

今天&#xff0c;我们要介绍的是一款功能强大的视频处理软件——视频格式转换工厂。这款软件已经完美破解&#xff0c;无需登录即可享受全部高级功能。它不仅支持视频格式转换&#xff0c;还涵盖了音频、图片处理等多种功能&#xff0c;是一款真正的多媒体处理工具。 视频格式转…

VUE 中父级组件使用JSON.stringify 序列化子组件传递循环引用错误

背景 VUE 中父级组件使用JSON.stringify 序列化子组件传递的数据会报错 runtime-core.esm-bundler.js:268 Uncaught TypeError: Converting circular structure to JSON –> starting at object with constructor ‘Object’ — property ‘config’ closes the circle 原因…

HTTP,HTTPS

在网络工程师、开发工程师、运维工程师等岗位的面试中&#xff0c;​​HTTP/HTTPS​​ 是高频必考知识点&#xff0c;尤其在前端、后端、测试、DevOps等与网络通信相关的职位中。以下是系统化的核心考点梳理&#xff0c;涵盖基础概念、协议机制、安全特性及应聘高频问题。​​一…

Nginx访问日志分析在云服务器环境的技术实现与案例

在云计算时代&#xff0c;Nginx访问日志分析已成为服务器运维的关键环节。本文将深入解析如何通过日志切割、实时监控和可视化展示三大技术路径&#xff0c;实现云环境下Nginx日志的高效分析。我们将结合具体案例&#xff0c;演示从原始日志到运维决策的完整技术闭环&#xff0…

鸿蒙实现一次上传多张图片

记录初接触鸿蒙&#xff0c;遇到的一个问题&#xff0c;需求是点击一个图片上传的号图&#xff0c;访问本地图片&#xff0c;可以选择多张图片并上传。下面是图片上传后的方法&#xff1a;//选择图片并上传private async showPhotoPicker() {const maxImageCount 3;const rema…

【STM32】CRC 校验函数

先上一下 CRC校验 的源代码&#xff1a; void crc_check(unsigned char *ptr,unsigned int len) //crc为开源函数 {unsigned long wcrc0XFFFF;//预置16位crc寄存器&#xff0c;初值全部为1unsigned char temp;//定义中间变量int i0,j0;//定义计数for(i0;i<len;i)//循环计算每…

【Java】SVN 版本控制软件的快速安装(可视化)

目录 一、SVN 的概述 1.1 SVN 的概念 1.2 SVN 与 Git 的对比 1.3 SVN 软件 二、SVN 的安装 2.1 SVN 的工作流程 2.2 服务器端 SVN 的安装 三、SVN 服务器端的配置 3.1 搭建项目 3.2 权限控制 四、SVN 客户端的配置 4.1 SVN 客户端的下载 4.2 客户端连接 SVN 服务器…

Hadoop安全机制深度剖析:Kerberos认证与HDFS ACL细粒度权限控制

Hadoop安全机制概述在大数据时代&#xff0c;Hadoop作为分布式计算框架的核心组件&#xff0c;其安全性直接关系到企业数据资产的保护。随着数据价值的不断提升&#xff0c;Hadoop安全机制已从早期的"简单信任模式"演进为包含多重防护措施的综合体系&#xff0c;其重…

uniapp基本使用

资料 咸虾米视频 黑马视频 uniapp官方文档 hbuilder 1.uniapp页面生命周期 1.1 onLoad 还拿不到dom适合接受上页的参数&#xff0c;联网取数据&#xff0c;更新data。相当于created和beforeCreated期间主要的作用是比如说获取url上的query参数 *url: ***/**?name张三&…

ssh2-sftp-client 简化 sftp 文件传输的 node库

ssh2-sftp-client 极大地简化了通过 sftp 进行文件传输的复杂性。无论你是需要上传、下载、删除文件&#xff0c;还是列出目录内容&#xff0c;可当简易的部署脚步npm run deploy const SftpClient require(ssh2-sftp-client) const sftp new SftpClient()const config {hos…

数字美元与全球支付革命:稳定币的兴起与全球金融格局的重塑

一、数字美元的崛起&#xff1a;美国战略布局与全球竞争1. 数字美元的定位与战略意义 数字美元作为美国构建“数字美元帝国”的核心工具&#xff0c;旨在通过区块链技术实现美元的数字化发行与流通&#xff0c;巩固其全球储备货币地位。其核心逻辑在于&#xff1a;技术赋能货币…

LeetCode 633.平方数之和

给定一个非负整数 c &#xff0c;你要判断是否存在两个整数 a 和 b&#xff0c;使得 a2 b2 c 。 示例 1&#xff1a; 输入&#xff1a;c 5 输出&#xff1a;true 解释&#xff1a;1 * 1 2 * 2 5 示例 2&#xff1a; 输入&#xff1a;c 3 输出&#xff1a;false 提示&…

Spring Boot 使用Jasypt加密

一、配置Jasypt 1.在pom.xml中导入依赖 <!-- Jasypt 加密工具 --><dependency><groupId>com.github.ulisesbocchio</groupId><artifactId>jasypt-spring-boot-starter</artifactId><version>3.0.5</version></dependency&…

【电影剖析】千钧一发

目录 1 人物介绍 2 电影名解读 3 电影开头 3.1 电影开头的两段话 3.2 片头设计 4 电影正文 4.1 “杰罗米”各种诡异的行为 4.2 文森特 – 失败的man 4.3 真正的杰罗米以及假基因身份证 4.4 文森特新征程 4.5 基因人的不容易 4.6 睫毛被查出有问题 4.7 文森特身份初…

论文略读:Arcee’s MergeKit: A Toolkit for Merging Large Language Models

emnlp 2024在过去的一年里&#xff0c;开源大型语言模型&#xff08;LLMs&#xff09;迅速发展&#xff0c;并已可通过 Hugging Face 模型库获取。这些模型的训练规模可达数万亿个 token&#xff0c;参数量通常在 1 亿至 700 亿以上不等开源模型检查点涵盖了多种任务&#xff0…

刀客doc:Netflix与YouTube开始在广告战场正面交锋

01广告一开始并不是Netflix的核心业务&#xff0c;但眼下&#xff0c;广告正逐步成为这家公司与YouTube正面对抗的关键战场。在上周刚发布的Q2财报里&#xff0c;Netflix广告层已覆盖全球12个核心市场&#xff0c;月活跃用户已经逼近9400万&#xff0c;主要集中在CTV渗透率高的…

(四)Unity3d-ROS联合仿真:turtlebot在Unity3d中仿真

运行环境Ubuntu20.04Unity3d 1.下载运行 &#xff08;1&#xff09;项目下载地址&#xff1a; Robotics-Nav2-SLAM-Example 最好执行下面命令能将子模块也下载 git clone --recurse-submodule gitgithub.com:Unity-Technologies/Robotics-Nav2-SLAM-Example.gitgit submodu…

信息学奥赛一本通 1553:【例 2】暗的连锁

【题目链接】 ybt 1553&#xff1a;【例 2】暗的连锁 【题目考点】 1. 树上差分&#xff1a;边差分 类似对差分序列进行修改可以完成对原序列的区间修改。对树上边差分进行修改可以完成对树上一条路径中所有边的边权进行修改。 一条边的差分值为该边的权值减去该边连接的深…

二分查找-852.山峰数组的峰顶索引-力扣(LeetCode)

一、题目解析1.山峰数组数据严格满足arr[0]<arr[1]……<arr[i]>arr[i1]……arr[arr.size()-1]2.时间复杂度要求为O(logN)二、算法解析解法1&#xff1a;暴力解法-O(N)遍历数组arr&#xff0c;结合山峰数组性质&#xff0c;我们发现峰顶存在arr[i]>arr[i-1]&#xf…