使用二维数组作为 Dapper 参数列表

Using two dimensional array as Dapper parameter list

在 Dapper 中,可以使用以下代码查询列表:

var sql = "SELECT * FROM Invoice WHERE Kind IN @Kind;";

using (var connection = My.ConnectionFactory())
{
    connection.Open();

    var invoices = connection.Query<Invoice>(sql, new {Kind = new[] {InvoiceKind.StoreInvoice, InvoiceKind.WebInvoice}}).ToList();
}

但我想查询多个供应商的产品列表及其产品代码。为此,我尝试创建一个数组数组。这是我存储库中的方法:

public Dictionary<int, Dictionary<string, Product>> GetGroupedListByRelationIdAndProductCode(Dictionary<int, List<string>> productKeysByRelationId)
{
    Dictionary<int, Dictionary<string, Product>> list = new Dictionary<int, Dictionary<string, Product>>();

    string sql = "SELECT * FROM Products WHERE 1=1 ";

    int i = 0;
    foreach (KeyValuePair<int, List<string>> productKeys in productKeysByRelationId)
    {
        sql = sql + " AND (ManufacturerRelationId = " + productKeys.Key + " AND ManufacturerProductCode in @ProductCodeList[" + i + "] )";
        ++i;
    }

    using (var conn = _connectionFactory.CreateConnection())
    {
        conn.Open();

        var param = new { ProductCodeList = productKeysByRelationId.Select(x => x.Value.ToArray()).ToArray() };

        var productsList = conn.Query<Product>(sql, param).ToList();

        if (productsList.Count > 0)
        {
            foreach (var product in productsList)
            {
                list[product.ManufacturerRelationId][product.ManufacturerProductCode] = product;
            }
        }
    }


    return list;
}

虽然这给了我这个错误:System.ArgumentException: 'No mapping exists from object type System.String[] to a known managed provider native type.'

关于如何做到这一点有什么建议吗?

您的代码有几个问题。

如果您的 productKeysByRelationId 中有不止一项,您最终会 SQL 喜欢:

WHERE 1=1 AND ManufacturerRelationId = 1 ... AND ManufacturerRelationId = 2

这不太可能 return 任何结果,您需要在其中添加一些 OR。

你得到的错误是因为你有类似的东西:

AND ManufacturerProductCode in @ProductCodeList[0]

Dapper 无法处理。它主要期望查询参数是一个对象,其中包含一些简单类型或数组的适当命名的成员。

幸运的是 Dapper 有一个解决方案,DynamicParameters 来拯救!

您可以像这样构建查询:

var queryParams = new DynamicParameters();
foreach (var productKeys in productKeysByRelationId)
{
    sql = sql + $" ... AND ManufacturerProductCode in @ProductCodeList{i} )";
    queryParams.Add($"ProductCodeList{i}", productKeys.Value);
    i++;
}

现在您的查询参数格式正确,您可以这样做:

var productsList = conn.Query<Product>(sql, queryParams).ToList();

这应该可以解决问题,但您确实应该也尝试参数化 ManufacturerRelationId。这不仅仅是关于 SQL 注入,可能还有一些 SQL 缓存性能相关的东西。 您还可以通过使用 Dapper.Contrib.

中的 SqlBuilder 使代码更加清晰