How to insert multiple integer parameters into query?

时间秒杀一切 提交于 2020-01-06 05:40:12

问题


Website user can enter search criteria to query orders. User, States, Status, OrderID, etc.

Website communicates with API. Query parameters are in the header, so I assume they come in as strings. API communicates with Access via Dapper.

For some criteria, they can send multiple values. So I want to use an "IN" clause.

where UserID in (150, 3303, 16547)

Dapper handles this nicely.

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

This works in MS-Access

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

But that only works when the values are ints. String and Strings both give "Data type mismatch in criteria expression" in 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

It may be a coincidence, but all the examples I see are integers. Access throws an error on strings if you don't specify the size. Using DynamicParameters makes it easy to specify the size.
But when the field is an int, my dapper code gives the same error (Data type mismatch in criteria expression):

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

So I assume the issue is that I'm telling it that the parameter is a string.

But if I make the parameter an int, then it won't take the string with multiple values. Conversely, if I include the () in the string, it complains about the parens being missing from the 'in' clause.

I tried splitting the string of numbers into an array and/or list.

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

and it gives ": No mapping exists from object type System.String[] to a known managed provider native type." whether I say the parameters are int32 or string.

UPDATE: There may be multiple search criteria, so I'm using DynamicParameters.
Here is my attempt at implementing Palle Due's idea.

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

throws

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.

回答1:


The github page @Dai links to specifies that the Dapper list support only works with IEnumerable<int>.

But as I understand it your UserID is an int, so I don't get why you try to enter a string. You need to get the string the user has input and convert it to IEnumerable<int>. Do something like this:

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

You might want to apply some input checking to that, and you might also want to reconsider using Access as the "database" for a website. It's not what it was meant for.




回答2:


I give up. Dapper should be able to handle this, but it's a newer feature, so...
I just built the IN clause myself.

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


来源:https://stackoverflow.com/questions/57743770/how-to-insert-multiple-integer-parameters-into-query

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!