2009-07-29 3 views
1

Ich habe einen Fehler in meinem Code festgestellt und ich bin nicht sicher, wie er überhaupt aufgetreten sein könnte.asp.net/sql Server versuchen zu fangen, was vor sich geht?

Meine Frage ist, habe ich einen Übersprung in den Datenbank-ID-Feldern gefunden (es ist ein inkrementiertes Identitätsfeld), anzeigend einige Datensätze wurden nicht eingefügt - was bedeutet, dass mein SQL-Sprocs (wahrscheinlich) einen Fehler warf. Wenn Sie von dort rückwärts denken, bedeutet dies, dass mein Geschäftsobjekt diesen Fehler erfasst und ausgelöst, sofort beendet und zum Codebehind der Seite zurückgekehrt sein sollte (statt dessen ging es direkt weiter zur zweiten gespeicherten Prozedur). Ich verstehe nicht warum oder wie das möglich ist. Was passiert in Bezug auf die Codeausführung, indem ich meine Versuche vergesse?

Suchrufcode hinter:

protected void submitbutton_click(object sender, EventArgs e){ 
     try{ 
     mybusinessobject.savetodatabase() 
     } catch(Exception ex) { 
     Response.Redirect("Error.aspx"); 
     } 
} 

Business-Objektcode:

public static void savetodatabase(){ 
     int ID1=-1; 
     int ID2=-1; 
     //store the billing contact 
     SqlCommand cmd1 = new SqlCommand("SaveInfo1", con); 
     cmd1.CommandType = CommandType.StoredProcedure; 
     //... 
     cmd1.Parameters.Add("@Ret", SqlDbType.Int); 
     cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue; 

     try 
     { 
      con.Open(); 
      cmd1 .ExecuteNonQuery(); 
      ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value); 
     } 
     catch (Exception ex) { throw ex; } 
     finally { con.Close(); } 

     if (ID1 > 0) 
     { 
      SqlCommand cmd = new SqlCommand("SaveInfo2", con); 
      cmd.CommandType = CommandType.StoredProcedure; 
      //... 
      try 
      { 
       con.Open(); 
       cmd.ExecuteNonQuery(); 
       ID2= Convert.ToInt32(cmd.Parameters["@Ret"].Value); 
      } 
      catch (Exception ex) { throw ex; } 
      finally { con.Close(); } 
     } 
} 

SQL-Code:

PROCEDURE [dbo].[SaveInfo1] 
( 
-- ... parameters ... 
) 
AS 
    INSERT INTO Table1 (...) Values (...) 
RETURN SCOPE_IDENTITY 

PROCEDURE [dbo].[SaveInfo2] 
( 
-- ... parameters ... 
) 
AS 
    DECLARE @SpecialID INT 
    INSERT INTO Table2 (...) Values (...) 
    SET @SpecialID = SCOPE_IDENTITY() 
    INSERT INTO Table3 ([ID], ...) Values (@SpecialID, ...) 
RETURN SCOPE_IDENTITY() 
+0

Ich benutze nicht asp.net, also könnte ich hier das Boot vermissen. Es würde nicht das Problem verursachen, nach dem Sie fragen, aber gibt es eine Transaktion um die zwei Aufrufe der gespeicherten Prozedur? –

+0

Nein, das war Teil des Problems. Aber das erklärt immer noch nicht, warum es meine Versuchsfänge übersprungen hat. –

+0

Siehe meine Antwort. Ich bin mir sicher, dass ich recht habe. Ich habe mir den Kopf zerbrochen und versucht, das gleiche Problem für ein paar Wochen zu lösen, bevor ich die Lösung gefunden habe. – abatishchev

Antwort

2

Ihre Ausnahmebehandlung ist schrecklich. Nie dies tun:

catch (Exception ex) { throw ex; } 

Alles, führt den Stack-Trace in Ausnahme vermasseln ist. Es sieht so aus, als ob die Ausnahme an dem Punkt der throw entstanden wäre.

