Истекло время ожидания в ядре EF при использовании одновременных транзакций DBContext - PullRequest
0 голосов
/ 08 февраля 2019

Я использую проект ASP.NET Core 2.1 Web API, разработанный с архитектурой доменного управления.

У меня есть два контекста БД, AppDbContext используется Asp.net Identity (для пользователя и ролиуправление, как используется UserManager), и Sprint1DbContext используется для транзакций других таблиц.

В файле startup.cs я использовал:

  string constring =  Configuration.GetValue<string>("DBConnectionString");
      services.AddDbContext<ApplicationDbContext>(options =>
              options.UseSqlServer(constring));



  services.AddIdentity<ApplicationUser, ApplicationRole>()
         .AddEntityFrameworkStores<ApplicationDbContext>()
         .AddDefaultTokenProviders();

  services.AddDbContext<Sprint1DbContext>
    (options =>  options
    .UseLazyLoadingProxies()
  .UseSqlServer(constring
 // , sqlServerOptions => sqlServerOptions.CommandTimeout(120) this is not worked
  )

//_dbContext is Sprint1DbContext 
// _appDbContext is AppDbContext 

Я использовал следующие строки в своем классе CustomActionFilterAttribute:

public override void OnActionExecuting(ActionExecutingContext context)
    {

      _dbContext.Database.BeginTransaction();

    }  

public override void OnActionExecuted(ActionExecutedContext context)
{
 if (context.Exception == null)
      {
        _dbContext.Database.CommitTransaction();

      }
      else
      {

        _dbContext.Database.RollbackTransaction();

   }
}

В классе обслуживания я использую следующий бизнес-код:

// Some code
// creating Bill of the customer
 await billToDataRepository.Add(billTo);
 // some code

// creating new customer’s data AspNetUser, Role, and it Account record
 ApplicationUser user = new ApplicationUser
      {
        Name = model.FName + " " + model.LName,
        UserName = model.Email,
        Email = model.Email,
        PhoneNumber=model.PrimaryPhone,
      };
      // creating AspNetuser
      IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault);

  // some code for assigning the role to a user

  var account = new Account
      {
        Id = Guid.NewGuid(),
        FName = model.FName,
        LName = model.LName,
        AccountType = EnumAccountType.Customer,
        AspNetUserId = user.Id,
      };
 await accountDataRepository.Add(account);

// other application business logic

Вышеуказанный метод Add определен в DataRepository классе:

public class DataRepository<TEntity> : IDataRepository<TEntity>
         where TEntity :  DomainEntity
  {
  public async Task<TEntity> Add(TEntity entity)
    {

      if (entity == null)
        throw new ArgumentException("entity is null");

      return await Task.Run(() =>
      {
        try
        {
          Context.Set<TEntity>().Add(entity);
          Context.SaveChanges();
        }
        catch (Exception e)
        {
          throw;
        }
        return entity;
      });

}
}

Если в бизнес-логике другого приложения возникнет какое-либо исключение, мне придется все откатить.Поскольку я использовал только _dbContext.Database.RollbackTransaction(), он откатывает только те записи, которые созданы _dbContext.Это не возвращает ApplicationUser и Role вещи, созданные _appDbContext (userManager и RoleManager).Итак, снова я обновил свой CustomActionFilterAttribute класс.

public override void OnActionExecuting(ActionExecutingContext context)
    {

      _dbContext.Database.BeginTransaction();
           _appdbContext.Database.BeginTransaction();

    }  

public override void OnActionExecuted(ActionExecutedContext context)
{
 if (context.Exception == null)
      {
        _dbContext.Database.CommitTransaction();
                _appdbContext.Database.CommitTransaction();

      }
      else
      {

        _dbContext.Database.RollbackTransaction();
                _appdbContext.Database.RollbackTransaction();

   }
}

После записи BeginTransaction для _appdbContext, когда я выполняю тот же код класса обслуживания, я получаю ошибку тайм-аута наследующий код:

 await accountDataRepository.Add(account);

Этот метод Add вызывает метод Add класса DataRepository означает, что исключение происходит в следующей строке, вызываемой методом accountDataRepository.Add:

Context.Set<TEntity>().Add(entity);
          Context.SaveChanges();

"errorDetail":"Microsoft.EntityFrameworkCore.DbUpdateException: An error occurred while updating the entries. See the inner exception for details. ---> System.Data.SqlClient.SqlException: Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.\r\nThe statement has been terminated. ---> System.ComponentModel.Win32Exception: The wait operation timed out\r\n

Хотя функция RollbackTransaction в обоих контекстах (_dbContext & _appdbContext) работает нормально и данные возвращаются, но я недалее.

Итак, подведем итог:

Задача 1

Если я использую

_dbContext.Database.BeginTransaction();

_dbContext.Database.CommitTransaction();

 _dbContext.Database.RollbackTransaction();


await billToDataRepository.Add(billTo); //record created and rollback
// unable to rollback 
IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault);  //record created and but not rollback
await accountDataRepository.Add(account);   //record created and rollback

Задача 2

В порядкеЧтобы решить проблему 1, я использовал:

 _dbContext.Database.BeginTransaction();
           _appdbContext.Database.BeginTransaction();

    _dbContext.Database.CommitTransaction();
                _appdbContext.Database.CommitTransaction();


   _dbContext.Database.RollbackTransaction();
                _appdbContext.Database.RollbackTransaction();


await billToDataRepository.Add(billTo);//record created and rollback

IdentityResult result = await userManager.CreateAsync(user, Constants.PasswordDefault); //record created and rollback

await accountDataRepository.Add(account);

//Which calling 

Context.Set<TEntity>().Add(entity);
          Context.SaveChanges();
    //Unable to create record, Time out exception occur.

Как я могу это исправить?

...