Npgsql调用PostgreSQL时jsonb #>操作符报错,如何正确传参?
解决Npgsql调用PostgreSQL jsonb操作符的类型不匹配问题
这个错误的核心原因很明确:PostgreSQL的#>操作符要求右侧参数是text数组类型(对应你在DataGrip里写的'{inner_id}',这是PostgreSQL的数组字面量,会被解析为text[]),但你在C#里直接传递了普通字符串,Npgsql默认把它识别为text类型,导致数据库找不到匹配的操作符,所以报错operator does not exist: jsonb #> text。
下面给你两种可行的解决方案:
方案1:正确传递text[]类型的路径参数
直接把SearchField参数转换成PostgreSQL识别的text[]类型,同时注意把SearchValue转成jsonb类型(因为#>返回的是jsonb,两边类型要匹配):
修改你的C#代码如下:
public IQueryable<CustomerForPartnerApiServiceModel> GetCustomerBySearchField(Advertiser advertiser, string searchValue) { var rawSql = @" select distinct ""Customers"".""CustomerId"" as ""CustomerId"", ""Customers"".""FcmRegistrationId"" as ""FcmRegistrationId"", ""Customers"".""FCMServerKey"" as ""FCMServerKey"", ""Customers"".""AppId"" as ""AppId"" from ""CustomerEvents"" inner join ""Customers"" on ""CustomerEvents"".""CustomerId"" = ""Customers"".""CustomerId"" where ""Customers"".""AdvertiserId"" = @AdvertiserId and ""Data"" #> @SearchField = @SearchValue::jsonb"; // 处理advertiser.SearchField:如果是类似"{inner_id}"的字符串,先转成string数组 var searchPathArray = advertiser.SearchField .Trim('{', '}') .Split(',', StringSplitOptions.RemoveEmptyEntries) .Select(s => s.Trim()) .ToArray(); var res = _applicationDbContext.BySearchFieldCustomerApiModels.FromSql(rawSql, // 指定参数类型为text数组 new NpgsqlParameter("SearchField", NpgsqlDbType.Array | NpgsqlDbType.Text) { Value = searchPathArray }, // 指定SearchValue为jsonb类型 new NpgsqlParameter("SearchValue", NpgsqlDbType.Jsonb) { Value = searchValue }, new NpgsqlParameter<int>("AdvertiserId", advertiser.AdvertiserId)); return res; }
关键细节说明:
- 如果你的
advertiser.SearchField本来就是数组格式(比如直接存储的是["inner_id"]这样的字符串数组),可以跳过字符串分割的步骤,直接传入数组即可。 - 加上
@SearchValue::jsonb是为了确保比较两边的类型一致,避免出现jsonb = text的类型不匹配错误。
方案2:改用JsonPath语法(PostgreSQL 12+适用)
如果你的PostgreSQL版本是12或以上,可以用更直观的JsonPath语法,参数直接传递字符串路径(比如'$.inner_id'),不需要处理数组:
修改SQL语句和参数如下:
public IQueryable<CustomerForPartnerApiServiceModel> GetCustomerBySearchField(Advertiser advertiser, string searchValue) { // 假设advertiser.SearchField现在是类似"$.inner_id"的JsonPath字符串 var rawSql = @" select distinct ""Customers"".""CustomerId"" as ""CustomerId"", ""Customers"".""FcmRegistrationId"" as ""FcmRegistrationId"", ""Customers"".""FCMServerKey"" as ""FCMServerKey"", ""Customers"".""AppId"" as ""AppId"" from ""CustomerEvents"" inner join ""Customers"" on ""CustomerEvents"".""CustomerId"" = ""Customers"".""CustomerId"" where ""Customers"".""AdvertiserId"" = @AdvertiserId and jsonb_path_query(""Data"", @SearchPath) = @SearchValue::jsonb"; var res = _applicationDbContext.BySearchFieldCustomerApiModels.FromSql(rawSql, new NpgsqlParameter("SearchPath", advertiser.SearchField), new NpgsqlParameter("SearchValue", NpgsqlDbType.Jsonb) { Value = searchValue }, new NpgsqlParameter<int>("AdvertiserId", advertiser.AdvertiserId)); return res; }
这种方式更符合现代json查询的习惯,路径格式也更容易理解和维护。
内容的提问来源于stack exchange,提问作者Aleksej_Shherbak
相关产品推荐
相关产品推荐

