使用PostgreSQLCopyHelper批量插入PostgreSQL时触发连接未打开错误
解决PostgreSQLCopyHelper批量插入时"Connection is not open"错误
错误原因
你的代码中创建了NpgsqlConnection实例,但没有调用Open()方法打开数据库连接,而PostgreSQLCopyHelper.SaveAll()方法要求连接处于已打开状态。
修复后的BulkInsert代码
public void BulkInsert(List<TType> list) { using (var connection = new NpgsqlConnection("Server=localhost;Database=demodb;Port=5432;User Id=postgres;Password=a`12345;")) { connection.Open(); // 关键:添加这行打开连接 var postgreSQLCopyHelper = CreateHelper<TType>(_schemaName, _tableName); postgreSQLCopyHelper.SaveAll(connection, list); } }
额外优化建议(针对CreateHelper方法)
原CreateHelper存在语法错误和性能优化空间,优化后的代码如下:
private static PostgreSQLCopyHelper<T> CreateHelper<T>(string schemaName, string tableName) { // 无需手动加引号,PostgreSQLCopyHelper会自动处理标识符转义 var helper = new PostgreSQLCopyHelper<T>(schemaName, tableName); var properties = typeof(T).GetProperties(); foreach (var prop in properties) { // 跳过主键属性 if (Attribute.IsDefined(prop, typeof(System.ComponentModel.DataAnnotations.KeyAttribute))) continue; var propType = prop.PropertyType; // 统一处理可空类型的底层类型 var underlyingType = Nullable.GetUnderlyingType(propType) ?? propType; // 编译表达式树提升反射性能,避免重复查找属性 var getValue = Expression.Lambda<Func<T, object>>( Expression.Convert(Expression.Property(Expression.Parameter(typeof(T)), prop), typeof(object)), Expression.Parameter(typeof(T))).Compile(); switch (underlyingType) { case Type t when t == typeof(int): helper = helper.MapInteger(prop.Name, x => (int?)getValue(x)); break; case Type t when t == typeof(string): helper = helper.MapText(prop.Name, x => (string)getValue(x)); break; case Type t when t == typeof(DateTime): helper = helper.MapTimeStamp(prop.Name, x => (DateTime?)getValue(x)); break; case Type t when t == typeof(decimal): helper = helper.MapMoney(prop.Name, x => (decimal?)getValue(x)); break; case Type t when t == typeof(double): helper = helper.MapDouble(prop.Name, x => (double?)getValue(x)); break; case Type t when t == typeof(float): helper = helper.MapReal(prop.Name, x => (float?)getValue(x)); break; case Type t when t == typeof(Guid): // 同时支持Guid和可空Guid类型 helper = helper.MapUUID(prop.Name, x => (Guid?)getValue(x) ?? Guid.Empty); break; } } return helper; }
优化说明:
- 移除手动添加的引号,由工具类自动处理PostgreSQL标识符转义逻辑
- 用表达式树编译属性访问器,避免重复反射查找属性,提升批量插入性能
- 统一处理可空与非可空类型,补充了可空Guid的支持
- 修复了原方法定义中的语法错误
内容的提问来源于stack exchange,提问作者yegane
相关产品推荐
相关产品推荐

