PostgreSQL JSONB查询结果绑定C#模型报错的解决问询
问题分析
错误的核心原因是:PostgreSQL返回的content列是字符串类型的JSON数组,而你的ToModelList方法直接将DataTable序列化为JSON后,content字段会被保留为带引号的字符串值(例如 "[{\"created_by\": \"user1\", ...}]"),但C#模型中NegotiatedContents是List<NegotiatedContent>类型,Json.NET无法直接将字符串转换为集合对象,因此抛出类型转换错误。
解决方案
以下提供两种可行的修复方式,可根据你的代码习惯选择:
方式一:修改ToModelList扩展方法,手动处理JSON字段反序列化
直接在转换模型的过程中,对需要解析JSON的字段单独处理,确保字符串转成对应的集合:
using System.Reflection; using Newtonsoft.Json; public static List<T> ToModelList<T>(this DataTable dt) where T : new() { if (dt?.Rows.Count == 0) return new List<T>(); var modelList = new List<T>(); var modelType = typeof(T); // 获取模型的公共属性 var properties = modelType.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (DataRow row in dt.Rows) { var model = new T(); foreach (var prop in properties) { // 根据JsonProperty特性匹配DataTable列名 var jsonAttr = prop.GetCustomAttribute<JsonPropertyAttribute>(); string columnName = jsonAttr?.PropertyName ?? prop.Name; if (!dt.Columns.Contains(columnName)) continue; var cellValue = row[columnName]; if (cellValue == DBNull.Value) continue; // 判断当前属性是否为List<T>类型 if (prop.PropertyType.IsGenericType && prop.PropertyType.GetGenericTypeDefinition() == typeof(List<>)) { // 将字符串形式的JSON反序列化为对应集合 string jsonStr = cellValue.ToString(); var deserializedList = JsonConvert.DeserializeObject(jsonStr, prop.PropertyType); prop.SetValue(model, deserializedList); } else { // 普通类型直接转换赋值 var convertedValue = Convert.ChangeType(cellValue, prop.PropertyType); prop.SetValue(model, convertedValue); } } modelList.Add(model); } return modelList; }
方式二:使用自定义JsonConverter处理字段转换
通过自定义Json转换器,告诉Json.NET如何将字符串形式的JSON数组转换为List<NegotiatedContent>:
1. 定义自定义转换器
using Newtonsoft.Json; using System.Collections.Generic; public class JsonStringToListConverter<T> : JsonConverter<List<T>> { public override List<T> ReadJson(JsonReader reader, Type objectType, List<T> existingValue, bool hasExistingValue, JsonSerializer serializer) { // 如果读取到的是字符串,先反序列化为JSON再转成集合 if (reader.TokenType == JsonToken.String) { string jsonStr = reader.Value.ToString(); return JsonConvert.DeserializeObject<List<T>>(jsonStr); } // 正常JSON数组直接反序列化 return serializer.Deserialize<List<T>>(reader); } public override void WriteJson(JsonWriter writer, List<T> value, JsonSerializer serializer) { serializer.Serialize(writer, value); } }
2. 在模型中应用转换器
修改MainClauseHistoryDto,给NegotiatedContents属性添加转换器特性:
public class MainClauseHistoryDto { [JsonProperty("transaction_id")] public int TransactionId { get; set; } [JsonProperty("content")] [JsonConverter(typeof(JsonStringToListConverter<NegotiatedContent>))] public List<NegotiatedContent> NegotiatedContents { get; set; } } public class NegotiatedContent { [JsonProperty("created_by")] public string CreatedBy { get; set; } [JsonProperty("created_date")] public DateTime CreatedDate { get; set; } [JsonProperty("title")] public string Title{ get; set; } }
3. 保留原ToModelList方法即可
此时原有的ToModelList方法无需修改,Json.NET会通过自定义转换器自动处理字符串到集合的转换。
验证说明
两种方式都能解决字符串JSON数组到C#集合的转换问题,方式一更通用(无需修改模型),方式二更灵活(可针对特定字段定制转换逻辑),根据你的实际场景选择即可。
内容的提问来源于stack exchange,提问作者Niranjan
相关产品推荐
相关产品推荐

