对一个事务的多个查询。使用SQLite

时间:2017-03-31 06:32:17

标签: c# sqlite

我正在学习如何使用SQLite,而且我在这个问题上停留了一个多星期,而且我在网络搜索中找不到答案。

问题在于我需要使用相应的行注册账单,并更新已购买产品的一些信息,如果某些查询失败,则在同一事务中进行更新。

当我尝试注册某些内容时,我获得“数据库已被锁定”异常,但我发现奇怪的是我在创建此问题时保持程序运行,当我看到它时我再次发现“继续”按钮可用,然后程序终于有效了。

所以我想知道如果没有那个例外我必须改进。

啊,这是一个Winforms应用程序,只有一个人会使用它,所以它不会出现并发问题(或者我认为是这样)。

首先,这是 connectionString (如果我需要添加内容): “数据源= D:\ De disco c \ Documents \ Visual Studio 2010 \ Projects \ Racion \ Racion \ bin \ Racion.db; Version = 3;”

在法案课程的Mapper上我有这个方法:

public static void registrarFactura(Factura f)
{

    SQLiteConnection conn = null;
    SQLiteTransaction trn = null;

    try
    {

        var parametros = new List<SQLiteParameter>();
        var cant = new SQLiteParameter();
        cant.ParameterName = "@Cliente";
        cant.Value = f.cliente;
        parametros.Add(cant);

        cant = new SQLiteParameter();
        cant.ParameterName = "@Fecha";
        cant.Value = DateTime.Now;

        parametros.Add(cant);
        //Here is one query. I need to know the bill's ID to register the lines and make the update.
        String consulta = "Insert into Factura(Cliente, Fecha)  VALUES (@Cliente, @Fecha); SELECT last_insert_rowid();";


        //Open the connection
        conn = ObtenerConection();


        //begin transaction
        using (trn = conn.BeginTransaction())
        {
            //Here I register the bill and obtain it's id
            int codigo = Convert.ToInt32(Mapper.ejecutaScalar(consulta, CommandType.Text, parametros, conn, trn));

            //Now I must register the lines of the bill

             String consulta2 = "";

            foreach (Linea l in f.lineas)
            {
                parametros = new List<SQLiteParameter>();
                cant = new SQLiteParameter();
                cant.ParameterName = "@NLinea";
                cant.Value = l.numeroLinea;
                parametros.Add(cant);

                cant = new SQLiteParameter();
                cant.ParameterName = "@Cantidad";
                cant.Value = l.cantidad;
                parametros.Add(cant);

                cant = new SQLiteParameter();
                cant.ParameterName = "@CodigoProd";
                cant.Value = l.producto.Codigo;
                parametros.Add(cant);

                cant = new SQLiteParameter();
                cant.ParameterName = "@PTotal";
                cant.Value = l.PrecioTotal;
                parametros.Add(cant);

                cant = new SQLiteParameter();
                cant.ParameterName = "@Codigo";
                cant.Value = codigo;
                parametros.Add(cant);

                //The query to insert the actual line of the foreach
                consulta = "Insert into Linea(IdFactura, IdLinea, IdProducto, Cantidad, Total) VALUES (" + codigo + ", @NLinea, @CodigoProd, @Cantidad, @PTotal)";

                Mapper.EjecutaNonQuery(consulta, CommandType.Text, parametros, conn, null);

                //Update the stock of the product
                if (f.cliente == "")
                {
                    consulta2 = "Update Producto Set Cantidad=Cantidad+@Cantidad Where IdProducto=@CodigoProd;";
                }
                else
                {
                    consulta2 = "Update Producto Set Cantidad=Cantidad-@Cantidad Where IdProducto=@CodigoProd;";
                }

                Mapper.EjecutaNonQuery(consulta2, CommandType.Text, parametros, conn, null);


            }

            //The transaction concludes
            trn.Commit();
        }
    }
    catch (SqlException ex)
    {
        //If there is a problem
        trn.Rollback();
    }
    finally
    {
        //Close the connection
        CerrarConexion(conn);
    }

}

在mapper类中,我有两个在前一个方法中使用的方法:

public static object ejecutaScalar(string sentencia, CommandType tipoComando, List<SQLiteParameter> parametros, SQLiteConnection con, SQLiteTransaction trn)
{
    object retorno;
    using (SQLiteCommand cmd = new SQLiteCommand())
    {
        cmd.Connection = con;
        cmd.CommandText = sentencia;
        cmd.CommandType = tipoComando;
        cmd.Parameters.AddRange(parametros.ToArray());
        if (trn != null)
            cmd.Transaction = trn;
        retorno = cmd.ExecuteScalar();

    }

    return retorno;
}

public static int EjecutaNonQuery(string sentencia, CommandType tipoComando, List<SQLiteParameter> parametros, SQLiteConnection con, SQLiteTransaction trn)
{
    int afectadas = -1;

    using (SQLiteCommand cmd = new SQLiteCommand())
    {
        cmd.Connection = con;
        cmd.CommandText = sentencia;
        cmd.CommandType = tipoComando;
        cmd.Parameters.AddRange(parametros.ToArray());
        if (trn != null)
            cmd.Transaction = trn;
        afectadas = cmd.ExecuteNonQuery();
    }
    return afectadas;
}

谢谢,对不起,如果我不能更好地解释我,英语不是我的母语,我有一些困难:P

1 个答案:

答案 0 :(得分:0)

错误消息“数据库已锁定”表示存在一些具有活动事务的其他连接。

要确保事务不会保持活动状态,请检查所有 SQL命令和事务对象是否仅用于using块,或以其他方式清除。此外,整个程序应该只使用一个连接对象(除非它有多个线程);你不应该每次都重新打开它(因为页面缓存丢失会使一切变慢)。