Использование двумерного массива в качестве списка параметров Dapper

#c# #dapper

#c# #dapper

Вопрос:

В Dapper можно запросить список с помощью where, используя этот код:

 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.'

Любые предложения о том, как это сделать?

Ответ №1:

У вас есть несколько проблем с вашим кодом.

Если у вас есть более одного элемента в вашем productKeysByRelationId , вы в конечном итоге получите SQL, подобный:

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

Это вряд ли вернет какие-либо результаты, вам нужно добавить туда несколько ИЛИ.

Ошибка, которую вы получаете, заключается в том, что у вас есть что-то вроде:

 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 also. Речь идет не только о внедрении SQL, могут быть некоторые проблемы, связанные с производительностью кэша SQL.
Вы также можете получить некоторую ясность в коде, используя SqlBuilder от Dapper.Contrib.