通过多个列的值的多个列表进行SQL搜索

时间:2018-10-09 18:57:50

标签: c# sql .net sql-server dapper

我可能有一个天真的问题,但是我以前从未使用过数据库。我是.NET工程师,并且使用Dapper访问SQL Server数据库。

情况如下:我有一个用于保留几种类型实体的非规范化表。每个都有一个复合键(类型,id,owner_id),并且该键的每一行都是字符串类型(但这并不重要)。而且,比如说,我正在将数据库中许多针对不同用户的兴趣(批量发布)写入到数据库中。为了使它们不再重复,我需要进行查询并确定数据库中已经存在哪些。

因此,我的InterestService类中包含以下代码:

private IEnumerable<Interest> GetAlreadyExistingInterestsFor(IEnumerable<Interest> interestsForCreating) =>
    _interestRepository.GetInterests(interestsForCreating.Select(interest => interest.Id).ToList(),
                                     interestsForCreating.Select(interest => interest.UserId).ToList());

在那之后我有了一些逻辑等等。这不重要。

InterestRepository方法GetInterests如下所示:

public GetInterests(IList<string> interestIds, IList<string> userIds) 
{
    var query = @"SELECT type, id, owner_id
                  FROM entities
                  WHERE type = 'interest'
                   AND id IN @InterestIds
                   AND owner_id IN @UserIds";
    return _dbContext.ExecuteQuery(query, new { InterestIds = interestIds, UserIds = userIds });
}

该代码可能有错误,因为现在我没有访问工作环境的能力,但是我认为这个主意很明确。因此,问题是这是否是进行查询的最佳方法。如果有更好的选择,那是什么。

2 个答案:

答案 0 :(得分:1)

基本上,您可以简单地完成本文中所完成的工作,但是对于表值参数,使用两组而不是1组。 Using Dapper, how do I pass in the values for a sql type as param?

它使用存储过程和sql表值参数。

答案 1 :(得分:0)

如果没有stored procedure选项,则可以使用以下方法之一。

  1. 将您的interestIdsuserIds转换为字符串
    string interests = "(1, 2, 3, 4)"(如果列表仅包含数字)或('a1', 'b1', 'c2')(如果它们是字符串)。

然后将它们内联到您的查询中

var query = @"SELECT type, id, owner_id
              FROM entities
              WHERE type = 'interest'
               AND id IN "+ interests
               + " AND owner_id IN " + users;

该方法被认为是不好的做法,并且是对SQL注入攻击的一种诱因(在用户输入的情况下)。 如果使用它,您可以绝对确定自己​​的数据。

  1. SQL Server 2016+具有内置功能string_split,可在此处使用。该函数将带有分隔符的字符串拆分为表t(value)
    再次将列表转换成字符串string interests="a1, a2, b3, c4";(此处没有单引号)

并查询

var query = @"SELECT type, id, owner_id
              FROM entities
              WHERE type = 'interest'
               AND id IN (select value from string_split(@interests,','))
               AND owner_id IN (select value from string_split(@users,','))";

对于早期版本,您可以创建具有相同功能的UDF。

create function dbo.split_string(@input varchar(max), @separator varchar(2))
returns table as
return
(with cte as(
select cast('<v>'+ REPLACE(@input, @separator, '</v><v>') +'</v>' as xml) x
)
select t.v.value('.[1]', 'varchar(max)') [value]
from cte
cross apply x.nodes('v') t(v))