如何在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
相关产品推荐
相关产品推荐

