我可能有一个天真的问题,但是我以前从未使用过数据库。我是.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 });
}
该代码可能有错误,因为现在我没有访问工作环境的能力,但是我认为这个主意很明确。因此,问题是这是否是进行查询的最佳方法。如果有更好的选择,那是什么。
答案 0 :(得分:1)
基本上,您可以简单地完成本文中所完成的工作,但是对于表值参数,使用两组而不是1组。 Using Dapper, how do I pass in the values for a sql type as param?
它使用存储过程和sql表值参数。
答案 1 :(得分:0)
如果没有stored procedure
选项,则可以使用以下方法之一。
interestIds
和userIds
转换为字符串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注入攻击的一种诱因(在用户输入的情况下)。 如果使用它,您可以绝对确定自己的数据。
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))