使用二维数组作为 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 使代码更加清晰
在 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.