Comment exécuter des transactions (ou plusieurs requêtes SQL) dans Firebird en utilisant c #

J’ai essayé plusieurs façons, y compris sur SO.

Le code MYSQL suivant ne fonctionne pas dans 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 ); 

Donc, pour atteindre cet objective dans Firebird, j’utilise:

  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 ; !! 

Et avec ce qui précède, j’ai l’erreur:

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

Lorsque je ne //FbTransaction fbt = Connection.BeginTransaction(); et //fbt.Commit();

L’exécution requirejs que l’object Command ait un object Transaction lorsque l’object Connection affecté à la commande se trouve dans une transaction locale en attente. La propriété Transaction de la commande n’a pas été initialisée.

J’utilise le code C # suivant:

 //FbTransaction fbt = Connection.BeginTransaction(); // FbBatchExecution fbe = new FbBatchExecution( Connection ); fbe.SqlStatements = new System.Collections.Specialized.SsortingngCollection();//.Add( querySsortingng ); // Your ssortingng here fbe.SqlStatements.Add( querySsortingng ); // Your ssortingng here fbe.Execute(); //fbt.Commit(); 

NB: réglage de set term ; !! set term ; !! au début du code sql donne l’erreur: The type of the SQL statement could not be determinated

Comment puis-je faire cela?

Firebird ne peut exécuter que des instructions SQL individuelles et la plupart des pilotes de Firebird suivent cette même règle. Vous ne pouvez pas exécuter un script à la fois comme ceci.

Le fournisseur Firebird.net contient une classe d’utilitaire permettant de scinder les scripts en instructions individuelles.

Vous devez faire quelque chose comme:

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

Notez que pour que votre script actuel fonctionne, vous devez également remplacer:

 rawtext text, 

avec

 rawtext BLOB SUB_TYPE TEXT CHARACTER SET UTF8 

Techniquement, vous pouvez laisser la clause de jeu de caractères désactivée, mais à moins de définir un jeu de caractères par défaut pour votre firebase database, vous devez spécifier le jeu de caractères, sinon ce sera NONE ce qui pourrait entraîner des problèmes ultérieurement.

Vous ne pouvez pas démarrer une transaction vous-même lorsque vous utilisez FbBatchExecution , car la transaction est gérée en interne dans la méthode Execute . Notez que si vous souhaitez également insérer (ou modifier autrement) des données dans le script, vous devez utiliser Execute(true) , afin que chaque instruction DDL soit validée immédiatement. Firebird n’autorise pas l’utilisation des modifications DDL d’une transaction par DML dans la même transaction.

Le problème avec SET TERM est dû au fait que SET TERM ne fait pas partie de la syntaxe Firebird. Cela fait partie de la syntaxe utilisée par des outils tels que ISQL et FlameRobin, et par exemple FbScript .

Si vous souhaitez exécuter ces instructions individuellement et avoir le contrôle de la transaction, procédez comme suit:

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

Comme Mark l’a souligné, Firebird ne peut exécuter que des instructions individuelles. Si vous les groupez dans un bloc, le bloc a sa propre transaction et vous ne pouvez pas démarrer la transaction vous-même. J’ai résolu ce problème en créant une méthode d’extension ExecuteBatch () que vous pouvez utiliser à la place de ExecuteNonQuery (). Voici le code:

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