I have a PostgreSQL function that takes in a parameter of type json
. Using Dapper, how do I execute a call that passes the object to the PostgreSQL function such that PostgreSQL recognizes the type as json
instead of as text
?
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$;
[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);
}
}
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;
}
}
In this current iteration, I've added a SqlMapper.TypeHandler
. (At the moment, I'm only concerned with passing the JArray
to PostgreSQL, hence the NotImplmentedException
for Parse
.)
With this example, I get the following exception:
System.NotSupportedException : 'The CLR array type Newtonsoft.Json.Linq.JArray isn't supported by Npgsql or your PostgreSQL. If you wish to map it to an PostgreSQL composite type array you need to register it before usage, please refer to the documentation.'
In past iterations, I've also tried things like using a List<Hero>
type handler and letting that type handler deal with the Json conversion.
I've also tried adding the Npgsql.Json.NET
Nuget package extension for Npgsql and call conn.TypeMapper.UseJsonNet()
in my test method, but that didn't seem to have any effect.
And if I do anything to serialize the object to a JSON string, then I get a different error (below), which makes sense.
Npgsql.PostgresException : '42883: function testfuncthattakesinjson(heroes => text) does not exist'
So, it is possible to use Dapper to pass a JSON object as a PostgreSQL primitive to a function?
You can use Dapper's ICustomQueryParameter interface.
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);
}
}
Then your Dapper call becomes:
var results = conn.Query<Character>(funcName, new
{
heroes = new JsonParameter(jsonObj.ToString())
}, commandType: CommandType.StoredProcedure);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.