es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Error de base de datos bloqueada al utilizar BeginTransaction, múltiples repositorios, SQLite, UnitOfWork y Dapper.

Estoy intentando implementar transacciones con SQLite y Dapper pero recibo el error “la base de datos está bloqueada”.

Estoy usando el patrón UnitOfWork sugerido aquí.

Este es el código:

Controller.cs:
“`
public async Task MyMethodAsync()
{
//inyectando unitOfWork pero esta es la implementación
var unitOfWork = new UnitOfWork(new SQLiteConnection(“Data Source=TestDb;Mode=Memory;Cache=Shared”));

using (var connection = unitOfWork.Connection)
{
    connection.Open();

    unitOfWork.Begin();

    var myFirstRepository = new MyFirstRepository(unitOfWork);
    var mySecondRepository = new MySecondRepository(unitOfWork);

    try 
    {
        myFirstRepository.CreateStuff(); //aquí arroja la excepción "la base de datos está bloqueada"

        mySecondRepository.CreateOtherStuff();

        unitOfWork.Commit();
    }
    catch(Exception e)
    {
        unitOfWork.Rollback();
        throw;
    }
}

}

MyFirstRepository.cs:
public class MyFirstRepository
{
private IUnitOfWork _unitOfWork;

public MyFirstRepository(IUnitOfWork unitOfWork) 
{
    _unitOfWork = unitOfWork;
}

public void CreateStuff()
{
    using (var connection = _unitOfWork.Connection)
    {
        connection.Open();
        await connection.ExecuteAsync("INSERT INTO ...", param).ConfigureAwait(false);
    }
}

}

MySecondRepository.cs:
Implementación similar a MyFirstRepository.cs.

¿Alguien tiene alguna idea de lo que me estoy perdiendo aquí?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    El problema aquí es que la conexión se está abriendo dos veces, una vez en el controlador y otra vez en el repositorio. Dado que SQLite solo admite una conexión de escritura a la vez, la base de datos queda bloqueada al abrir la conexión en el controlador y el repositorio al mismo tiempo. Para solucionar este problema, elimine la apertura de la conexión de los repositorios e inyecte la instancia de conexión en el constructor del repositorio. Luego, abra la conexión en el controlador y pase la instancia de conexión abierta a los repositorios. Aquí está el código actualizado:

    Controller.cs:

    public async Task MyMethodAsync()
    {
        var connection = new SQLiteConnection($"Data Source=TestDb;Mode=Memory;Cache=Shared");
    
        //**inyectando el unitOfWork pero esta es la implementación**
        var unitOfWork = new UnitOfWork(connection);
    
        connection.Open();
    
        unitOfWork.Begin();
    
        var myFirstRepository = new MyFirstRepository(unitOfWork, connection);
        var mySecondRepository = new MySecondRepository(unitOfWork, connection);
    
        try 
        {
            myFirstRepository.CreateStuff(); //Aquí arroja la excepción "la base de datos está bloqueada"
    
            mySecondRepository.CreateOtherStuff();
    
            unitOfWork.Commit();
        }
        catch(Exception e)
        {
            unitOfWork.Rollback();
            throw;
        }
        finally
        {
            connection.Close();
        }
    }
    

    MyFirstRepository.cs:

    public class MyFirstRepository
    {
        private IUnitOfWork _unitOfWork;
        private SQLiteConnection _connection;
    
        public MyFirstRepository(IUnitOfWork unitOfWork, SQLiteConnection connection) 
        {
            _unitOfWork = unitOfWork;
            _connection = connection;
        }
    
        public void CreateStuff()
        {
            _connection.Execute("INSERT INTO ...", param);
        }
    }
    

    MySecondRepository.cs:

    public class MySecondRepository
    {
        private IUnitOfWork _unitOfWork;
        private SQLiteConnection _connection;
    
        public MySecondRepository(IUnitOfWork unitOfWork, SQLiteConnection connection) 
        {
            _unitOfWork = unitOfWork;
            _connection = connection;
        }
    
        public void CreateOtherStuff()
        {
            _connection.Execute("INSERT INTO ...", param);
        }
    }
    

    Al abrir la conexión solo una vez en el controlador y compartirla entre los repositorios, nos aseguramos de que solo se use una conexión de escritura a la vez y evitamos el error “la base de datos está bloqueada”.

Comments are closed.