< Summary

Information
Class: OzonRepositories.Utils.TransactionHelper
Assembly: OzonRepositories
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonRepositories/Utils/TransactionHelper.cs
Line coverage
83%
Covered lines: 51
Uncovered lines: 10
Coverable lines: 61
Total lines: 130
Line coverage: 83.6%
Branch coverage
75%
Covered branches: 15
Total branches: 20
Branch coverage: 75%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteInTransactionAsync()100%11100%
<ExecuteInTransactionAsync()87.5%88100%
ExecuteInTransaction(...)100%1187.5%
ExecuteInTransactionAsync()100%11100%
<ExecuteInTransactionAsync()62.5%11862.5%
TryRollbackAsync()100%2266.66%
TryRollback(...)50%3250%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonRepositories/Utils/TransactionHelper.cs

#LineLine coverage
 1using System.Data;
 2using Microsoft.EntityFrameworkCore;
 3using Microsoft.EntityFrameworkCore.Storage;
 4
 5namespace OzonRepositories.Utils
 6{
 7    /// <summary>
 8    /// Helper для работы с транзакциями в контексте retry strategy.
 9    /// Используйте этот класс когда нужно выполнить операции в транзакции с поддержкой retry.
 10    /// </summary>
 11    public static class TransactionHelper
 12    {
 13        /// <summary>
 14        /// Выполняет операцию в транзакции с поддержкой retry strategy.
 15        /// Используйте этот метод вместо BeginTransaction() когда включен EnableRetryOnFailure.
 16        /// </summary>
 17        /// <typeparam name="TResult">Тип результата операции</typeparam>
 18        /// <param name="context">Контекст базы данных</param>
 19        /// <param name="operation">Операция для выполнения в транзакции</param>
 20        /// <returns>Результат операции</returns>
 21        public static async Task<TResult> ExecuteInTransactionAsync<TResult>(
 22            DbContext context,
 23            Func<IDbContextTransaction, Task<TResult>> operation)
 24        {
 325            var strategy = context.Database.CreateExecutionStrategy();
 326            return await strategy.ExecuteAsync(async () =>
 327            {
 328                await using var transaction = await context.Database.BeginTransactionAsync();
 329                try
 330                {
 331                    var result = await operation(transaction);
 132                    await transaction.CommitAsync();
 133                    return result;
 334                }
 235                catch
 336                {
 237                    await TryRollbackAsync(context, transaction);
 238                    throw;
 339                }
 340            });
 241        }
 42
 43        /// <summary>
 44        /// Выполняет операцию в транзакции с поддержкой retry strategy (синхронная версия).
 45        /// </summary>
 46        /// <typeparam name="TResult">Тип результата операции</typeparam>
 47        /// <param name="context">Контекст базы данных</param>
 48        /// <param name="operation">Операция для выполнения в транзакции</param>
 49        /// <returns>Результат операции</returns>
 50        public static TResult ExecuteInTransaction<TResult>(
 51            DbContext context,
 52            Func<IDbContextTransaction, TResult> operation)
 53        {
 154            var strategy = context.Database.CreateExecutionStrategy();
 155            return strategy.Execute(() =>
 156            {
 157                using var transaction = context.Database.BeginTransaction();
 158                try
 159                {
 160                    var result = operation(transaction);
 061                    transaction.Commit();
 062                    return result;
 163                }
 164                catch
 165                {
 166                    TryRollback(context, transaction);
 167                    throw;
 168                }
 169            });
 70        }
 71
 72        /// <summary>
 73        /// Выполняет операцию в транзакции без возвращаемого значения с поддержкой retry strategy.
 74        /// </summary>
 75        /// <param name="context">Контекст базы данных</param>
 76        /// <param name="operation">Операция для выполнения в транзакции</param>
 77        public static async Task ExecuteInTransactionAsync(
 78            DbContext context,
 79            Func<IDbContextTransaction, Task> operation)
 80        {
 181            var strategy = context.Database.CreateExecutionStrategy();
 182            await strategy.ExecuteAsync(async () =>
 183            {
 184                await using var transaction = await context.Database.BeginTransactionAsync();
 185                try
 186                {
 187                    await operation(transaction);
 088                    await transaction.CommitAsync();
 089                }
 190                catch
 191                {
 192                    await TryRollbackAsync(context, transaction);
 193                    throw;
 194                }
 195            });
 096        }
 97
 98        private static async Task TryRollbackAsync(DbContext context, IDbContextTransaction transaction)
 99        {
 100            try
 101            {
 3102                if (context.Database.GetDbConnection().State == ConnectionState.Open)
 103                {
 1104                    await transaction.RollbackAsync();
 105                }
 3106            }
 0107            catch
 108            {
 109                // Подавляем ошибку отката (например, если соединение было сброшено или разорвано).
 110                // Это предотвращает маскирование оригинального исключения и сохраняет работу EF Core retry strategy.
 0111            }
 3112        }
 113
 114        private static void TryRollback(DbContext context, IDbContextTransaction transaction)
 115        {
 116            try
 117            {
 1118                if (context.Database.GetDbConnection().State == ConnectionState.Open)
 119                {
 0120                    transaction.Rollback();
 121                }
 1122            }
 0123            catch
 124            {
 125                // Подавляем ошибку отката
 0126            }
 1127        }
 128    }
 129}
 130