如何在查询中插入多个整数参数?

时间:2019-09-01 06:42:05

标签: api ms-access dapper

网站用户可以输入搜索条件来查询订单。用户,州,状态,订单ID等

网站与API通信。查询参数位于标题中,因此我假设它们以字符串形式出现。 API通过Dapper与Access进行通信。

对于某些条件,他们可以发送多个值。所以我想使用“ IN”子句。

where UserID in (150, 3303, 16547)

Dapper处理得很好。

connection.Query<int>("select * from table where Id in @Ids", new { Ids = new int[] { 1, 2, 3 } });

这在MS-Access中有效

SELECT top 100 * from Orders where UserID in (150, 30330)

但这仅在值是int时有效。在Access中,字符串和字符串都给出“条件表达式中的数据类型不匹配”。

SELECT top 100 * from Orders where UserID in ("150", "30330")  // two strings
SELECT top 100 * from Orders where UserID in ("150, 30330")  // single string

这可能是一个巧合,但是我看到的所有示例都是整数。如果不指定大小,Access会在字符串上引发错误。使用DynamicParameters可以轻松指定大小。
但是,当字段为int时,我的精简程序代码会给出相同的错误(条件表达式中的数据类型不匹配):

var paramlist = new DynamicParameters();
if ((!string.IsNullOrWhiteSpace(userId)) && userId != "0") {
    paramlist.Add("userId", userId, DbType.String, ParameterDirection.Input, 50);                
    sbWhere.AppendFormat("AND CustFID in (?) ", paramIndex++);
}

所以我认为问题是我告诉它参数是一个字符串。

但是,如果我将参数设为int,则它将不会采用具有多个值的字符串。相反,如果我在字符串中包含(),它会抱怨'in'子句中缺少括号。

我尝试将数字字符串拆分为数组和/或列表。

if ((!string.IsNullOrWhiteSpace(userId)) && userId != "0") {
    var userIds = userId.Split(',');  //.ToList(); fails, can't map to native type
    paramlist.Add("userId", userIds, DbType.String, ParameterDirection.Input, 1000);
    if (userIds.Length > 1) {
        sbWhere.AppendFormat("AND CustFID in @userId ", paramIndex++);
    } else {
        sbWhere.AppendFormat("AND CustFID = @userId ", paramIndex++);                
    }
}

,它给出“:没有从对象类型System.String []到已知托管提供程序本机类型的映射。”我说的参数是int32还是字符串。

更新: 可能有多个搜索条件,所以我正在使用DynamicParameters。
这是我实现Palle Due想法的尝试。

if ((!string.IsNullOrWhiteSpace(userId)) && userId != "0") {
//    var userIds = userId.Split(',').Select(i => Int32.Parse(i)).ToList();// fails, can't map to native type
   IEnumerable<int> userIds = userId.Split(',').Select<string, int>(int.Parse);
   paramlist.Add("userId", userIds, DbType.Int32, ParameterDirection.Input);
   if (userIds.Count() > 1) {
      sbWhere.AppendFormat("AND CustFID in @userId ", paramIndex++);
   } else {
      sbWhere.AppendFormat("AND CustFID = @userId ", paramIndex++);                
   }
}

using (IDbConnection conn = Connection) {
   string sQuery = string.Format("SELECT {0} FROM vwweb_Orders {1}", columns, where);
   conn.Open();
   var result = await conn.QueryAsync<Order>(sQuery, paramlist);
   return result.ToList();
}

抛出

Message: System.AggregateException : One or more errors occurred. (Failed to convert parameter value from a SelectArrayIterator`2 to a Int32.)
----> System.InvalidCastException : Failed to convert parameter value from a SelectArrayIterator`2 to a Int32.
----> System.InvalidCastException : Object must implement IConvertible.

2 个答案:

答案 0 :(得分:0)

github页面@Dai链接到,指定Dapper列表支持仅适用于IEnumerable<int>

但是据我了解,您的UserID是一个整数,所以我不明白您为何尝试输入字符串。您需要获取用户输入的字符串并将其转换为IEnumerable<int>。做这样的事情:

IEnumerable<int> userIDs = (userId?? "").Split(',').Select<string, int>(int.Parse);
var result = connection.Query<int>("SELECT TOP 100 * FROM Orders WHERE UserID IN @Ids", new { Ids = userIDs });

您可能要对此进行一些输入检查,还可能需要重新考虑将Access用作网站的“数据库”。这不是它的本意。

答案 1 :(得分:0)

我放弃。 Dapper应该可以处理这个,但这是一个较新的功能,所以...
我只是自己构建了IN子句。

if (userIds.Count() > 1) {
    sbWhere.AppendFormat("AND CustFID in ( ");
    int paramCnt = 0;
    foreach (int id in userIds) {
        sbWhere.AppendFormat("?, ");  // Access doesn't mind a trailing ,
        paramlist.Add("userId" + paramCnt.ToString(), id, DbType.Int32, ParameterDirection.Input);
        paramCnt++;
    }
    sbWhere.AppendFormat(") ");
} else {
    sbWhere.AppendFormat("AND CustFID = ? ");
    paramlist.Add("userId", userIds.ToArray<int>()[0], DbType.Int32, ParameterDirection.Input);
}