Home > Net >  EF core error with transaction but not using trasactions
EF core error with transaction but not using trasactions

Time:12-16

Recently one of our tester reported an error on our app. this error seems to be related to EF core transaction but we are not using transaction in our code. But we didn't use transaction at all on this app.

This issue seems occurs at random, when multiple user are connected on our app.

The error is:

Error : System.invalidOperationException
BeginExecuteReader require the command to have a transaction when the connection assigned to the command is in a pending local transaction. 
The transaction property of the command has not been initialized.

And from the stack trace this error occurs when we simply do in a class called "SurveyOperations":

Survey surveyToSave = await _context.Surveys.FindAsync(id);

in details:

The _context is initialized using asp.net core Dependency injection in the SurveyOperations constructor.

In the startup.cs, SurveyOperations is scoped as "Transient" and the DB connection also. 100% of our EF core calls are async.

We got this error on a Blazor component where we inject SurveyOperations using OwningComponentBase:

@using Microsoft.Extensions.DependencyInjection
@inherits OwningComponentBase

@code{
   private SurveyOperations _surveyOperations;
   private Survey survey;

   protected override async Task OnInitializedAsync()
   {
       _surveyOperations = ScopedServices.GetRequiredService<SurveyOperations>();
      survey = await _surveyOperations.GetSurveyAsync(id);
   }

   private async Task HandleValidSubmit()
   {
      // Get sone data from the form on the component

      await _surveyOperations.SaveSurvey(survey);

   }
}
```

We suspect that EF core is reusing connections but we didn't know how to avoid that.

CodePudding user response:

It seems to me that your design is wrong, and the use of OwningComponentBase does not secure you from the issues aroused from using the DbContext in Blazor. You may resolve this issue in either using the following:

@inherits OwningComponentBase<AppDbContext>

AppDbContext is your DbContext

Or still better, and more appropriate to your design, implement the IDbContextFactory... in that case, you can configure the dbcontext like this:

builder.Services.AddDbContextFactory<ContactContext>(opt =>
    opt.UseSqlite($"Data Source={nameof(ContactContext.ContactsDb)}.db"))

See here full explanation: full explanation

And in your SurveyOperations service you can do something like this:

public SurveyOperations(IDbContextFactory<ContactContext> factory)
{
    DbFactory = factory;
}

And in your various methods you can do something like this:

using var _context = DbFactory.CreateDbContext();    

Survey surveyToSave = await _context.Surveys.FindAsync(id);

Note that the second option render the use of OwningComponentBase superfluous.

  • Related