如何将PostgreSQL动态JSON字段运行时转为C#类实例传入Razor视图
解决方案
一、动态JSON字段转强类型实例实现(高性能适配数百条数据场景)
你的场景中同一次查询返回的DynamicData结构是统一的,只需生成一次对应类型即可复用,性能和静态定义类无显著差异:
- 结构哈希缓存:首次拉取查询结果时,取第一条
DynamicData的JSON结构生成哈希值作为缓存键,相同结构的查询直接复用已生成的类型,避免重复编译。 - 运行时类型生成:可以直接用成熟的开源封装
DynamicTypeBuilder,也可以基于System.Reflection.Emit自行实现,按JSON的属性名、类型、嵌套结构生成对应C#类,示例核心逻辑:
// 生成类型后用System.Text.Json反序列化,性能接近静态类反序列化 var targetType = DynamicTypeBuilder.GetTypeFromJson(sampleJson); var contentList = new List<object>(); foreach(var row in dbRows) { var content = Activator.CreateInstance(typeof(Content<>).MakeGenericType(targetType)); // 赋值Id、Title content.GetType().GetProperty("Id").SetValue(content, row.Id); content.GetType().GetProperty("Title").SetValue(content, row.Title); // 反序列化DynamicData var dynamicData = JsonSerializer.Deserialize(row.DynamicDataJson, targetType); content.GetType().GetProperty("DynamicData").SetValue(content, dynamicData); contentList.Add(content); }
- Razor视图适配:生成的强类型可以直接作为模型传入视图,属性访问和静态定义类完全一致。
二、dynamic类型数组循环访问属性失败的原因
该问题是C#编译期类型推断导致的:
- 如果你用Newtonsoft.Json反序列化动态数组,数组元素实际为
JObject类型,用foreach(var item in 数组)时,var会被推断为object类型,编译期不允许访问未定义的属性 - 调试器可以看到属性是因为调试时会反射解析对象的实际内容,不受编译期类型检查限制
- 修复方案只需在循环时明确指定元素类型为
dynamic:
// 错误写法 foreach (var item in dynamicArray) { var name = item.Name; // 编译报错 } // 正确写法 foreach (dynamic item in dynamicArray) { var name = item.Name; // 正常运行 }
三、更轻量的替代方案(无需生成运行时类型)
如果你的场景仅需在视图中渲染属性,不需要强类型的编译期检查,可以直接用.NET原生的JsonElement承载JSON内容,性能足够支撑数百条数据的渲染,也不会遇到动态属性访问问题:
- 配置EF Core映射PostgreSQL的json字段为
JsonElement类型,无需手动反序列化 - 视图中直接按key访问属性:
@* 访问顶级属性 *@ @Model.DynamicData["Name"].GetString() @* 访问嵌套属性 *@ @Model.DynamicData["Details"]["Job"].GetString() @* 访问数值/布尔类型属性 *@ @Model.DynamicData["Details"]["Age"].GetInt32()
内容的提问来源于stack exchange,提问作者srkn
相关产品推荐
相关产品推荐

