You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将PostgreSQL动态JSON字段运行时转为C#类实例传入Razor视图

解决方案

一、动态JSON字段转强类型实例实现(高性能适配数百条数据场景)

你的场景中同一次查询返回的DynamicData结构是统一的,只需生成一次对应类型即可复用,性能和静态定义类无显著差异:

  1. 结构哈希缓存:首次拉取查询结果时,取第一条DynamicData的JSON结构生成哈希值作为缓存键,相同结构的查询直接复用已生成的类型,避免重复编译。
  2. 运行时类型生成:可以直接用成熟的开源封装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);
}
  1. 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内容,性能足够支撑数百条数据的渲染,也不会遇到动态属性访问问题:

  1. 配置EF Core映射PostgreSQL的json字段为JsonElement类型,无需手动反序列化
  2. 视图中直接按key访问属性:
@* 访问顶级属性 *@
@Model.DynamicData["Name"].GetString()
@* 访问嵌套属性 *@
@Model.DynamicData["Details"]["Job"].GetString()
@* 访问数值/布尔类型属性 *@
@Model.DynamicData["Details"]["Age"].GetInt32()

内容的提问来源于stack exchange,提问作者srkn

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 17:21:00