linq 使用QueryAsync将多个参数传递到Dapper查询中

4ktjp1zp  于 2022-12-15  发布在  其他
关注(0)|答案(2)|浏览(232)

我试图参数化查询中的多个值,但总是出错。这是我目前正在处理的问题,在userClientIds参数上出现“必须声明标量变量”错误。有人能帮我找出遗漏的内容吗?

public async Task<IEnumerable<SharedUser>> GetUsersForSharing(Guid userId, Guid 
 templateId, string? searchedEmpName, string? searchedEmpNumber)
 {
     // this is a list of ints, which will need passed into the WHERE IN clause below
     var userClientIds = userClients.Select(client => client.ClientId).ToList();

     var sql = $@"SELECT DISTINCT
            UserId, 
            ClientId,
            FullName,
            EmployeeNumber
        FROM dbo.ClientUser

        WHERE 
            UserId <> @UserId
            AND ClientId in (
                @userClientIds
            )";

        if(searchedEmpName != null)
        {
            sql += $@"AND FullName LIKE '%@searchedEmpName%'";
        }
        if(searchedEmpNumber != null)
        {
            sql += $@"AND EmployeeNumber LIKE '%@searchedEmpNumber%'";
        }
        
        using(var conn = _connectionFactory.GetDbConnection())
        {
            var parameters = new DynamicParameters();
            parameters.Add("@userId", userId.ToString());
            parameters.Add("@userClientIds", new[] { userClientIds });
            parameters.Add("@searchedEmpName", searchedEmpName);
            parameters.Add("@searchedEmpNumber", searchedEmpNumber);
            conn.Open();
            var result = await conn.QueryAsync<SharedUser>(sql, new { parameters });
            return result;
        }
}
djmepvbi

djmepvbi1#

您只需要将整个列表传递给DyanmicParameters,而不需要包含数组,Dapper将为您注入它。
必须删除ClientId in (@userClientIds)的括号(),否则会出现语法错误。
更多注解:

  • 将动态参数直接传递给Query,而不是传递给contining数组。
  • 使用DISTINCT是一种代码气味:为什么你的表格一开始就有重复项?也许你应该改进你的表格设计。
  • userId.ToString()为什么?如果它是Guid,请保持原样。
  • LIKE参数不会像这样工作。相反,您需要将它们 * 在 * SQL $@"AND FullName LIKE '%' + @searchedEmpName + '%'等中连接起来。
  • Dapper将自动为您打开和关闭连接。
public async Task<IEnumerable<SharedUser>> GetUsersForSharing(Guid userId, Guid 
 templateId, string? searchedEmpName, string? searchedEmpNumber)
 {
     var userClientIds = userClients.Select(client => client.ClientId).ToList();

     var sql = $@"
SELECT
  UserId, 
  ClientId,
  FullName,
  EmployeeNumber
FROM dbo.ClientUser
WHERE 
  UserId <> @UserId
  AND ClientId in @userClientIds
";

        if(searchedEmpName != null)
        {
            sql += $@"AND FullName LIKE '%' + @searchedEmpName + '%'
";
        }
        if(searchedEmpNumber != null)
        {
            sql += $@"AND EmployeeNumber LIKE '%' + @searchedEmpNumber + '%'
";
        }
        
        using(var conn = _connectionFactory.GetDbConnection())
        {
            var parameters = new DynamicParameters();
            parameters.Add("@userId", userId);
            parameters.Add("@userClientIds", userClientIds);
            parameters.Add("@searchedEmpName", searchedEmpName);
            parameters.Add("@searchedEmpNumber", searchedEmpNumber);
            var result = await conn.QueryAsync<SharedUser>(sql, parameters);
            return result;
        }
}

如果你有一个很大的列表,那么不要做上面的代码,因为性能会很糟糕,而是使用一个表值参数,并通过.AsTableValuedParameter传递它
首先,创建表类型

CREATE TYPE dbo.IdList (Id int PRIMARY KEY)

然后像这样传球

var table = new DataTable { Columns = {
    { "Id", typeof(int) },
} };
foreach (var id in userClientIds)
    table.Rows.Add(id);

parameters.Add("@userClientIds", table.AsTableValuedParameter("dbo.IdList"));

SQL的语法是

WHERE 
  UserId <> @UserId
  AND ClientId in (SELECT uci.Id FROM @userClientIds uci)
jtjikinw

jtjikinw2#

将客户端ID创建为逗号分隔的字符串;

var clientIds = String.Join(",", userClientIds.Select(i => i.ToString()).ToArray())

然后添加参数:

parameters.Add("@userClientIds", clientIds);

相关问题