代码之家  ›  专栏  ›  技术社区  ›  B-Ray

C Web API多个方法调用方写入数据库

  •  1
  • B-Ray  · 技术社区  · 6 年前

    我希望有人能帮我把这个方法写得更好。这个方法一直工作,直到我有多个用户同时点击这个方法。我开始使用Async/Wait,但我不知道它是否适合我。最大的问题是我们有一个保存到的临时/工作表,然后对该表执行一个存储过程,该存储过程执行一些操作,并在完成后清除该表。表中的数据是特定于用户的,因此我们只需要其中的数据就可以让用户执行存储过程。如果有其他数据进入,就会把事情搞砸。这就是为什么在我们继续之前,我要检查确保桌子是空的。

    简言之,我如何才能使这个方法以真正的RESTful方式工作,并为许多用户提供可伸缩性?

    [HttpPost, Route("api/SubmitOrder")]
    public IHttpActionResult SubmitOrderEntry([FromBody] OrderRequest request)
    {
        var profileObjs = OrderEntities.Set<OrderStaging>();
        foreach (var s in request.Items)
        {
            OrderStaging orderObj = new OrderStaging();
    
            orderObj.OrderName = request.OrderName;
            orderObj.OrderDescription = request.OrderDescription;
            orderObj.OrderComments = request.Comments;
            orderObj.EnteredBy = request.EnteredBy;
            //and many more
    
            profileObjs.Add(orderObj);
        }
    
        try
        {
            bool tableEmpty = false;
            int count = 0;
            int countMax = 180;
    
            while (!tableEmpty && count < countMax)
            {
                count++;
                if (!OrderEntities.OrderStagings.Any())
                {
                    tableEmpty = true;
                }
                else
                {
                    System.Threading.Thread.Sleep(5000);
                }
            }
    
            if (tableEmpty)
            {
                OrderEntities.Configuration.EnsureTransactionsForFunctionsAndCommands = false;
                OrderEntities.Database.CommandTimeout = 180;
                OrderEntities.SaveChanges();
    
                if (request.Pending)
                {
                    var result = OrderEntities.SPPENDING();
                    var firstRow = result.FirstOrDefault();
                    String[] returnValue = new String[] { firstRow.TransactionID, firstRow.ExternalOrderID };
                    return Ok(returnValue);
                }
                else
                {
                    var result = OrderEntities.SPORDER();
                    var firstRow = result.FirstOrDefault();
                    String[] returnValue = new String[] { firstRow.TransactionID, firstRow.ExternalOrderID };
                    return Ok(returnValue);
                }
            }
    
            return Content(HttpStatusCode.BadRequest, "SQL Server Exception");
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return Content(HttpStatusCode.BadRequest, "SQL Server Exception");
        }
    } 
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Steve Py    6 年前

    你很可能想重新考虑一下你的方法。听起来您有一个现有的解决方案,它涉及一个处理这些分段记录的存储过程,可能需要一些时间才能完成。存储过程假定所有临时记录都与它要处理的任务相关。在存储过程运行时对多个请求进行排队将导致问题。

    您应该考虑的第一件事是将调用分成两部分:1。准备数据。2.第2条。投票结果。不要让API调用静坐等待存储过程完成,让它返回一个结果,指示数据是否已成功转移,并且客户机代码可以移交给第2部分,该部分对该作业的结果进行轮询。轮询可以针对单个作业ID,也可以基于上次轮询日期/时间和自该日期/时间以来修改的轮询记录。(这允许客户端“查看”其他用户启动的作业(如果适用)

    对于临时存储过程,应将作业标识符添加到临时表中。临时表中的每一行都有一个作业ID,作业记录跟踪有关请求的一些基本详细信息,包括:请求是什么时候开始的?谁开始的?完成了吗?它的状态是什么?(排队、开始、完成、失败等)失败的原因是什么?(如果适用)应使用作业ID启动存储过程,或者查询任何未开始的作业并处理该作业或作业组的临时记录。当存储过程完成一组记录的处理后,它将更新作业行,并清除临时记录。我甚至会考虑将临时记录清除到每天下班后运行的计划任务,以避免在该表上的数据库中出现不必要的锁。(删除每晚已完成/失败的临时行和/或作业。)

    寻找设计系统来扩展多个可以同时成功处理的请求,或者流程的所有步骤都可以按顺序识别和处理,但在前一个请求完成之前,不能将一个请求排队。