Nie dies tun:

try{ 
    mybusinessobject.savetodatabase() 
    } catch(Exception ex) { 
    Response.Redirect("Error.aspx"); 
    } 

Sie wissen nicht, was passiert ist Ausnahme. Sie haben keine Ahnung, ob es sicher ist, umzuleiten oder nicht, und obendrein verlieren Sie alle Informationen darüber, was die Ausnahme war!

Sie sollten auch in die Gewohnheit der Umsetzung using Blöcke:

public static void savetodatabase() 
{ 
    using (SqlConnection con = new SqlConnection("Connectionstring")) 
    { 
     int ID1; 
     //store the billing contact 
     using (SqlCommand cmd1 = new SqlCommand("SaveInfo1", con)) 
     { 
      cmd1.CommandType = CommandType.StoredProcedure; 
      //... 
      cmd1.Parameters.Add("@Ret", SqlDbType.Int); 
      cmd1.Parameters["@Ret"].Direction = ParameterDirection.ReturnValue; 

      con.Open(); 
      cmd1.ExecuteNonQuery(); 
      ID1 = Convert.ToInt32(cmd1.Parameters["@Ret"].Value); 
     } 

     if (ID1 <= 0) 
     { 
      return; 
     } 

     int ID2 = -1; 
     using (SqlCommand cmd = new SqlCommand("SaveInfo2", con)) 
     { 
      cmd.CommandType = CommandType.StoredProcedure; 
      //... 
      con.Open(); 
      cmd.ExecuteNonQuery(); 
      ID2 = Convert.ToInt32(cmd.Parameters["@Ret"].Value); 
     } 
    } 
} 

Ein using Block stellt sicher, dass die Ressource seine Dispose Methode aufgerufen haben wird, ob oder ob nicht eine Ausnahme ausgelöst wird.

0

Ist nicht die mo Re wahrscheinlich Szenario, dass jemand nur einige Datensätze aus der Tabelle gelöscht hat?

+1

Ist es wichtig, dass Sie in Ihrer ersten Prozedur RETURN SCOPE_IDENTITY zurückgeben und SCOPE_IDENTITY() nicht zurückgeben? – MyItchyChin

0

Wenn Datensätze gelöscht werden, werden ihre eindeutigen Bezeichner nicht wiederverwendet, auch wenn später neue Datensätze eingefügt werden. Sie können RESEED in SQL verwenden, um den Identitätsstartwert auf 0 zurückzusetzen, wenn Sie möchten, aber ich schlage das vor, es sei denn, Sie löschen die Tabelle. Andernfalls könnten Sie mit Primärschlüsselverletzungen enden.

Stellen Sie außerdem sicher, dass der Identitätsstartwert Ihrer Spalte auf 1 erhöht ist.

0

Ihr Code keine Rolle spielt, nur um Web.config gehen und mit entsprechenden Knoten spielen:

<customErrors mode="On|Off" /> 

P. S. Verwenden Sie die using-Klausel, um eine Verbindung automatisch zu schließen, anstatt manuell in der finally Klausel

+0

Das hat absolut keine Auswirkung darauf, ob Ausnahmen von 'catch' Blöcken abgefangen werden oder nicht (sie werden immer abgefangen). –

+0

nein, das tun sie nicht! Machen Sie einen Test für jeden möglichen Wert für customErrors und Sie werden sehen. Ich habe das gleiche Problem mit VS2008TS/SQL2008/Win7RC. blind mich, wenn nicht! – abatishchev

0

können Sie den Catch testen. ändern, nur das Verfahren:

PROCEDURE [dbo].[SaveInfo1] 
( 
-- ... parameters ... 
) 
AS 
    INSERT INTO Table1 (...) Values (..., some_out_of_range_value_here, ....) 
RETURN SCOPE_IDENTITY() 

einige hart außerhalb des zulässigen Bereichs Wert (so der Einsatz ausfällt) kodiert haben, und führen Sie Ihre Anwendung ...