0

I've been scouring the net for an answer, but haven't found anything yet.

I have a small console app, which I'm trying to insert some data into a SQL Server database (.mdf database file), everything runs without error, but when I open the DB after the fact in Server Explorer, the data is not there.

This is the 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);
            }
        }                                        
    }
}

The db connection string is:

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

and the data directory is:

AppDomain.CurrentDomain.SetData("DataDirectory", Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\FrameBudget\"));
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
devonuto
  • 375
  • 1
  • 6
  • 18
  • Check this question http://stackoverflow.com/questions/17147249/why-saving-changes-to-a-database-fails – Steve Nov 15 '16 at 20:48
  • Interesting, even though I'm explicitly setting the datadirectory, and when I debug through the application and look at the connection properties, the database is showing as the correct one located in ProgramData? – devonuto Nov 15 '16 at 21:24
  • And the connection in the Server Explorer? – Steve Nov 15 '16 at 21:46
  • I connected to all 3 databases in server explorer: The one in my project folder, the one in the bin folder and the one in ProgramData after running the application and checked. Nothing is in any of them... I have no idea why. But viewing the SqlConnection mid-debug, the database file connected shows the one in ProgramData too, so I don't see how it could be connecting to another one? – devonuto Nov 15 '16 at 22:06
  • sorry, AppData, not ProgramData – devonuto Nov 15 '16 at 22:17

1 Answers1

1

Really it is not clear why you have both a TransactionScope instance and a call to BeginTransaction. I would use only one of them. However this line

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

needs to be completed in case of success with

   scope.Complete();
}

Without the call to Complete, exiting the using block implies a rollback.
I would remove the block with the call to

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

and the relative Rollback or Commit calls leaving only the TransactionScope instance (a lot simpler to handle).

As a side note. Your code is vulnerable to Sql Injection. That string.Format is a form of string concatenation and we all know the nasty things that can happen with a string concatenation approach to build sql queries

Community
  • 1
  • 1
Steve
  • 213,761
  • 22
  • 232
  • 286
  • Yeah, I thought that might be confusing. I added in the SqlTransaction after the fact, as I thought that might get it to work. Previously I was using only the scope, and I was using cmd.AddParameterWithValue() as well. The change to parameterised string was so I could grab out the SQL and run it directly on the database to test it was working. But you were correct, I am missing the scope.Complete() call. As you can see here, I used it earlier, but not here: https://github.com/devonuto/VSApplications/blob/master/FrameBudget/FrameBudget/Program.cs – devonuto Nov 16 '16 at 00:18
  • I will try again once I get home, but I suspect that missing line is the issue. – devonuto Nov 16 '16 at 00:18
  • 1
    thanks, sometimes all it needs is an extra pair of eyes! – devonuto Nov 16 '16 at 00:21