2016-11-15 2 views
0

Ich habe das Netz nach einer Antwort durchforstet, aber noch nichts gefunden.Konnte keine Daten zum Commit an SQL Server erhalten

Ich habe eine kleine Konsole App, die ich versuche, einige Daten in eine SQL Server-Datenbank (.mdf Datenbank-Datei) einzufügen, alles läuft ohne Fehler, aber wenn ich die DB nach der Tatsache in Server Explorer öffnen, die Daten sind nicht da.

Dies ist der Code:

using (TransactionScope scope = new TransactionScope()) 
{ 
    using (SqlConnection conn = new SqlConnection(ConfigurationManager.ConnectionStrings["FrameBudgetDB"].ToString())) 
    { 
     SqlCommand cmd = new SqlCommand(); 
     cmd.Connection = conn; 

     conn.Open(); 

     cmd.CommandText = string.Format("SELECT TOP 1 category_id FROM businesses WHERE '{0}' LIKE CONCAT('%',description,'%')", transDescription.Replace("'", "''")); 

     SqlDataReader reader = cmd.ExecuteReader(); 

     try 
     { 
      if (reader.HasRows) 
      { 
       while (reader.Read()) 
       { 
        categoryId = (int)reader[0]; 
       } 
      } 
      else 
      { 
       categoryId = 44; // Unknown 
      } 
     } 
     finally 
     { 
      reader.Close(); 
     } 

     // Get Transaction Type 
     int transTypeId = 0; 
     cmd.CommandText = string.Format("SELECT trans_type_id FROM transaction_types WHERE description = '{0}'", transType); 

     reader = cmd.ExecuteReader(); 

     try 
     { 
      if (reader.HasRows) 
      { 
       while (reader.Read()) 
       { 
        transTypeId = (int)reader[0]; 
       } 
      } 
     } 
     finally 
     { 
      reader.Close(); 
     } 

     SqlTransaction trans = conn.BeginTransaction("InsertTransactiolns"); 

     try 
     { 
      cmd.Transaction = trans; 
      cmd.CommandText = string.Format(
           "BEGIN " + 
             "IF NOT EXISTS(SELECT * FROM transactions " + 
                    "WHERE transaction_date = '{0}' " + 
                    "AND description = '{1}' " + 
                    "AND trans_type_id = {2} " + 
                    "AND amount = {3} " + 
                    "AND(category_id = {5} OR previous_category_id = {5})) " + 
            "BEGIN " + 
              "INSERT INTO transactions(transaction_date, description, trans_type_id, import_date, category_id, amount) " + 
              "VALUES('{0}', '{1}', {2}, '{4}', {5}, {3}) " + 
            "END " + 
           "END", transDate, transDescription.Replace("'", "''"), transTypeId, amount, DateTime.Now, categoryId); 

      rowsInserted = rowsInserted + cmd.ExecuteNonQuery(); 
      trans.Commit(); 
     } 
     catch (Exception e) 
     { 
      Console.WriteLine(e.Message); 

      try 
      { 
       trans.Rollback(); 
      } 
      catch (Exception e2) 
      { 
       Console.WriteLine(e2.Message); 
      } 
     }           
    } 
} 

Der db Verbindungszeichenfolge ist:

<connectionStrings> 
    <add name="FrameBudgetDB" 
     connectionString="Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=|DataDirectory|FrameBudget.mdf;Integrated Security=True;Connect Timeout=30" 
     providerName="System.Data.SqlClient" /> 
</connectionStrings> 

und das Datenverzeichnis ist:

AppDomain.CurrentDomain.SetData("DataDirectory", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\FrameBudget\")); 
+0

Überprüfen Sie diese Frage http://stackoverflow.com/questions/17147249/why-saving-changes-to -a-database-failed – Steve

+0

Interessant, obwohl ich das Datenverzeichnis explizit festlegen, und wenn ich über die Anwendung debuggen und die Verbindungseigenschaften betrachten, wird die Datenbank als die richtige in ProgramData angezeigt? – devonuto

+0

Und die Verbindung im Server Explorer? – Steve

Antwort

1

Wirklich nicht klar ist, warum haben Sie sowohl eine TransactionScope-Instanz als auch ein Aufruf von BeginTransaction. Ich würde nur einen von ihnen verwenden. Doch diese Linie

using (TransactionScope scope = new TransactionScope()) 
{ 
    ... 

muss mit

scope.Complete(); 
} 

Ohne den Aufruf im Erfolgsfall abgeschlossen wird zum Abschließen der Verwendung von Block impliziert einen Rollback zu verlassen.
würde ich den Block mit dem Aufruf von

SqlTransaction trans = conn.BeginTransaction("InsertTransactiolns"); 

und die relativen Rollback entfernen oder Anrufen Commit nur die Transaction Instanz (viel einfacher zu handhaben) zu verlassen.

Als eine Randnotiz. Ihr Code ist anfällig für SQL Injection. Das string.Format ist eine Art von String-Verkettung und wir alle kennen die nasty things that can happen mit einem String-Verkettung Ansatz zum Erstellen von SQL-Abfragen

+0

Ja, ich dachte, das könnte verwirrend sein. Ich fügte in der SqlTransaction nachträglich hinzu, da ich dachte, dass es damit funktionieren könnte. Zuvor habe ich nur den Bereich verwendet, und ich habe auch cmd.AddParameterWithValue() verwendet. Die Änderung an der parametrisierten Zeichenkette war so, dass ich das SQL herausnehmen und direkt in der Datenbank ausführen konnte, um zu testen, ob es funktionierte. Aber Sie hatten Recht, ich vermisse den scope.Complete() Anruf. Wie Sie hier sehen können, habe ich es früher verwendet, aber nicht hier: https://github.com/devonuto/VSApplications/blob/master/FrameBudget/FrameBudget/Program.cs – devonuto

+0

Ich werde es wieder versuchen, sobald ich nach Hause komme, aber ich vermute, dass fehlende Linie das Problem ist. – devonuto

+0

Nun, viel Glück und gute Nacht (zumindest für mich) – Steve

Verwandte Themen