一个事务上的多个查询。带SQLite的C#winforms

一个事务上的多个查询。带SQLite的C#winforms,c#,sqlite,C#,Sqlite,我正在学习如何使用SQLite,我在这个问题上纠缠了一个多星期,在我的网络搜索中没有找到答案 问题是,如果查询失败,我需要在同一笔交易中用相应的行注册账单,并更新购买产品的一些信息 当我尝试注册某个内容时,我获得了“数据库被锁定”异常,但我发现奇怪的是,我在创建此问题时一直让程序运行,当我再次看到它时,我发现“继续”按钮可用,然后程序最终工作了 所以我想知道我必须改进什么才能不出现这种例外 啊,这是一个Winforms应用程序,只有一个人会使用它,所以它不会有并发问题(我也这么认为)。 首先,这

我正在学习如何使用SQLite,我在这个问题上纠缠了一个多星期,在我的网络搜索中没有找到答案

问题是,如果查询失败,我需要在同一笔交易中用相应的行注册账单,并更新购买产品的一些信息

当我尝试注册某个内容时,我获得了“数据库被锁定”异常,但我发现奇怪的是,我在创建此问题时一直让程序运行,当我再次看到它时,我发现“继续”按钮可用,然后程序最终工作了

所以我想知道我必须改进什么才能不出现这种例外

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

首先,这是连接字符串(如果需要添加内容): “数据源=D:\De disco c\Documents\Visual Studio 2010\Projects\Racion\Racion\bin\Racion.db;版本=3;”

在bill类的映射器上,我有以下方法:

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);
    }

}
public static void registratorfactura(事实f)
{
SQLiteConnection conn=null;
SQLiteTransaction trn=null;
尝试
{
var parametros=新列表();
var cant=新的SQLiteParameter();
cant.ParameterName=“@Cliente”;
铁路超高值=f.客户;
参数添加(铁路超高);
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@Fecha”;
cant.Value=DateTime.Now;
参数添加(铁路超高);
//这里有一个查询。我需要知道账单的ID才能注册行并进行更新。
String consulta=“插入Factura(Cliente,Fecha)值(@Cliente,@Fecha);选择last_Insert_rowid();”;
//打开连接
conn=钝角连接();
//开始交易
使用(trn=conn.BeginTransaction())
{
//在这里,我注册账单并获得它的id
int codigo=Convert.ToInt32(Mapper.ejectascalar(consulta,CommandType.Text,parametros,conn,trn));
//现在我必须登记一下账单的行数
字符串consulta2=“”;
foreach(线性中的线性)
{
parametros=新列表();
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@NLinea”;
铁路超高值=l.numeroLinea;
参数添加(铁路超高);
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@Cantidad”;
铁路超高值=l.cantidad;
参数添加(铁路超高);
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@CodigoProd”;
铁路超高值=l.producto.Codigo;
参数添加(铁路超高);
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@PTotal”;
铁路超高值=1.PrecioTotal;
参数添加(铁路超高);
铁路超高=新的SQLiteParameter();
cant.ParameterName=“@Codigo”;
铁路超高值=codigo;
参数添加(铁路超高);
//用于插入foreach的实际行的查询
consulta=“插入Linea(IdFactura、IdLinea、IdProducto、Cantidad、Total)值(“+codigo+”、@NLinea、@CodigoProd、@Cantidad、@PTotal)”;
EjecutaNonQuery(consulta,CommandType.Text,parametros,conn,null);
//更新产品的库存
如果(f.客户==“”)
{
consulta2=“更新Producto Set Cantidad=Cantidad+@Cantidad,其中IdProducto=@CodigoProd;”;
}
其他的
{
consulta2=“更新Producto Set Cantidad=Cantidad-@Cantidad,其中IdProducto=@CodigoProd;”;
}
EjecutaNonQuery(consulta2,CommandType.Text,parametros,conn,null);
}
//交易结束
trn.Commit();
}
}
catch(SqlException-ex)
{
//如果有问题
trn.Rollback();
}
最后
{
//关闭连接
康涅狄格州;
}
}
在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;
}
公共静态对象ejectascalar(字符串判决、命令类型tipoComando、列表参数、SQLiteConnection con、SQLiteTransaction trn)
{
对象:否;
使用(SQLiteCommand cmd=new SQLiteCommand())
{
cmd.Connection=con;
cmd.CommandText=判决;
cmd.CommandType=tipoComando;
cmd.Parameters.AddRange(parametros.ToArray());
如果(trn!=null)
cmd.Transaction=trn;
returno=cmd.ExecuteScalar();
}
返回号;
}
公共静态int-EjecutaNonQuery(字符串语句、CommandType-tipoComando、列表参数、SQLiteConnection-con、SQLiteTransaction-trn)
{
int-afectadas=-1;
使用(SQLiteCommand cmd=new SQLiteCommand())
{
cmd.Connection=con;
cmd.CommandText=判决;
cmd.CommandType=tipoComando;
cmd.Parameters.AddRange(parametros.ToArray());
如果(trn!=null)
cmd.Transaction=trn;
afectadas=cmd.ExecuteNonQuery();
}
返回afectadas;
}
谢谢,如果我不能更好地解释的话,我很抱歉,英语不是我的母语,我在这方面有一些困难:p

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

要确保事务不保持活动状态,请检查所有SQL命令和事务对象是否仅与
使用块一起使用,或以其他方式清理。此外,整个程序应仅使用单个连接对象(unles