如何在只对数据库进行一次查询的计数器字段上进行 +1?

Posted

技术标签:

【中文标题】如何在只对数据库进行一次查询的计数器字段上进行 +1?【英文标题】:How to do a +1 on a counter field with only one query to the db? 【发布时间】:2016-03-04 19:03:23 【问题描述】:

我有一个字段,用于计算用户的订阅总数。现在我像这样更新这个字段:

using (var context = new AppDbContext())

    var foundEntry = context.Users.Find(id);
    if (foundEntry != null)
    
        foundEntry.TotalSubscriptions = foundEntry.TotalSubscriptions + 1;
        context.Entry(foundEntry).CurrentValues.SetValues(foundEntry);

        var result = context.SaveChanges();
    

但是这样我必须对数据库进行 2 次查询。一个用于获取当前总计数,另一个用于更新值。

有没有办法通过实体框架只对数据库进行一次查询来做到这一点?

我想尝试这样的事情:

var user = new User()  Id = userId, TotalSubscriptions = currentS + 1 ;
db.Users.Attach(user);
db.Entry(user).Property(x => x.TotalSubscriptions).IsModified = true;

但我面临的问题是我必须先获取当前计数,但不知道如何在单个查询中执行。我认为使用原始 SQL 语句/查询可以对此进行 1 次查询。

我正在尝试归档类似这样的内容:https://***.com/a/2762856/1286942,但使用实体框架。

更新

我也试过这样的:

var user = new User()  Id = userId ;
db.Users.Attach(user);
user.TotalSubscriptions = context.Entry(user)
.Property(u => u.TotalSubscriptions).OriginalValue + 1;
db.Entry(user).Property(x => x.TotalSubscriptions).IsModified = true;

但问题是.OriginalValue.OriginalValue 总是返回0。所以TotalSubscriptions 字段总是更新为-1 或1。

更新 #2

现在我只看到这个选项:

var numberOfUpdatedRows = context.Database
.ExecuteSqlCommand("UPDATE dbo.Users 
SET TotalSubscriptions = TotalSubscriptions + 1 
WHERE id = " + id + "");

【问题讨论】:

无法直接使用 EF 执行此操作。您要么必须运行一些原始 SQL(即 UPDATE)或调用存储过程。 在最坏的情况下,我猜我仍然可以执行原始 SQL 语句。 @JoSmo,微软建议使用 Raw SQL 进行批量更新 【参考方案1】:

此类代码的基本方法是为您的 SQL 代码使用存储过程,并将变量值传递给该过程。这是您的问题的可能解决方案。

CREATE PROCEDURE AdjustSubscriptions 
    @userid int,
    @adjustment int
AS
BEGIN
    DECLARE @subs int
    SET NOCOUNT ON

    UPDATE UserInfo
    SET @subs = currentS + @adjustment, currentS = @subs
    WHERE userID = @userid

    SELECT @subs AS SubscriptionCount
END

这会将 currentS 值选择到一个变量中,按照@adjustment 中的值指定对其进行调整,(添加三个订阅?传递一个三。删除三个订阅?传递一个负三)然后将值更新到保存的行.最后,返回仅包含调整后的 subscriptionCount 值的行。

可以重写存储过程以在 OUTPUT 变量中返回值(如果实施正确,您只需将值返回到变量中,而不必处理记录集),甚至可以使用语句 RETURN @subs在程序结束时将调整后的值作为返回值返回。我强烈建议您不要使用 RETURN @subs 方法,因为它会在返回字符串或 smallint 之外的值时中断。

我让你来实现实体框架代码来处理存储过程。我不相信您可以在实体框架中使用一次调用对值进行相同的直接操作,但我完全愿意以其他方式显示。

快乐编码。

【讨论】:

这个问题被标记在 entity framework ,因此需要与 ef 相关的答案 它也被标记为sql-server,这是我提供的答案的一部分。作为一个严肃的问题 - 答案是否必须针对所有标签? 如果您看到更新 #2 本身解决了问题,但他仍然发布问题是期待关于实体框架的答案。

以上是关于如何在只对数据库进行一次查询的计数器字段上进行 +1?的主要内容,如果未能解决你的问题,请参考以下文章

Prometheus 查询 promql 以在同一字段上进行平均

如何通过查询在 AWS AppSync 中的嵌套字段上进行筛选

我应该执行多个 sql 查询还是一个大型查询并在服务器上进行处理?

如何提高 SQL Server 查询的性能以选择具有值的行不在子查询中的一次计数

大数据之-HIVE入门(十二)

solr 查询的相关配置