2

首先对不起我的英语。我有问题需要帮助。我有一个自己在 c# 上制作的简单工具。此工具可连接到本地或远程 firebird 服务器 (v.2.5)。我的工具可以在服务器的某处创建指定的 .fdb 文件(数据库)。

我还有一个包含 SQL 语句的文件(创建表、触发器等)。我想在创建数据库后执行这个文件。执行此文件将填充用户数据库的结构 - 不是数据,只有结构。

但后来我尝试执行我的 SQL 脚本 - firebird 服务器返回一个

SQL 错误代码 = -104 令牌未知行 xxx 列 xxx。

这是这条CREATE TABLESQL 语句中的一行,例如:

CREATE TABLE tb1
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

/* This next create statement causes an error */

CREATE TABLE tb2
(
    col1 INTEGER NOT NULL,
    col2 VARCHAR(36)
); 

如果我只在我的文件中留下一个创建语句 - 一切都会好的......我不知道我是如何解释的(是否清楚) - 换句话说 - 为什么我不能使用许多创建语句执行完整查询在一笔交易中?有我执行查询的主要方法:

public static string Do(string conString, string query)
{
            using (FbConnection conn = new FbConnection())
            {
                try
                {
                    conn.ConnectionString = conString;
                    conn.Open();
                    FbTransaction trans = conn.BeginTransaction();
                    FbCommand cmd = new FbCommand(query, conn, trans);
                    cmd.ExecuteNonQuery();
                    trans.Commit();
                }
                catch (Exception ex)
                {
                    System.Windows.MessageBox.Show(ex.ToString());
                    return "Transaction Fail";
                }
            }
            return "Transaction Commited";
}

有一个查询是我的SQL文件。

4

2 回答 2

4

正如 Victor 在他的最后评论中所述,您可以使用 FBScript 类进行批处理。

我刚刚面临同样的任务。这个问题为我指明了正确的方向,但我必须做一些进一步的挖掘。

在这个例子中,语句的来源是一个外部脚本文件:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    if (!File.Exists(scriptPath))
        throw new FileNotFoundException("Script not found", scriptPath);

    FileInfo file = new FileInfo(scriptPath);
    string script = file.OpenText().ReadToEnd();

    // use FbScript to parse all statements
    FbScript fbs = new FbScript(script);
    fbs.Parse();

    // execute all statements
    FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
    fbe.Execute(true);
}

这可以正常工作,但您可能想知道为什么整个事情没有被事务包围。实际上不支持将 FbBatchExecution 直接“绑定”到事务。

我尝试的第一件事是这个(行不通

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);
        fbe.Execute(true);

        myTransaction.Commit();
    }
}

这将导致异常说明:“当分配给命令的 Connection 对象处于挂起的本地事务中时,Execute 要求 Command 对象具有 Transaction 对象。Command 的 Transaction 属性尚未初始化。”

这意味着 FbBatchExecution 执行的命令没有分配给我们围绕代码块的本地事务。这里有帮助的是 FbBatchExecution 提供了事件 CommandExecuting ,我们可以在其中拦截每个命令并分配我们的本地事务,如下所示:

private void ExecuteScript(FbConnection myConnection, string scriptPath) {
    using (FbTransaction myTransaction = myConnection.BeginTransaction()) {
        if (!File.Exists(scriptPath))
            throw new FileNotFoundException("Script not found", scriptPath);

        FileInfo file = new FileInfo(scriptPath);
        string script = file.OpenText().ReadToEnd();

        // use FbScript to parse all statements
        FbScript fbs = new FbScript(script);
        fbs.Parse();

        // execute all statements
        FbBatchExecution fbe = new FbBatchExecution(myConnection, fbs);

        fbe.CommandExecuting += delegate(object sender, CommandExecutingEventArgs args) {
            args.SqlCommand.Transaction = myTransaction;
        };

        fbe.Execute(true);
        // myTransaction.Commit();
    }
}

请注意,我已取消注释 myTransaction.Commit() 行。我对这种行为有点惊讶,但如果你保留这条线,事务将抛出一个异常,说明它已经被提交。bool 参数 fbe.Execute(true) 被命名为“autoCommit”,但将其更改为 false 似乎没有任何效果。

如果您发现以这种方式分配本地事务有任何潜在问题,或者它是否有任何好处或者也可以省略,我希望得到一些反馈。

于 2012-12-10T18:01:20.063 回答
1

在一批中启动两个创建语句可能会出错。如果您将其分解为单独的查询,它会起作用吗?它在您的 SQL 工具中有效吗?

于 2010-07-20T18:52:48.740 回答