Passing query parameters in Dapper using OleDb

dapper oledb

Question

This query produces an error No value given for one or more required parameters:

using (var conn = new OleDbConnection("Provider=..."))
{
  conn.Open();
  var result = conn.Query(
    "select code, name from mytable where id = ? order by name",
    new { id = 1 });
}

If I change the query string to: ... where id = @id ..., I will get an error: Must declare the scalar variable "@id".

How do I construct the query string and how do I pass the parameter?

Accepted Answer

The current source code (not yet released to NuGet) addresses this issue; the following should work:

var result = conn.Query(
"select code, name from mytable where id = ?id? order by name",
new { id = 1 });

Expert Answer

Important: see newer answer


In the current build, the answer to that would be "no", for two reasons:

  • the code attempts to filter unused parameters - and is currently removing all of them because it can't find anything like @id, :id or ?id in the sql
  • the code for adding values from types uses an arbitrary (well, ok: alphabetical) order for the parameters (because reflection does not make any guarantees about the order of members), making positional anonymous arguments unstable

The good news is that both of these are fixable

  • we can make the filtering behaviour conditional
  • we can detect the category of types that has a constructor that matches all the property names, and use the constructor argument positions to determine the synthetic order of the properties - anonymous types fall into this category

Making those changes to my local clone, the following now passes:

// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
    using (var conn = new System.Data.OleDb.OleDbConnection(
        Program.OleDbConnectionString))
    {
        var row = conn.Query("select Id = ?, Age = ?", new DynamicParameters(
            new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
        ) { RemoveUnused = false } ).Single();
        int age = row.Age;
        int id = row.Id;
        age.IsEqualTo(23);
        id.IsEqualTo(12);
    }
}

Note that I'm currently using DynamicParameters here to avoid adding even more overloads to Query / Query<T> - because this would need to be added to a considerable number of methods. Adding it to DynamicParameters solves it in one place.

I'm open to feedback before I push this - does that look usable to you?


Edit: with the addition of a funky smellsLikeOleDb (no, not a joke), we can now do this even more directly:

// see https://stackoverflow.com/q/18847510/23354
public void TestOleDbParameters()
{
    using (var conn = new System.Data.OleDb.OleDbConnection(
        Program.OleDbConnectionString))
    {
        var row = conn.Query("select Id = ?, Age = ?",
            new { foo = 12, bar = 23 } // these names DO NOT MATTER!!!
        ).Single();
        int age = row.Age;
        int id = row.Id;
        age.IsEqualTo(23);
        id.IsEqualTo(12);
    }
}



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