Autor |
Beitrag |
Vegeto
Beiträge: 262
|
Verfasst: Di 08.10.13 12:25
Hallo
Ich ahbe mal einige fragen zu SQL-Command und C#, ich hoffe man kann mir hier weiter helfen.
Über eine C# Anwendung lösche ich eine Tabelle und füge neue Datensätze hinzu und danach werden die Datensätze verändert(angepasst).
Ich habe also drei verschiedene SQL Commands:
Delete, Insert Into und Update.
Jeder von diese haben andere Syntax(verständlich hoffe ich)
Jetzt möchte ich aber das er vorher überprüft ob das Insert into und Update erfolgreich gemacht wurden dann soll er die tabelle löschen und die Datensätze einfügen.
Denn wenn ich das so mache wie gehabt, dann löscht er zunächst eine Komplette Tabelle fügt dann hinzu(doch wenn es hier zum fehler kommt ist die Tabelle leer).
ich weiß nämlich nicht wie ich vorzugehen habe...:/
Ich hoffe ihr versteht mein Anliegen und könnt mir weiterhelfen
Lg
|
|
Ralf Jansen
Beiträge: 4701
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 08.10.13 13:10
Es gibt viele Wege zur Datenbank welchen benutzt du? (DataAdapter, typisierte DataAdapter, eigene Commands, Entity Framework, Linq2Sql, sonstige ORMs .... und und und)
|
|
Vegeto
Beiträge: 262
|
Verfasst: Di 08.10.13 14:42
Hallo Ralf Jansen,
ich benutze eige Commands, SqlCommand cmd = new SqlCommand();(und so weiter)
ich glaub ich muss das mit Transaktion lösen, doch leider weiß ich nicht wie diese aufgebaut werden oder verwendet werden, hier habe diesen Link gefunden, doch ich werde daraus einfach nciht schlau.
muss ich am ende des Commands, im try-block ein commit setzen und wenn dieser ein catch auslöst soll im catch ein rollback statt finden?
Ich bitte um nachsehen bin in diesem gebiet neuling.
Lg
|
|
Ralf Jansen
Beiträge: 4701
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 08.10.13 15:02
Du solltest bei der Verwendung von SqlTransaction einen using Block verwenden (wie eigentlich immer wenn eine Klasse IDisposable implementiert) und nur am Ende Commit aufrufen. Wenn dich eine Exception aus dem Codeblock wirft wird der Commit nicht ausgeführt. Das Ende des using Blocks wird aber automatisch ein Dispose auf der Transaction auslösen und damit einen Rollback.
Aka
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| using (var cn = new SqlConnection("meinLieberConnectionString")) { cn.Open(); using (var tr = cn.BeginTransaction()) { using(var cmd1 = SqlCommand("meinLieberErsterSQLBefehl", cn, tr)) { }
using(var cmd2 = SqlCommand("meinLieberZweiterSQLBefehl", cn, tr)) { } tr.Commit(); } } |
Für diesen Beitrag haben gedankt: Vegeto
|
|
Vegeto
Beiträge: 262
|
Verfasst: Di 08.10.13 15:27
Hi Ralf Jansen,
Wow Danke, und wenn der Command fehlerhaft ist, kommt dann ein Rollback?
Also die Tabelle bleib so wie sie vorher war?
Oder muss ich die Commands in Try-Catch blöcken tun?
Habe gerade das hier gemacht:
Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| USE databaseA; GO BEGIN TRANSACTION;
BEGIN TRY Insert Into Test VALUES ('test','test','1111','test','test'); DELETE FROM Test IF @@TRANCOUNT > 0 COMMIT TRANSACTION; Insert Into Test VALUES ('test','test','1111','test','test'); END TRY BEGIN CATCH IF @@TRANCOUNT > 0 ROLLBACK TRANSACTION; END CATCH; GO |
Habe es im Server Managment ausprobiert und er macht genau das wie ich mir das vorstelle, z.B. wenn die Zahl ein Buchstabe erhält wird der obere Block nicht berüht und die Tabelle bleibt so wie sie vorher was.
Oder ist das so falsch? soll ich die try-catch-blöcke entfernen?
Lg
|
|
Ralf Jansen
Beiträge: 4701
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Di 08.10.13 15:37
In einem T-SQL Batch ist das ok so wie du das gemacht hast.
In C# würde ich das so machen wie ich es gezeigt habe. Das verlassen des using Blocks lößt garantiert immer einen Rollback aus wenn vorher aber ein Commit stattgefunden hat ist der irrelevant. Die Alternativen mit try .. finally oder try .. catch wären deutlich unleserlicher und nicht besser.
Für diesen Beitrag haben gedankt: Vegeto
|
|
Vegeto
Beiträge: 262
|
Verfasst: Di 08.10.13 15:55
Hallo Ralf Jansen,
Alles Klar, danke für deine Hilfe
Werde ich versuchen so umzusetzen, ich schreibe bei nicht weiter kommen
Lg
DANKE NOCHMAL
|
|
Vegeto
Beiträge: 262
|
Verfasst: Mi 09.10.13 09:19
Guten Morgen und Hallo Ralf Jansen,
ich probiere gerade dein Codegerüst umzubauen so wie ich es mir vorstelle, zu Testzwecken habe ich mir eine neue Anwendung gebaut und eine Tabelle in meiner Datenbank erstellt.
Die Datenbank beseitzt eine Tabelle "Test" mit den Spalten (Mail,Adresse,Nummer,Name,Name2), bis auf Nummer sind alle nvarchar und Nummer ist INT.
Jetzt wollte ich mit deinem Codegerüst sowas erreichen: Er soll gucken ob ein Insert Into - fehlerfrei ist und dann soll er die Tabelle löschen und die Datensätze einfügen, ich habe es so aufgebaut:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| using (SqlConnection conn = new SqlConnection(@"MeinString")) { conn.Open(); using (var transAct = conn.BeginTransaction()) { using(var insertCmd = new SqlCommand()) { insertCmd.CommandText = "INSERT INTO Test (Mail,Adresse,Nummer,Name,Name2) " + "VALUES ('" + textBox1.Text + "','" + textBox2.Text + "','" + textBox3.Text + "','" + textBox4.Text + "','" + textBox5.Text + "')"; insertCmd.Connection = conn; insertCmd.Transaction = transAct;
insertCmd.ExecuteNonQuery();
} using (var deleteCmd = new SqlCommand()) {
deleteCmd.CommandText = "Delete From Test"; deleteCmd.Connection = conn; deleteCmd.Transaction = transAct;
deleteCmd.ExecuteNonQuery();
} transAct.Commit(); } } |
So habe ich das nun aufgebaut, zu Testzwecken habe ich die Tabelle mit Datensätzen gefüllt, nun schreibe ich in die Textboxen (hauptsächlich Test), doch bei der Nummer schreibe ich statt nur Zahlen auch ein Buchstaben (z.B. C146). Wenn ich dann das "hinzufügen" will gibt er mir ein fehler aus(kann nicht in INT-Konvertiert werden), das gute ist die Tabelle wurde nicht gelöscht , doch wenn ich nur zahlen eingebe(z.B. 146) kommt kein Fehler und die Tabelle ist leer.
Jetzt wollte ich diesen Fehler abfangen , also eine MessageBox anzeigen, dies tue ich mit Try-Catch, doch sobald ich um die Commands ein Try-Catch block einfüge fängt er den Fehler ab und sagt was Fehlgeschlagen ist, doch danach löscht er die Tabelle trotzdem, da dieser Command keine Fehler beinhaltet.
Ich weiß nicht mehr weiter, ich probiere es weiter, doch ich freue mich über jegliche Hilfe.
LG
|
|
Ralf Jansen
Beiträge: 4701
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 09.10.13 09:43
Warum hast du den try.. catch nicht um die Transaction gepackt? Die ist das atomare Vorgang denn du beobachten willst und ganz oder gar nicht stattfinden soll.
Wenn du aus irgendeinem Grund nur den einen Command mit einem Exception Block kapseln willst dann wirf die Exception zumindest aus dem catch weiter (heißt ruf am Ende des catch Block throw auf).
Und nebenbei einfach den Fehler anzeigen ist in den seltensten Fehler eine vernünftige Fehlerbehandlung. In diesem Fall hier solltest du wenn du die ganze Transaction mit einem try..catch kapselst so nur auf SQLException(s) reagieren und nicht auf alle.
Für diesen Beitrag haben gedankt: Vegeto
|
|
Vegeto
Beiträge: 262
|
Verfasst: Mi 09.10.13 09:50
Hi Ralf Jansen,
DANKE, habe es gelöst habe jz um die beiden Commands das Try gelegt. Wenn Ich den try um den Transaktions block lege kann ich kein RollBack machen.
So Sieht es jetzt bei mir aus:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34:
| using (var transAct = conn.BeginTransaction()) { try { using (var deleteCmd = new SqlCommand()) {
deleteCmd.CommandText = "Delete From Test"; deleteCmd.Connection = conn; deleteCmd.Transaction = transAct;
deleteCmd.ExecuteNonQuery();
}
using (var insertCmd = new SqlCommand()) {
insertCmd.CommandText = "INSERT INTO Test (Mail,Adresse,Nummer,Name,Name2) " + "VALUES ('" + textBox1.Text + "','" + textBox2.Text + "','" + textBox3.Text + "','" + textBox4.Text + "','" + textBox5.Text + "')"; insertCmd.Connection = conn; insertCmd.Transaction = transAct;
insertCmd.ExecuteNonQuery(); }
transAct.Commit(); } catch (SqlException ex) { MessageBox.Show(ex.Message); transAct.Rollback(); } } |
Warum ich das im Transaktion-Block mache, damit ich auf die Variable transAct zugreifen kann
Meine letzte frage: kann man Commit auch bei Commands mit parameter übergabe benutzen?
Lg
|
|
Ralf Jansen
Beiträge: 4701
Erhaltene Danke: 991
VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
|
Verfasst: Mi 09.10.13 09:59
Den Rollback macht der Transactions using Block automatisch. Du solltest eigentlich nur Commit manuell machen.
Edit:
Zitat: | Meine letzte frage: kann man Commit auch bei Commands mit parameter übergabe benutzen? |
Natürlich
Für diesen Beitrag haben gedankt: Vegeto
|
|
Vegeto
Beiträge: 262
|
Verfasst: Mi 09.10.13 10:21
Danke Ralf Jansen,
ich lass es einfach so, denn es funktioniert und so werden mehre Commands überprüft und wenn alle korrekt sind wird ein Commit durchgeführt wenn was falsch ist, bleibt die tabelle so wie sie ist.
Aufjedenfall Danke ich dir SEHR...
|
|
|