You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Merge查询中返回插入或更新的记录ID

问题

我的数据库包含两张表:dbo.Customers和dbo.Images。其中Images表的OwnerId与Customers表存在外键关联,OwnerType用于标识关联的表名。

需求为:当Images表中存在匹配记录时进行更新,不存在则插入新记录。目前已通过Merge查询实现该逻辑,但需额外执行一次查询获取插入/更新的记录ID,希望能在Merge查询中直接返回该ID,避免额外的数据库调用。

当前实现代码如下:

public async Task<int> GetInsertedUpdatedId(int customerId, string imageUrl, CancellationToken cancellationToken)
{
    await db.Images
            .Merge()
            .Using(new[] { new { OwnerId = customerId} })
                 .On((_new, old) => _new.OwnerId == old.OwnerId)
                 .UpdateWhenMatched((old, _new) => new Image
                     {
                          ImageUrl = Image.ImageUrl,                                                
                          UpdatedAt = Sql.CurrentTimestampUtc
                     })
                 .InsertWhenNotMatched(_new => new Image
                     {
                          OwnerId = _new.OwnerId,
                          OwnerType = ImageOwnerType.Customer,                                                
                          CreatedAt = Sql.CurrentTimestampUtc,
                          UpdatedAt = Sql.CurrentTimestampUtc,
                     })              
            .MergeAsync(cancellationToken);
 
    int insertedOrUpdatedId = await db.Images
                 .Where(x => x.OwnerId == customerId)
                 .Select(x => x.Id)
                 .FirstOrDefaultAsync(cancellationToken);
    return insertedOrUpdatedId;
}
解决方案

可以借助SQL MERGE语句的OUTPUT子句,在EF的Merge操作中直接返回插入或更新的记录ID,无需额外查询。具体修改如下:

public async Task<int> GetInsertedUpdatedId(int customerId, string imageUrl, CancellationToken cancellationToken)
{
    var recordId = await db.Images
        .Merge()
        .Using(new[] { new { OwnerId = customerId, ImageUrl = imageUrl } })
            .On((_new, old) => _new.OwnerId == old.OwnerId)
            .UpdateWhenMatched((old, _new) => new Image
                {
                    ImageUrl = _new.ImageUrl,
                    UpdatedAt = Sql.CurrentTimestampUtc
                })
            .InsertWhenNotMatched(_new => new Image
                {
                    OwnerId = _new.OwnerId,
                    OwnerType = ImageOwnerType.Customer,
                    CreatedAt = Sql.CurrentTimestampUtc,
                    UpdatedAt = Sql.CurrentTimestampUtc,
                    ImageUrl = _new.ImageUrl
                })
        .Output(inserted => inserted.Id, updated => updated.Id)
        .FirstOrDefaultAsync(cancellationToken);

    return recordId ?? 0; // 根据业务需求调整默认返回值
}

关键说明

  • Output(inserted => inserted.Id, updated => updated.Id):对应SQL中的OUTPUT INSERTED.Id, DELETED.Id,EF会自动处理插入或更新场景,返回对应记录的ID。
  • 直接通过FirstOrDefaultAsync获取结果,省去了第二次查询数据库的开销,提升了执行效率。
  • 修正了原代码中的两处问题:Cancellationtoken拼写错误应为CancellationToken,Image.ImageUrl需改为_new.ImageUrl以正确引用传入的图片地址。

内容的提问来源于stack exchange,提问作者user3920526

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 02:51:23