Ya estoy usando transacciones dentro de mis funciones de repositorio en algunos casos porque a veces necesito insertar datos en dos tablas a la vez y quiero que toda la operación falle si falla una de las inserciones.
Ahora me encontré con una situación en la que tenía que envolver llamadas a múltiples repositorios/funciones en otra transacción, pero cuando una de esas funciones ya usa una transacción internamente, obtendré el error The connection is already in a transaction and cannot participate in another transaction . No quiero eliminar la transacción de la función de repositorio porque esto significaría que tengo que saber para qué funciones de repositorio se requiere una transacción que luego tendría que implementar en la capa de servicio. Por otro lado, parece que no puedo usar funciones de repositorio en una transacción cuando ya usan una transacción internamente. Aquí hay un ejemplo de dónde estoy enfrentando este problema:
// 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; } }¿Hay alguna manera de anidar varias transacciones una dentro de otra sin saber en las transacciones internas que podría haber una transacción externa? Sé que puede que no sea posible anidar esas transacciones desde una perspectiva técnica, pero todavía necesito una solución que use la transacción interna del repositorio o la externa (si existe), así que no hay forma de que pueda accidentalmente Olvídese de usar una transacción para las funciones de repositorio que lo requieran.
Puede verificar la propiedad CurrentTransaction y hacer algo como esto:
var transaction = Database.CurrentTransaction ?? Database.BeginTransaction()Si ya hay una transacción, utilícela; de lo contrario, inicie una nueva...
Editar: se eliminó el bloque Uso, ver comentarios. Sin embargo, se necesita más lógica para Confirmar/Revertir la transacción...