升级Npgsql至3.2.7后,hstore列转XPO类属性遇IConvertible错误
解决Npgsql 3.2.7升级后XPO读取hstore列报"IConvertible"错误的问题
我之前处理过类似的Npgsql版本升级后和XPO适配的问题,你的情况核心原因是Npgsql 3.x对hstore类型的处理逻辑完全变了,咱们一步步来解决:
问题根源
在Npgsql 2.2.5版本中,hstore列会直接以字符串形式返回(比如"key1=>val1,key2=>val2"),所以你的XPO值转换器可以直接基于字符串解析成List<Tuple<object, object>>。但升级到3.2.7后,Npgsql会返回NpgsqlTypes.NpgsqlHstore类型的对象,不再是原始字符串——你的旧转换器还是按字符串来处理,类型不匹配就触发了"an object should implement IConvertible"的错误。
解决方案
1. 修改XPO值转换器适配NpgsqlHstore
你需要把原来处理字符串的逻辑改成处理NpgsqlHstore对象,示例代码如下:
using DevExpress.Xpo.Metadata; using NpgsqlTypes; using System; using System.Collections.Generic; using System.Linq; public class HstoreToTupleListConverter : ValueConverter { public override Type StorageType => typeof(NpgsqlHstore); public override object ConvertFromStorageType(object value) { if (value == null || value == DBNull.Value) return new List<Tuple<object, object>>(); // 现在value是NpgsqlHstore类型,直接遍历其键值对 var hstore = (NpgsqlHstore)value; return hstore.Select(kvp => Tuple.Create((object)kvp.Key, (object)kvp.Value)).ToList(); } public override object ConvertToStorageType(object value) { var tupleList = value as List<Tuple<object, object>>; if (tupleList == null || !tupleList.Any()) return DBNull.Value; // 将Tuple列表转成NpgsqlHstore var hstoreDict = tupleList.ToDictionary(t => t.Item1.ToString(), t => t.Item2?.ToString()); return new NpgsqlHstore(hstoreDict); } }
2. 注册转换器到XPO字典
确保在XPO初始化时,把这个转换器注册到对应的hstore属性上:
// 假设你的XPO类是YourPersistentClass,对应的hstore属性是HstoreData var dict = new ReflectionDictionary(); dict.GetClassInfo(typeof(YourPersistentClass)) .GetMember(nameof(YourPersistentClass.HstoreData)) .SetValueConverter(new HstoreToTupleListConverter());
3. 确认程序集版本一致性
检查你的项目引用:
- Npgsql版本必须是3.2.7,不能混合旧版本
- 如果使用了DevExpress的Npgsql XPO集成包(比如DevExpress.Xpo.vXX.Npgsql),也要确保版本和Npgsql兼容(3.2.7对应的集成包版本需要匹配你的DevExpress版本)
额外注意点
- 测试双向转换:不仅要测试读取hstore列,还要测试修改
List<Tuple<object, object>>后写入数据库是否正常 - 如果你的Tuple类型有特殊值(比如非字符串类型),需要在转换时做额外的类型处理,避免ToString()丢失信息
内容的提问来源于stack exchange,提问作者leszy77
相关产品推荐
相关产品推荐

