Dapper中不允许在此上下文中使用可枚举序列的参数(数组、列表等)。

19

我有以下代码:

static void Main(string[] args){
        string sql= "SELECT * FROM Posts WHERE 1=1 ";
        SqlParameter[] @params= SetDynamicParameter(ref sql, "Param=Value", "Param2=Value2", "ParamN=ValueN");

        IDbConnection connection = new SqlConnection(connectionString);
        IEnumerable<Posts> en = connection.Query<Posts>(sql,param:@params);

        Console.ReadKey(true);
}
 static SqlParameter[] SetDynamicParameter(ref string sql,params string[] sarr) {
        string condition = string.Empty;
        List<SqlParameter> list = new List<SqlParameter>();
        foreach (var item in sarr)
        {
            condition += " AND "+item.Split('=')[0] + "=@" + item.Split('=')[0];
            list.Add(new SqlParameter("@" + item.Split('=')[0], item.Split('=')[1]));
        }
        sql += condition;
        return list.ToArray() ;
  }

输出错误:不允许在此上下文中使用可枚举的参数序列(数组、列表等)。

这是怎么回事?是否有等效的解决方案?


2
这是因为Dapper想要一组属性和值,而不是一组SQL参数列表。我认为你可以创建一个Dictionary<string, object>,其中键是参数名称(不带@),值是要设置到参数的值。这样做的想法是Dapper会为您创建属性。 - juharr
你可能会在这个stackoverflow线程中找到一些有用的东西。[https://dev59.com/NlwX5IYBdhLWcg3wjgCf] - user6745503
4个回答

23

尝试使用Dapper.DynamicParameters代替SqlParameter数组:

var parameters = new DynamicParameters();
parameters.Add("@ParameterName", parameterValue);

5
我知道对你来说可能有些晚了,但也许能帮助其他人 :)
你可以像这样实现它:
public class MySqlDataAccess
{
    string _connectionString = "{your connection string}";

    public async Task<IEnumerable<CustomerDto>> GetListAsync(IList<Guid> customers)
    {
        const string query = @"
            SELECT TOP 100 Id,
                    Name
            FROM Customers
            WHERE Id IN @CustomerIdList
        ";

        using (var c = new SqlConnection(_connectionString))
        {
            return await c.QueryAsync<CustomerDto>(query, new { CustomerIdList = customers.ToArray() });
        }
    }
}

你可以使用WHERE Id IN @CustomerIdList,然后从数组中传入一个匿名类型,如下所示:new { CustomerIdList = customers.ToArray() },而不是直接传递数组。

希望这对你有帮助!


1
你可以通过使用 WHERE Id IN @customersawait c.QueryAsync<CustomerDto>(query, new { customers }); 来缩短代码,这样也能正常工作。 - emilsteen

1
Dapper将以IEnumerable形式作为param参数,并插入多条记录。这就是我传递的内容,所以当我收到上面的错误消息时感到困惑。
我的错误在于我从另一个调用connection.Query而不是connection.Execute的方法中复制和粘贴了代码。
所以,如果您的查询已经指定了列,请检查是否调用了Execute而不是其他方法。

1
如果您使用ExecuteNonQuery而不是Query<>,则将不再出现此异常。但是,当您在Oracle中使用查询时,会出现另一个问题。
我解决这个问题的方法是使用一个中间表。我正在使用Oracle;Oracle有一个名为“dual”的特殊表,位于sys模式下。这张表给了我灵感,我创建了另一张表,位于我的用户模式下。
CREATE TABLE USER_SCHEMA.DUAL2
(
  DUMMY  VARCHAR2(1000 BYTE)
)
NOCOMPRESS 
NOCACHE
NOPARALLEL;

你可以根据需要扩展长度。给表格一些授权。然后我将我的查询从选择语句更改为插入语句。
INSERT INTO USER_SCHEMA.DUAL2
   (SELECT ID
      FROM ANOTHER_SCHEMA.SOME_TABLE
     WHERE SOME_FLAG = 'M' AND NO IN :NO)

这是因为ADO.NET无法从ExecuteNonQuery返回结果。默认情况下,它运行SELECT查询,但对每个查询返回-1。我通过提供一个SELECT查询来模拟INSERT。这将返回一个结果。
var parameters = noSplit.Select(x => new { NO = x, SOME_FLAG = flag }).ToList();

var queryResult = dbConnection.Execute(insertSelectQuery, parameters, transactionIfExists);

if (queryResult != parameters.Count)
{
    throw new Exception("Can not find some no");
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接