14

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

4 回答 4

14

以下应该有效:

var result = conn.Query(
"select code, name from mytable where id = ?id? order by name",
new { id = 1 });
于 2014-09-23T09:05:39.843 回答
7

重要提示:查看更新的答案


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

  • 该代码尝试过滤未使用的参数 - 目前正在删除所有这些参数,因为它找不到类似@id,:id?idsql 中的任何内容
  • 从类型添加值的代码对参数使用任意(好吧,按字母顺序)顺序(因为反射不保证成员的顺序),使位置匿名参数不稳定

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

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

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

// 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添加更多重载- 因为这需要添加到相当多的方法中。将其添加到一处即可解决。QueryQuery<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);
    }
}
于 2013-09-18T08:45:43.287 回答
0

我已经在使用 odbc 连接的软件产品中试用了 Dapper(目前)。但是有一天我打算离开 odbc 并使用一种不同的模式来支持不同的 RDBMS 产品。但是,我的解决方案实施问题是 2 倍:

  1. 我想用符合不同后端的参数编写 SQL 代码,所以我现在想在我的 SQL 中编写命名参数,这样我以后就不用回去重新做。
  2. 我不想依赖让我的属性的顺序符合我的?。这是不好的。所以我的建议是请为 odbc 添加对命名参数的支持。

与此同时,我拼凑了一个解决方案,让我可以用 Dapper 来做这件事。本质上,我有一个例程将命名参数替换为 ? 并且还重建参数对象以确保参数的顺序正确。但是查看 Dapper 代码,我可以看到我已经重复了一些 dapper 正在做的事情,实际上它现在每个参数值都被访问了一次,而不是必要的。这成为批量更新/插入的更多问题。但至少它似乎对我有用..

我从这里借了一些代码来形成我的解决方案的一部分......

于 2014-05-22T21:59:03.403 回答
0

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

OdbcException: 错误 [HY104] [Microsoft][ODBC Microsoft Access Driver]无效的精度值
System.Data.Odbc。OdbcParameter.Bind (OdbcStatementHandle hstmt, OdbcCommand command, short ordinal, CNativeBuffer parameterBuffer, bool allowReentrance)
System.Data.Odbc.OdbcParameterCollection.Bind(OdbcCommand command, CMDWrapper cmdWrapper, CNativeBuffer parameterBuffer) System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior 行为, 字符串方法, bool needReader, object[] methodArguments, SQL_API odbcApiMethod)
System.Data.Odbc.OdbcCommand.ExecuteReaderObject(CommandBehavior 行为, 字符串方法, bool needReader)
System.Data.Common.DbCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancelToken)
Dapper.SqlMapper.QueryAsync(IDbConnection cnn, Type EffectiveType, CommandDefinition command) in SqlMapper.Async.cs
WebAPI.DataAccess.CustomerRepository.GetByState(string state) in SqlMapper.Async.cs .cs
var result = await conn.QueryAsync(sQuery, new { State = state });
CustomerController .cs 中的 WebAPI.Controllers.CustomerController.GetByState(string state)
返回 await _customerRepo.GetByState(state);

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

var result = await conn.QueryAsync<Customer>(sQuery, new { State = new DbString { Value = state, IsFixedLength = true, Length = 4} });
于 2019-07-19T16:08:54.760 回答