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

我尝试了几种方法,包括在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对象处于挂起的本地事务中时,Execute要求Command对象具有Transaction对象。 Command的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(); 

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

我该怎么做呢?

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只能执行单独的语句。 如果将它们分组到一个块中,则块具有自己的事务,您无法自己启动事务。 我通过创建一个可以使用而不是ExecuteNonQuery()的扩展方法ExecuteBatch()解决了这个问题。 这是代码:

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