簡體   English   中英

EF數據庫事務可以在循環中使用嗎?

[英]Can EF Database Transaction be used in a loop?

我有一個過程,我定期從數據庫中檢索記錄,並對每個記錄運行3個操作。 對於每條記錄,3個操作必須全部成功,或者根本不成功。 如果其中一個操作失敗,我希望提交已經為先前記錄處理的操作,以便下次進程運行時,它會獲取3個事務中的一個失敗的記錄先前。

我想在每個記錄的事務中包裝3個操作,並為每個記錄循環,但我想確保在這種情況下使用數據庫事務是有效的。 以下是我的想法。 這是正確的嗎?

    public async Task OrderCollectionProcessorWorker()
    {
        using (var context = new DbContext())
        {
            try
            {
                IList<Order> ordersToCollect =
                    await context.Orders.Where(
                        x => x.OrderStatusId == OrderStatusCodes.DeliveredId)
                              .ToListAsync(_cancellationTokenSource.Token);

                await ProcessCollectionsAsync(context, ordersToCollect);
            }
            catch (Exception ex)
            {
                Log.Error("Exception in OrderCollectionProcessorWorker", ex);
            }
        }
    }


    /// <summary>
    /// For each order to collect, perform 3 operations
    /// </summary>
    /// <param name="context">db context</param>
    /// <param name="ordersToCollect">List of Orders for collection</param>
    private async Task ProcessCollectionsAsync(DbContext context, IList<Order> ordersToCollect)
    {
        if (ordersToCollect.Count == 0) return;

        Log.Debug($"ProcessCollections: processing {ordersToCollect.Count} orders");

        foreach (var order in ordersToCollect)
        {
            // group the 3 operations in one transaction for each order
            // so that if one operation fails, the operations performend on the previous orders
            // are committed
            using (var transaction = context.Database.BeginTransaction())
            {
                try
                {
                    // *************************
                    // run the 3 operations here
                    // operations consist of updating the order itself, and other database updates
                    Operation1(order);
                    Operation2(order);
                    Operation3(order);

                    // *************************

                    await context.SaveChangesAsync();

                    transaction.Commit();
                }
                catch (Exception ex)
                {
                    transaction?.Rollback();                        
                    Log.Error("General exception when executing ProcessCollectionsAsync on Order " + order.Id, ex);
                    throw new Exception("ProcessCollections failed on Order " + order.Id, ex); 
                }
            }
        }
    }

這似乎是一種正確的方法,除了事實上,在捕獲中你應該重新拋出異常或做一些其他事情來阻止循環的進展(如果我理解你的要求)。 甚至沒有必要使用

var transaction = context.Database.BeginTransaction()

因為

await context.SaveChangesAsync();

創建自己的交易。 您所做的每項更改都存儲在上下文中,當您調用SaveChanges時,會進行事務處理,並且所有更改都將寫為1批。 如果某些內容失敗,則所有更改都將被回滾。 對SaveChanges的另一次調用將對新的更改進行另一次交易。 但請記住,如果事務失敗,您應該不再使用相同的上下文,而是創建一個新的上下文。 總結一下,我會按如下方式編寫您的方法:

private async Task ProcessCollectionsAsync(DbContext context, IList<Order> ordersToCollect)
{
    if (ordersToCollect.Count == 0) return;

    Log.Debug($"ProcessCollections: processing {ordersToCollect.Count} orders");

    foreach (var order in ordersToCollect)
    {
        // group the 3 operations in one transaction for each order
        // so that if one operation fails, the operations performend on the previous orders
        // are committed
        try
        {
            // *************************
            // run the 3 operations here
            // operations consist of updating the order itself, and other database updates
            Operation1(order);
            Operation2(order);
            Operation3(order);

            // *************************

            await context.SaveChangesAsync();
        }
        catch (Exception ex)
        {                     
            Log.Error("General exception when executing ProcessCollectionsAsync on Order " + order.Id, ex);
            throw;
        }
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM