如何使用c#在firebird中执行事务(或多个sql查询)

本文关键字:sql 查询 事务 何使用 firebird 执行 | 更新日期: 2023-09-27 18:21:33

我已经尝试了几种方法,包括在SO.上

以下MYSQL代码在Firebird:中不起作用

CREATE TABLE publications (
  INT NOT NULL AUTO_INCREMENT , 
  PRIMARY KEY (`id`),
  filename varchar(500) not null unique,
  title varchar(500) DEFAULT NULL,
  authors varchar(1000) DEFAULT NULL,
  uploader int DEFAULT NULL,
  keywords varchar(500) DEFAULT NULL,
  rawtext text,
  lastmodified timestamp default CURRENT_TIMESTAMP
);

因此,为了在Firebird中实现这一点,我正在使用:

 CREATE TABLE publications (
   id int NOT NULL PRIMARY KEY,
   filename varchar(500) NOT NULL UNIQUE,
   title varchar(500) DEFAULT NULL,
   authors varchar(1000) DEFAULT NULL,
   uploader int DEFAULT NULL,
   keywords varchar(500) DEFAULT NULL,
   rawtext text,
   file_data BLOB SUB_TYPE 0,
   insertdate timestamp DEFAULT NULL
 );
 CREATE GENERATOR gen_t1_id;
 SET GENERATOR gen_t1_id TO 0;
set term !! ;
 CREATE TRIGGER journalInsertionTrigger FOR publications 
 ACTIVE BEFORE INSERT POSITION 0
 AS
 BEGIN
  if (NEW.ID is NULL) then NEW.ID = GEN_ID(GEN_T1_ID, 1);
 END!!
set term ; !!

通过以上内容,我得到了错误:

Batch execution aborted The returned message was: Dynamic SQL Error SQL error code = -104 Token unknown - line 13, char 2 CREATE"

当我取消注释//FbTransaction fbt = Connection.BeginTransaction();//fbt.Commit();

当分配给该命令的Connection对象处于挂起的本地交易命令的Transaction属性尚未已初始化。

我正在使用以下C#代码:

//FbTransaction fbt = Connection.BeginTransaction(); // 
FbBatchExecution fbe = new FbBatchExecution( Connection );
fbe.SqlStatements = new System.Collections.Specialized.StringCollection();//.Add( queryString ); // Your string here                    
fbe.SqlStatements.Add( queryString ); // Your string here
fbe.Execute();
//fbt.Commit();

注意:在sql代码的开头设置set term ; !!会出现错误:The type of the SQL statement could not be determinated

我该怎么做?

如何使用c#在firebird中执行事务(或多个sql查询)

Firebird只能执行单独的SQL语句,大多数Firebird的驱动程序都遵循相同的规则。你不能像这样一次执行一个脚本。

Firebird.net提供程序包含一个实用程序类,用于将脚本拆分为单独的语句。

你需要做一些类似的事情:

using (var connection = new FbConnection(@"User=sysdba;Password=masterkey;Database=D:'data'db'testdatabase.fdb;DataSource=localhost"))
{
    connection.Open();
    FbScript script = new FbScript(dbScript);
    script.Parse();
    FbBatchExecution fbe = new FbBatchExecution(connection);
    fbe.AppendSqlStatements(script);
    fbe.Execute();
}

请注意,要使当前脚本工作,还需要替换:

rawtext text,

带有

rawtext BLOB SUB_TYPE TEXT CHARACTER SET UTF8

从技术上讲,您可以省略字符集子句,但除非您为数据库定义了默认字符集,否则您应该指定字符集,不然它将是NONE,这可能会导致以后出现问题。

当您使用FbBatchExecution时,您不能自己启动事务,因为事务在Execute方法中进行内部处理。请注意,如果您还想在脚本中插入(或以其他方式修改)数据,那么您应该使用Execute(true),以便立即提交每个DDL语句。Firebird不允许DML在同一事务中使用事务中的DDL更改。

SET TERM的问题是由于SET TERM不是Firebird语法的一部分。它是ISQL和FlameRobin等工具使用的语法的一部分,例如FbScript

如果你想单独执行这些语句并控制交易,你可以做这样的事情:

using (var connection = new FbConnection(@"User=sysdba;Password=masterkey;Database=D:'data'db'testdatabase.fdb;DataSource=localhost"))
{
    connection.Open();
    using (var transaction = connection.BeginTransaction())
    using (var command = new FbCommand())
    {
        command.Connection = connection;
        command.Transaction = transaction;
        command.CommandText = @"CREATE TABLE publications (
           id int NOT NULL PRIMARY KEY,
           filename varchar(500) NOT NULL UNIQUE,
           title varchar(500) DEFAULT NULL,
           authors varchar(1000) DEFAULT NULL,
           uploader int DEFAULT NULL,
           keywords varchar(500) DEFAULT NULL,
           rawtext BLOB SUB_TYPE TEXT CHARACTER SET UTF8,
           file_data BLOB SUB_TYPE 0,
           insertdate timestamp DEFAULT NULL
         )";
        command.ExecuteNonQuery();
        command.CommandText = "CREATE GENERATOR gen_t1_id";
        command.ExecuteNonQuery();
        command.CommandText = @"CREATE TRIGGER journalInsertionTrigger FOR publications 
         ACTIVE BEFORE INSERT POSITION 0
         AS
         BEGIN
          if (NEW.ID is NULL) then NEW.ID = GEN_ID(GEN_T1_ID, 1);
         END";
        command.ExecuteNonQuery();
        transaction.Commit();
    }
}

正如Mark所指出的,Firebird只能执行单个语句。如果你把它们分组到一个区块中,那么这个区块有自己的交易,你不能自己启动交易。我通过创建一个扩展方法ExecuteBatch()来解决这个问题,您可以使用它来代替ExecuteNonQuery()。这是代码:

static class FbCommandExtension
{
    public static void ExecuteBatch(this FbCommand cmd)
    {
        var script = new FbScript(cmd.CommandText);
        script.Parse();
        foreach (var line in script.Results)
        {
            using (var inner = new FbCommand(line.Text, cmd.Connection, cmd.Transaction))
            {
                CopyParameters(cmd, inner);
                inner.ExecuteNonQuery();
            }
        }
    }
    private static void CopyParameters(FbCommand source, FbCommand inner)
    {
        foreach (FbParameter parameter in source.Parameters)
        {
            inner.Parameters.AddWithValue(parameter.ParameterName, parameter.Value);
        }
    }
}