使用C#和Npgsql加载含EARTH字段的PostgreSQL表至Dataset报错求助
这个错误是因为Npgsql默认没有为PostgreSQL的earth类型(来自earthdistance扩展)提供内置的二进制序列化器,当NpgsqlDataAdapter尝试用二进制模式读取该类型数据时就会抛出42883错误。下面提供几种可行的解决方案:
方案1:临时绕过——查询时转换为文本类型
最简单的快速解决方法是在SQL查询中将earth类型转换为Npgsql能识别的文本格式,使用earth类型自带的earth_to_text函数:
SELECT *, earth_to_text(your_earth_column) AS your_earth_column_text FROM postretable;
之后在C#代码中读取your_earth_column_text字段的字符串值,再自行解析成需要的坐标格式(比如经纬度)。
方案2:注册自定义类型映射(推荐)
通过Npgsql的类型映射系统,让它能正确序列化/反序列化earth类型。首先确保你已经安装了earthdistance扩展(如果没装的话执行CREATE EXTENSION IF NOT EXISTS earthdistance;)。
步骤1:定义.NET对应类型
创建一个对应earth类型的.NET类,用来存储经纬度信息:
public class EarthCoordinate { public double Latitude { get; set; } public double Longitude { get; set; } // 从earth类型的文本表示解析 public static EarthCoordinate FromEarthText(string earthText) { var trimmed = earthText.Trim('(', ')'); var parts = trimmed.Split(',', StringSplitOptions.TrimEntries); return new EarthCoordinate { Latitude = double.Parse(parts[0]), Longitude = double.Parse(parts[1]) }; } // 转换为earth类型的文本格式 public override string ToString() { return $"({Latitude}, {Longitude})"; } }
步骤2:注册类型映射
在应用初始化的地方(比如Program.cs或者数据库连接初始化代码中),注册earth类型与自定义.NET类的映射:
// 注册earth类型映射 NpgsqlConnection.GlobalTypeMapper.MapComposite<EarthCoordinate>("earth", new[] { new NpgsqlCompositeMember("lat", typeof(double)), new NpgsqlCompositeMember("lon", typeof(double)) });
这样Npgsql就能自动将数据库中的earth类型数据转换为EarthCoordinate对象,反之亦然。之后你原来的DataAdapter.Fill代码就能正常工作了。
关于“提供二进制输出函数”的说明
虽然可以在PostgreSQL中为earth类型编写自定义的二进制输出函数,但这需要使用C语言编写扩展,过程比较复杂且维护成本高,远不如客户端类型映射来得灵活。除非你有特殊的性能需求,否则不推荐这种方式。
内容的提问来源于stack exchange,提问作者Peter Simpson

