Autor Beitrag
Vegeto
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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 diesenLink 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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

ausblenden 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))
        {
            // Parameter setzen, ExecuteXXX aufrufen etc.
        }

        using(var cmd2 = SqlCommand("meinLieberZweiterSQLBefehl", cn, tr))
        {
            // Parameter setzen, ExecuteXXX aufrufen etc.
        }
        tr.Commit();
    }
}

Für diesen Beitrag haben gedankt: Vegeto
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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:
ausblenden 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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 :D

Lg

DANKE NOCHMAL
Vegeto Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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:

ausblenden 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 :D, 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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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:
ausblenden volle Höhe 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:
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
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 262



BeitragVerfasst: 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...