Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

366
Views
How to nest transactions in EF Core 6?

I am already using transactions inside my repository functions in some cases because I sometimes need to insert data into two tables at once and I want the whole operation to fail if one of the inserts fails.

Now I ran into a situation where I had to wrap calls to multiple repositories / functions in another transaction, but when one of those functions already uses a transaction internally I will get the error The connection is already in a transaction and cannot participate in another transaction. I do not want to remove the transaction from the repository function because this would mean that I have to know for which repository functions a transaction is required which I would then have to implement in the service layer. On the other hand, it seems like I cannot use repository functions in a transaction when they already use a transaction internally. Here is an example for where I am facing this problem:

// Reverse engineered classes
public partial class TblProject
{
    public TblProject()
    {
        TblProjectStepSequences = new HashSet<TblProjectStepSequence>();
    }
    
    public int ProjectId { get; set; }

    public virtual ICollection<TblProjectStepSequence> TblProjectStepSequences { get; set; }
}

public partial class TblProjectTranslation
{
    public int ProjectId { get; set; }
    public string Language { get; set; }
    public string ProjectName { get; set; }

    public virtual TblProject Project { get; set; }
}

public partial class TblProjectStepSequence
{
    public int SequenceId { get; set; }
    public int ProjectId { get; set; }
    public int StepId { get; set; }
    public int SequencePosition { get; set; }

    public virtual TblStep Step { get; set; }
    public virtual TblProject Project { get; set; }
}

// Creating a project in the ProjectRepository
public async Task<int> CreateProjectAsync(TblProject project, ...)
{
    using (var transaction = this.Context.Database.BeginTransaction())
    {
        await this.Context.TblProjects.AddAsync(project);
        await this.Context.SaveChangesAsync();
        // Insert translations... (project Id is required for this)
        await this.Context.SaveChangesAsync();
        transaction.Commit();
        
        return entity.ProjectId;
    }
}

// Creating the steps for a project in the StepRepository
public async Task<IEnumerable<int>> CreateProjectStepsAsync(int projectId, IEnumerable<TblProjectStepSequence> steps)
{
    await this.Context.TblProjectStepSequences.AddRangeAsync(steps);
    await this.Context.SaveChangesAsync();

    return steps.Select(step =>
    {
        return step.SequenceId;
    }
    );
}

// Creating a project with its steps in the service layer
public async Task<int> CreateProjectWithStepsAsync(TblProject project, IEnumerable<TblProjectStepSequence> steps)
{
    // This is basically a wrapper around Database.BeginTransaction() and IDbContextTransaction
    using (Transaction transaction = await transactionService.BeginTransactionAsync())
    {
        int projectId = await projectRepository.CreateProjectAsync(project);
        await stepRepository.CreateProjectStepsAsync(projectId, steps);

        return projectId;
    }
}

Is there a way how I can nest multiple transactions inside each other without already knowing in the inner transactions that there could be an outer transaction? I know that it might not be possible to actually nest those transactions from a technical perspective but I still need a solution which either uses the internal transaction of the repository or the outer one (if one exists) so there is no way how I could accidentally forget to use a transaction for repository functions which require one.

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

You could check the CurrentTransaction property and do something like this:

var transaction = Database.CurrentTransaction ?? Database.BeginTransaction()

If there is already a transaction use that, otherwise start a new one...

Edit: Removed the Using block, see comments. More logic is needed for Committing/Rollback the transcaction though...

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!