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

如何在判别联合的Match/Switch循环中实现提前返回?

批量更新接口复用单条更新函数的实现问题

问题描述

我正在编写一个包含单条和多条数据更新接口的API,希望在批量更新接口中复用单条更新函数,通过循环处理所有待更新项。单条更新函数借助OneOf实现判别联合,有三种返回值:

  • 更新后的条目
  • 条目不存在时返回OneOf.NotFound实例
  • 出现其他问题(如验证错误)时返回OneOf.Error实例

我希望在批量更新接口中,一旦某条数据更新出错就提前返回。尝试使用OneOf提供的Match和Switch方法,但未能实现预期行为。以下是当前的接口代码:

routes.MapPut(RouteBases.ShoppingList, async (IEnumerable<ShoppingListItem> itemsToUpdate, MariaDbContext dbContext) =>
{
    var storedItems = new List<ShoppingListItem>();
    var failedItems = new List<ShoppingListItem>();
    var state = (storedItems, failedItems);
    foreach (var item in itemsToUpdate)
    {
        var updateResult = await UpdateItem(item, dbContext);
        state = updateResult.Match<(IEnumerable<ShoppingListItem>, IEnumerable<ShoppingListItem>)>(
            storedItem => (storedItems.Append(storedItem), failedItems),
            notFound => (storedItems, failedItems.Append(item)),
            error => { return Results.BadRequest(); }
            );
    }

    await dbContext.SaveChangesAsync();

    return Results.Ok(new BulkUpdateResult(storedItems, failedItems));
});

显然,Match中的error分支无法编译,因为返回类型不匹配,但该分支体现了我想要的行为。请问如何正确实现,或者我的思路是否存在根本性问题?

附言:撰写此问题时我意识到,仅在出错时提前返回可能与条目不存在的情况不一致。我或许应该改为不提前返回并汇总所有错误,或者在遇到NotFound时也提前返回。对于这个API,我可能会选择汇总结果,但仍想了解如何实现提前返回的方案,因为在其他类似场景(如循环中存在高开销调用)可能需要该功能。


解决方案

方案一:遇到错误提前返回

OneOf的Match方法要求所有分支返回相同类型,因此无法在Match分支中直接返回ActionResult。我们可以通过判断OneOf的具体类型,在循环内直接跳出并返回响应,同时通过事务保证数据一致性(避免部分更新提交):

routes.MapPut(RouteBases.ShoppingList, async (IEnumerable<ShoppingListItem> itemsToUpdate, MariaDbContext dbContext) =>
{
    var storedItems = new List<ShoppingListItem>();
    var failedItems = new List<ShoppingListItem>();

    // 开启事务,确保出错时回滚所有已执行的更新
    using var transaction = await dbContext.Database.BeginTransactionAsync();
    try
    {
        foreach (var item in itemsToUpdate)
        {
            var updateResult = await UpdateItem(item, dbContext);

            if (updateResult.IsT0) // 匹配"更新后的条目"分支
            {
                storedItems.Add(updateResult.AsT0);
            }
            else if (updateResult.IsT1) // 匹配"条目不存在"分支
            {
                failedItems.Add(item);
            }
            else if (updateResult.IsT2) // 匹配"其他错误"分支
            {
                // 回滚事务,提前返回错误响应
                await transaction.RollbackAsync();
                return Results.BadRequest(updateResult.AsT2.Message); // 假设Error类型包含Message属性
            }
        }

        // 所有条目处理完成,提交事务
        await dbContext.SaveChangesAsync();
        await transaction.CommitAsync();

        return Results.Ok(new BulkUpdateResult(storedItems, failedItems));
    }
    catch (Exception ex)
    {
        // 捕获意外异常,回滚事务
        await transaction.RollbackAsync();
        return Results.StatusCode(StatusCodes.Status500InternalServerError);
    }
});

方案二:汇总所有结果(适合当前API场景)

如果选择汇总所有成功、NotFound和错误结果再统一返回,可以使用OneOf的Switch方法分别处理每个分支,收集状态后再生成响应:

routes.MapPut(RouteBases.ShoppingList, async (IEnumerable<ShoppingListItem> itemsToUpdate, MariaDbContext dbContext) =>
{
    var storedItems = new List<ShoppingListItem>();
    var notFoundItems = new List<ShoppingListItem>();
    var errorItems = new List<(ShoppingListItem Item, string ErrorMessage)>();

    foreach (var item in itemsToUpdate)
    {
        var updateResult = await UpdateItem(item, dbContext);
        // 用Switch分发不同分支的处理逻辑
        updateResult.Switch(
            storedItem => storedItems.Add(storedItem),
            _ => notFoundItems.Add(item),
            error => errorItems.Add((item, error.Message))
        );
    }

    // 根据业务需求决定是否提交更新:
    // 示例1:存在错误则不提交任何更新,返回错误详情
    if (errorItems.Any())
    {
        return Results.BadRequest(new 
        { 
            SuccessCount = storedItems.Count,
            NotFoundCount = notFoundItems.Count,
            Errors = errorItems
        });
    }

    // 示例2:无错误则提交所有成功的更新,返回汇总结果
    await dbContext.SaveChangesAsync();
    return Results.Ok(new BulkUpdateResult(storedItems, notFoundItems));
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.17 00:59:53