Dapper with Oracle passing in DbParameter

dapper oracle parameter-passing

Question

I'm trying out Dapper with Oracle and I was trying to run a multi-resultset query but Oracle requires a dbtype of refcursor.

StringBuilder query = new StringBuilder("BEGIN ");
query.Append("OPEN :rs1 FOR SELECT * FROM Table1 where key=:KEY; ");
query.Append("OPEN :rs2 FOR SELECT * FROM Table2 where key=:KEY; ");
query.Append("END;");
  • Is there a way to pass an OracleParameter (maybe as DbParameter?) to Dapper? When I tried, it threw an error.

  • What is the advantage of using the DynamicParameter vs. using a DbParameter (assuming types are known etc.)?

Accepted Answer

  1. A new interface was added in the most recent build that allows more control over the parameter - it was added to support TVPs in SQL server, but should work in this scenario. However, I'm also fairly content to add special casing for any types that look like dbparameter - and add them directly, which would allow you to add an oracleparameter directly.

  2. DynamicParameters is about how many parameters to add, so it is a bit orthogonal to the value vs DbParameter discussion. At the moment, the code generally prefers to take control of adding parameters itself, so the caller just knows "an int named id with value 7" - not any ado.net details. But it could do.


Edit: if you really want to work with lists-of-parameters (i.e. List<DbParameter> etc), then you can do that with something like:

public class DbParams : Dapper.SqlMapper.IDynamicParameters,
                        IEnumerable<IDbDataParameter>
{
    private readonly List<IDbDataParameter> parameters =
        new List<IDbDataParameter>();
    public IEnumerator<IDbDataParameter> GetEnumerator() {
        return parameters.GetEnumerator(); }
    IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
    public void Add(IDbDataParameter value)
    {
        parameters.Add(value);
    }
    void Dapper.SqlMapper.IDynamicParameters.AddParameters(IDbCommand command,
        Dapper.SqlMapper.Identity identity)
    {
        foreach (IDbDataParameter parameter in parameters)
            command.Parameters.Add(parameter);
    }
}

with usage like:

public void TestCustomParameters()
{
    var args = new DbParams {
        new SqlParameter("foo", 123),
        new SqlParameter("bar", "abc")
    };
    var result = connection.Query("select Foo=@foo, Bar=@bar", args).Single();
    int foo = result.Foo;
    string bar = result.Bar;
    foo.IsEqualTo(123);
    bar.IsEqualTo("abc");
}

which passes the test.

However, I must stress that I would prefer not to encumber the calling code with db-parameter knowledge unless it really really needs to know; I would by-far prefer:

var args = new {
    foo = 123, bar = "abc"
};

which does exactly the same thing, but without dropping to ADO.NET; this can be especially important if you are using a "decorated" ADO.NET connection (for example, mini-profiler) - in which case the layer you get is not an OracleCommand / OracleConnection etc - it is abstracted. This means that forcibly adding an OracleParameter may not always work - but adding a parameter with name "foo" and value 123 - that is pretty reliable.



Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why