如何使用 c# 在 firebird 中执行事务(或多个 sql 查询)
How to execute transactions (or multiple sql queries) in firebird using c#
我尝试了几种方法,包括在 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();
Execute requires the Command object to have a Transaction object when
the Connection object assigned to the command is in a pending local
transaction. The Transaction property of the Command has not been
initialized.
我正在使用以下 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
我该怎么做?
Firebird 只能执行单个 SQL 语句,大多数 Firebird 驱动程序都遵循相同的规则。您不能像这样立即执行脚本。
Firebird.net 提供程序包含一个实用程序 class 可将脚本拆分为单独的语句。
您需要执行以下操作:
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);
}
}
}
我尝试了几种方法,包括在 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();
Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized.
我正在使用以下 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
我该怎么做?
Firebird 只能执行单个 SQL 语句,大多数 Firebird 驱动程序都遵循相同的规则。您不能像这样立即执行脚本。
Firebird.net 提供程序包含一个实用程序 class 可将脚本拆分为单独的语句。
您需要执行以下操作:
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);
}
}
}