如何用.NET Expression API构建PostgreSQL JSON字段的表达式谓词
如何用.NET Expression API构建JSON属性查询的表达式谓词
问题描述
我需要用.NET Expression API创建一个表达式谓词,用来查询PostgreSQL的ObjectSource表,筛选出Data列(存储JsonDocument)中包含pnt_name属性且值为ABC123的行。最终要生成的查询逻辑等价于:
var names = context.ObjectSources .Where(e => e.Data.RootElement.GetProperty("pnt_name").GetString() == "ABC123") .ToList();
我的数据模型定义如下:
public class ObjectSource { [Key] public string ObjectSourceEId { get; set; } public string ObjectSourceIId { get; set; } public JsonDocument Data { get; set; } public int ObjectSourceEnvironment { get; set; } public string ObjectSourceCatalog { get; set; } public string ObjectSourceTable { get; set; } public string State { get; set; } public DateTime CreatedAd { get; set; } public DateTime UpdatedAt { get; set; } }
目前我已经能通过以下代码获取Data属性的表达式:
var property = Expression.Property(parm, typeof(T).GetProperty("Data"));
但不清楚如何构建完整的谓词表达式。
分步构建表达式谓词
1. 定义参数表达式
首先创建代表ObjectSource实例的参数表达式:
var param = Expression.Parameter(typeof(ObjectSource), "e");
2. 链式访问Data.RootElement
从参数表达式出发,依次获取Data属性和JsonDocument的RootElement属性:
// 获取e.Data var dataProperty = Expression.Property(param, nameof(ObjectSource.Data)); // 获取e.Data.RootElement var rootElementProperty = Expression.Property(dataProperty, nameof(JsonDocument.RootElement));
3. 调用GetProperty("pnt_name")
构建调用JsonElement.GetProperty方法的表达式,传入目标属性名作为常量参数:
// 获取GetProperty方法的MethodInfo var getPropertyMethod = typeof(JsonElement).GetMethod(nameof(JsonElement.GetProperty), new[] { typeof(string) }); // 构造方法调用:e.Data.RootElement.GetProperty("pnt_name") var getPropertyCall = Expression.Call( rootElementProperty, getPropertyMethod, Expression.Constant("pnt_name") );
4. 调用GetString()
接着调用JsonElement.GetString()方法获取属性的字符串值:
// 获取GetString方法的MethodInfo var getStringMethod = typeof(JsonElement).GetMethod(nameof(JsonElement.GetString), Type.EmptyTypes); // 构造方法调用:e.Data.RootElement.GetProperty("pnt_name").GetString() var getStringCall = Expression.Call(getPropertyCall, getStringMethod);
5. 构建相等比较表达式
将GetString()的结果与目标值"ABC123"做相等比较:
// 构造比较表达式:... == "ABC123" var equalsExpression = Expression.Equal( getStringCall, Expression.Constant("ABC123", typeof(string)) );
6. 组装成Lambda表达式并使用
把所有表达式组装成完整的Lambda谓词,即可用于查询:
// 创建Lambda表达式:e => e.Data.RootElement.GetProperty("pnt_name").GetString() == "ABC123" var predicate = Expression.Lambda<Func<ObjectSource, bool>>(equalsExpression, param); // 执行查询 var names = context.ObjectSources.Where(predicate).ToList();
完整代码示例
整合所有步骤的完整代码如下:
using System.Linq.Expressions; using System.Text.Json; // 构建参数表达式 var param = Expression.Parameter(typeof(ObjectSource), "e"); // 获取Data及RootElement属性 var dataProperty = Expression.Property(param, nameof(ObjectSource.Data)); var rootElementProperty = Expression.Property(dataProperty, nameof(JsonDocument.RootElement)); // 调用GetProperty方法 var getPropertyMethod = typeof(JsonElement).GetMethod(nameof(JsonElement.GetProperty), new[] { typeof(string) }); var getPropertyCall = Expression.Call(rootElementProperty, getPropertyMethod, Expression.Constant("pnt_name")); // 调用GetString方法 var getStringMethod = typeof(JsonElement).GetMethod(nameof(JsonElement.GetString), Type.EmptyTypes); var getStringCall = Expression.Call(getPropertyCall, getStringMethod); // 构建相等比较 var equalsExpression = Expression.Equal(getStringCall, Expression.Constant("ABC123", typeof(string))); // 生成Lambda谓词并执行查询 var predicate = Expression.Lambda<Func<ObjectSource, bool>>(equalsExpression, param); var names = context.ObjectSources.Where(predicate).ToList();
内容的提问来源于stack exchange,提问作者K N
相关产品推荐
相关产品推荐

