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

Api 如何在查询中插入多个整数参数?,api,ms-access,dapper,Api,Ms Access,Dapper,网站用户可以输入搜索条件来查询订单。用户、状态、状态、订单ID等 网站与API进行通信。查询参数在标题中,因此我假设它们以字符串的形式出现。API通过Dapper与Access通信 对于某些条件,它们可以发送多个值。所以我想用一个“IN”子句 整洁处理得很好 connection.Query<int>("select * from table where Id in @Ids", new { Ids = new int[] { 1, 2, 3 } }); 但这仅在值为int时有效。

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

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

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

整洁处理得很好

connection.Query<int>("select * from table where Id in @Ids", new { Ids = new int[] { 1, 2, 3 } });
但这仅在值为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时,我的dapper代码会给出相同的错误(条件表达式中的数据类型不匹配):

所以我假设问题是我告诉它参数是一个字符串

但是如果我将参数设置为int,那么它将不会接受具有多个值的字符串。相反,如果我在字符串中包含(),它会抱怨'in'子句中缺少paren

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

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还是String

更新: 可能有多个搜索条件,因此我使用的是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();
}

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

但据我所知,您的
UserID
是一个int,所以我不明白您为什么尝试输入字符串。您需要获取用户输入的字符串,并将其转换为
IEnumerable
。这样做:

IEnumerable userId=(userId??).Split(',).Select(int.Parse);
var result=connection.Query(“从@Ids中UserID所在的订单中选择前100个*,新的{Ids=userIDs}”);

您可能希望对此应用一些输入检查,并且您可能还希望重新考虑使用Access作为网站的“数据库”。这不是它的目的。

我放弃了。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);
}
if(userid.Count()>1){
sbWhere.AppendFormat(“)和CustFID in(”);
int paramCnt=0;
foreach(userid中的int-id){
sbWhere.AppendFormat(“?,”;//Access不介意尾随字符,
添加(“userId”+paramCnt.ToString(),id,DbType.Int32,ParameterDirection.Input);
paramCnt++;
}
sbWhere.AppendFormat(“)”;
}否则{
sbWhere.AppendFormat(“和CustFID=?”);
paramlist.Add(“userId”,userId.ToArray()[0],DbType.Int32,ParameterDirection.Input);
}

a
中的参数数量,其中x在(a,b,c)
子句中不能参数化-必须对每个参数占位符使用字符串连接-或使用表值参数(但Access不支持表值参数)。为了澄清我前面的评论:参数化
WHERE。。。在标准SQL中,
是不可能的,但是Dapper似乎将
WHERE IN
作为特例处理,而不需要RDBMS支持。那很方便-我不知道Dapper能做到!访问:我以前从未以这种方式使用过访问,也不打算再次使用,但出于各种原因,它在这个项目上是有意义的。备份存储是Postgres,因此不存在Access通常会遇到的并发性问题。访问只是业务逻辑层。我无法做出决定。数据以字符串形式从标题中输入。可能没有用户标识,一个或多个。我将用这种方法的结果更新这个问题。
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++);                
    }
}
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.
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);
}