使用OleDb在Dapper中传递查询参数

时间:2013-09-17 10:33:53

标签: oledb dapper

此查询产生错误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 });
}

如果我将查询字符串更改为:... where id = @id ...,我将收到错误:Must declare the scalar variable "@id".

如何构造查询字符串以及如何传递参数?

4 个答案:

答案 0 :(得分:12)

当前的源代码(尚未发布到NuGet)解决了这个问题;以下应该有效:

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

答案 1 :(得分:7)

重要提示:see newer answer


在当前构建中,答案是“否”,原因有两个:

  • 代码尝试过滤未使用的参数 - 目前正在删除所有参数,因为它无法在sql中找到@id:id?id之类的内容
  • 从类型中添加值的代码对参数使用任意(well,ok:alphabetical)顺序(因为反射不会对成员的顺序做出任何保证),使位置匿名参数不稳定

好消息是这两个都是可以修复的

  • 我们可以使过滤行为成为条件
  • 我们可以检测具有与所有属性名称匹配的构造函数的类型类别,并使用构造函数参数位置来确定属性的合成顺序 - 匿名类型属于此类别

对我的本地克隆进行这些更改后,现在传递以下内容:

// 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);
    }
}

请注意,我目前正在使用DynamicParameters来避免向Query / Query<T>添加更多重载 - 因为这需要添加到相当多的方法中。将其添加到DynamicParameters可以在一个地方解决它。

在我推动之前,我愿意接受反馈 - 这看起来对您有用吗?


编辑:添加了一个时髦的smellsLikeOleDb(不,不是笑话),我们现在可以更直接地做到这一点:

// 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);
    }
}

答案 2 :(得分:0)

我试图在我的软件产品中使用Dapper,该产品使用odbc连接(目前)。然而有一天,我打算放弃使用odbc并使用不同的模式来支持不同的RDBMS产品。但是,我在解决方案实现方面遇到的问题有两个:

  1. 我想编写带有符合不同后端的参数的SQL代码,所以我想在我的SQL中编写命名参数,这样我就不会再回去再重新做。
  2. 我不想依赖我的财产顺序与我一致?这是不好的。所以我的建议是请为odbc添加对命名参数的支持。
  3. 与此同时,我已经将一个允许我用Dapper执行此操作的解决方案整合在一起。基本上我有一个例程替换命名参数?并重建参数对象,确保参数的顺序正确。 然而,看看Dapper代码,我可以看到我已经重复了一些dapper正在做的事情,实际上每个参数值现在都被访问了一次,而不是必要的。对于批量更新/插入而言,这变得更加严重。 但至少它似乎对我有用o.k ......

    我从here借了一些代码,成为我解决方案的一部分......

答案 3 :(得分:0)

?参数对我来说是解决方案的一部分,但它仅适用于整数,例如ID。对于字符串,它仍然失败,因为未指定参数长度。

  

OdbcException:错误[HY104] [Microsoft] [ODBC Microsoft Access驱动程序] 无效的精度值
  System.Data.Odbc。 OdbcParameter.Bind ((OdbcStatementHandle hstmt,   OdbcCommand命令,短序号,CNativeBuffer参数Buffer,bool allowReentrance)
  System.Data.Odbc.OdbcParameterCollection.Bind(OdbcCommand命令,CMDWrapper cmdWrapper,CNativeBuffer parameterBuffer)   System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior行为,字符串方法,布尔NeedReader,object [] methodArguments,SQL_API odbcApiMethod)
  System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior行为,字符串方法,布尔型NeedReader)
  System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior行为,CancellationToken cancelToken)
  SqlMapper.Async.cs中的Dapper.SqlMapper.QueryAsync(IDbConnection cnn,Type validType,CommandDefinition命令)
  Repository.cs中的WebAPI.DataAccess.CustomerRepository.GetByState(字符串状态)
     var result = await conn.QueryAsync(sQuery,new {State = state});
  CustomerController .cs中的WebAPI.Controllers.CustomerController.GetByState(字符串状态)
     返回等待状态_customerRepo.GetByState(state);

要使Dapper将字符串参数传递给ODBC,我必须指定长度。

var result = await conn.QueryAsync<Customer>(sQuery, new { State = new DbString { Value = state, IsFixedLength = true, Length = 4} });