0

Does anyone have an idea if it is possible to implement the retry pattern with SaveChangesInterceptor interceptor?

Here is the SavingChangesAsync method.

  public override async ValueTask<InterceptionResult<int>> SavingChangesAsync(DbContextEventData eventData, InterceptionResult<int> result,
        CancellationToken cancellationToken = new CancellationToken())
    {
        int tryCount = 0;
        while (tryCount < _maxRetries)
        {
            try
            {
                return await new ValueTask<InterceptionResult<int>>(result); //it doesn't cause an exception.
            }
            catch (DbUpdateConcurrencyException ex)
            {
                if (ex.Entries.All(e => e.Entity.GetType() != typeof(TEntity)))
                {
                    throw;
                }

                Console.WriteLine(tryCount);

                foreach (var entry in ex.Entries)
                {
                    if (entry is TEntity)
                    {
                        await entry.ReloadAsync(cancellationToken);
                    }
                }

                await Task.Delay(_delay, cancellationToken);
            }
            catch (DbUpdateException ex)
            {
                Console.WriteLine("Testing");
            }

            tryCount += 1;
        }

        throw new DbUpdateConcurrencyException($"The maximum number of retries {_maxRetries} has been exceeded.");
    }

also I implemented the SaveChangesFailedAsync method.

        public override async Task SaveChangesFailedAsync(DbContextErrorEventData eventData,
        CancellationToken cancellationToken = new CancellationToken())
    {

        if (eventData.Exception is DbUpdateConcurrencyException myException)
        {
            await Task.Delay(_delay, cancellationToken);
            foreach (var entry in myException.Entries)
            {
                await entry.ReloadAsync(cancellationToken);
            }

            try
            {
                await eventData.Context.SaveChangesAsync(cancellationToken);
                InterceptionResult.Suppress();
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }

        }

    }

BTW, I know there is a usual way to handle that. inherit from DBContext and override savechanges, and I am using EF Core 5.0.

M.Aslzad
  • 68
  • 9
  • Probably you are looking for [ISaveChangesInterceptor](https://devblogs.microsoft.com/dotnet/announcing-ef7-preview7-entity-framework/#optimistic-concurrency-interception) which is introduced in EF Core 7 – Svyatoslav Danyliv Apr 26 '23 at 16:08
  • @SvyatoslavDanyliv Actually, [ISaveChangesInterceptor](https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.diagnostics.isavechangesinterceptor?view=efcore-7.0) has existed since EF Core 5, but the `ThrowingConcurrency` method was added in EF Core 7. Since I cannot upgrade EF 5.0 to EF 7, I wanted to implement it with existing methods. – M.Aslzad Apr 27 '23 at 06:44

0 Answers0