如何使用 Dapper 将 JSON 作为原始 PostgreSQL 类型传递给函数?

问题描述 投票:0回答:2

我有一个 PostgreSQL 函数,它接受类型为

json
的参数。使用 Dapper,如何执行将对象传递给 PostgreSQL 函数的调用,以便 PostgreSQL 将类型识别为
json
而不是
text

接受 json 类型的 PostgreSQL 函数示例

CREATE OR REPLACE FUNCTION testfuncthattakesinjson(heroes json)
    RETURNS SETOF characters 
    LANGUAGE 'sql'

    STABLE
    ROWS 100
AS $BODY$

    SELECT  c.*
    FROM    characters c
    JOIN    json_array_elements(heroes) j
    ON      c.first_name = j->>'first_name'
    AND     c.last_name = j->>'last_name';

$BODY$;

损坏的 C# 集成测试示例

[Test]
public void Query_CallFunctionThatTakesInJsonParameter_FunctionUsesJsonType()
{
    using (var conn = new NpgsqlConnection(Db.GetConnectionStringToDatabase()))
    {
        var funcName = "testfuncthattakesinjson";
        var expect = CharacterTestData.Where(character => character.id <= 3);
        var jsonObj = JArray.FromObject(CharacterTestData
            .Where(character => character.id <= 3)
            .Select(character => new Hero(character))
            .ToList());

        SqlMapper.AddTypeHandler(new JArrayTypeHandler());

        // Act 
        var results = conn.Query<Character>(funcName, new
        {
            heroes = jsonObj
        }, commandType: CommandType.StoredProcedure);

        // Assert
        CollectionAssert.AreEquivalent(expect, results);
    }
}

支持 JArrayTypeHandler

internal class JArrayTypeHandler : SqlMapper.TypeHandler<JArray>
{
    public override JArray Parse(object value)
    {
        throw new NotImplementedException();
    }

    public override void SetValue(IDbDataParameter parameter, JArray value)
    {
        parameter.Value = value;
    }
}

在当前的迭代中,我添加了一个

SqlMapper.TypeHandler
。 (目前,我只关心将
JArray
传递给 PostgreSQL,因此 NotImplmentedException
 代表 
Parse
。)

通过这个例子,我得到以下异常:

System.NotSupportedException:'Npgsql 或 PostgreSQL 不支持 CLR 数组类型 Newtonsoft.Json.Linq.JArray。如果您希望将其映射到 PostgreSQL 复合类型数组,则需要在使用前注册它,请参阅文档。'

在过去的迭代中,我还尝试过使用

List<Hero>

 类型处理程序并让该类型处理程序处理 Json 转换。

我还尝试添加 Npgsql 的

Npgsql.Json.NET

 Nuget 包扩展并在我的测试方法中调用 
conn.TypeMapper.UseJsonNet()
,但这似乎没有任何效果。

如果我执行任何操作将对象序列化为 JSON 字符串,则会收到不同的错误(如下),这是有道理的。

Npgsql.PostgresException:'42883:函数 testfuncthattakesinjson(heroes => text) 不存在'

那么,

可以使用 Dapper 将 JSON 对象作为 PostgreSQL 原语传递给函数吗?

c# postgresql dapper
2个回答
12
投票
您可以使用 Dapper 的 ICustomQueryParameter 接口。

public class JsonParameter : ICustomQueryParameter { private readonly string _value; public JsonParameter(string value) { _value = value; } public void AddParameter(IDbCommand command, string name) { var parameter = new NpgsqlParameter(name, NpgsqlDbType.Json); parameter.Value = _value; command.Parameters.Add(parameter); } }

然后你的 Dapper 调用就变成:

var results = conn.Query<Character>(funcName, new { heroes = new JsonParameter(jsonObj.ToString()) }, commandType: CommandType.StoredProcedure);
    

0
投票
  1. 首先注册您的 JsonTypeHandler。

    Dapper.SqlMapper.AddTypeHandler(new JsonTypeHandler());

  2. 创建 JsonTypeHandler 如下:

    public class JsonTypeHandler<T> : SqlMapper.TypeHandler<T> { public override T Parse(object value) { if(typeof(T) == typeof(BackgroundTaskStateJson)) { string json = (string)value; return JsonConvert.DeserializeObject<T>(json); } throw new NotImplementedException(); } public override void SetValue(IDbDataParameter parameter, T value) { throw new NotImplementedException(); } }
    
    
© www.soinside.com 2019 - 2024. All rights reserved.