Autor Beitrag
Cjreek
Hält's aus hier
Beiträge: 13

Windows 7 64-Bit
C# (VS 2013), Delphi 2010
BeitragVerfasst: Mo 25.01.16 17:10 
Hallo,

Ich verzweifel hier langsam :(
Ich möchte eine Liste von SQL-Befehlen hintereinander in der gleichen Transaktion ausführen.
Wenn ich allerdings ein CREATE TABLE ausführe (erfolgreich) und danach ein INSERT in diese Tabelle machen will,
schlägt das INSERT fehl weil die vorher erstellte Tabelle angeblich nicht existiert:

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
FbTransaction trans = connection.BeginTransaction(); // connection ist eine aktive Verbindung
try
{
  for (int i=0; i < SqlStatements.Count; i++)  // List<string> SqlStatements
  {
    FbCommand cmd = new FbCommand(SqlStatements[i], connection, trans);
    cmd.ExecuteNonQuery();
  }

  trans.Commit();
}
catch(FbException ex)
{
  trans.Rollback();
}


Kann mir jemand sagen was ich falsch mache?

(PS: Ich weiß, dass es FbBatchExecution gibt, aber das reicht für meine Zwecke nicht, ich muss es von Hand machen)

Crosspost: www.delphipraxis.net...ion.html#post1328153
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4346
Erhaltene Danke: 877


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 26.01.16 21:22 
Ich habe das in der DelphiPraxis ein wenig verfolgt da das dortige Ergebnis (DML und DDL kann man in einer Transaktion nicht sinnvoll mischen) meinen Erfahrungen entspricht kurz mein Senf dazu.
Du scheinst ein Update Verfahren zu brauchen in einer ähnlichen Situation (.Net Anwendung die multiple Firebird Embedded Datenbanken verwendet und gelegentlich upgedatet werden muß) habe ich um das Problem zu ~lösen~ eine Tabelle ergänzt die Einstellungen nachhält unter anderem den genauen Versionzustand der Datenbank. Wenn ich also ein Update der Datenbank brauche das sich nicht als eine Transaktion darstellen lässt hat jeder Zwischenschritt eine eigene Versionsnummer so das klar ist welche Steps noch fehlen und ich in einem 2.ten Anlauf nur die noch fehlenden Steps ausführen muß um zur Zielversion zu kommen. Ich selbst brauche kein zurück (es geht immer nur vorwärts) wenn das zwingend notwendig ist sollte das mit einem entsprechenden Upgradeskript das eine Version zurückdrehen kann aber auch möglich sein.

Da das hier im Net-Forum liegt muß ich auch was .Net mäßiges absondern da bleibt nur dein Code Sorry. ;)
Der ist (nach meinem empfinden) echt häßlich. Die Datenbankomponenten sind so geschrieben das man nie explizit Rollback aufrufen muss. Das wird von Dispose (wenn nötig aka es gab noch kein commit) erledigt man muß nur dafür sorgen das auch garantiert disposed wird, mit einem using Block (sollte man immer tun wenn eine Klasse IDisposable implementiert). Dann ist auch der try catch weg.

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
using (var trans = connection.BeginTransaction()) // connection ist eine aktive Verbindung
{
   for (int i = 0; i < SqlStatements.Count; i++)  // List<string> SqlStatements
   {
       using (var cmd = new FbCommand(SqlStatements[i], connection, trans))
       {
           cmd.ExecuteNonQuery();
       }
   } 
   trans.Commit();
}


Sieht in besagter Anwendung ähnlich aus. In der Schleife ist nur nicht zwingend ein einfacher Sql Call. Es gibt hier auch Fälle wo sich der Upgrade nicht einfach als Sql ausdrucken läßt sondern Code ausgeführt wird um Daten oder ähnliches erst noch zu ermitteln um daraus dann das nötige Statement zu basteln. Bei mir gibst da dann noch einen potentiellen delegaten.