3

I'm working a WinForms based C# tool which has an attached MDF file based database. I'm trying to use the SqlCommand.ExecuteNonQuery() method to save a record to this attached MDF database, but the record is not saved. No error or exception occurs; only problem is that the record is not actually saved.

I have a Console.WriteLine at the top which shows the query I'm trying to run. Its correct syntax-wise, and if I copy-paste it from the output windows and run it separately, it works.

I have correctly defined the connection string as the following, and it works fine for fetching records:

public static String connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\TestBuildDB.mdf;Integrated Security=True;Connect Timeout=30;User Instance=True";

Here the function I'm using to save records:

public static void PerformDBWriteTransaction(string inputSQLStatement)
{
    Console.WriteLine(inputSQLStatement);
    DataTable returnDataTable = new DataTable();
    SqlConnection sqlConnection = new SqlConnection();
    sqlConnection.ConnectionString = connectionString;
    SqlCommand cmd = new SqlCommand();
    cmd.Connection = sqlConnection;
    cmd.CommandType = CommandType.Text;
    cmd.CommandText = inputSQLStatement;
    cmd.Connection.Open();
    try
    {
        cmd.ExecuteNonQuery();
    }
    catch (SqlException ex)
    {
        errorMessages.Clear();
        errorMessages.Append("The following errors were found in the SQL statement:\n\n");

        for (int i = 0; i < ex.Errors.Count; i++)
        {
            errorMessages.Append("Index #" + i + "\n" +
                "Message: " + ex.Errors[i].Message + "\n" +
                "LineNumber: " + ex.Errors[i].LineNumber + "\n" +
                "Source: " + ex.Errors[i].Source + "\n" +
                "Procedure: " + ex.Errors[i].Procedure + "\n");
        }
        MessageBox.Show(errorMessages.ToString());
    }
    finally
    {
        cmd.Connection.Close();
    }
}

Can someone tell me what might be the problem ? Do I need to perform a 'commit' somehow ?

EDIT:

I have found the problem, and have written up a solution below .. Thanks to all who helped me out though :)

Ahmad
  • 12,886
  • 30
  • 93
  • 146
  • What's in `inputSQLStatement`? – Roger Lipscombe Sep 24 '12 at 12:08
  • The SQL statement I'm trying to execute .. basically its an insert statement .. – Ahmad Sep 24 '12 at 12:09
  • You're not doing a .Open on your connection. - Sry just saw it's the last thing called on the connection. – Kevin Sep 24 '12 at 12:10
  • I am, right above the try statement .. – Ahmad Sep 24 '12 at 12:10
  • don't see a problem with the code what is the SQL you are passing in? – Kevin Sep 24 '12 at 12:11
  • An example inputSQLStatement coming into this function is this: `INSERT INTO Products (Name, Barcode, TypeID, Region, Comments, Enabled) VALUES ('werew', 'rew', 1, 'werwer', 'wer', 1)` – Ahmad Sep 24 '12 at 12:13
  • Try putting the .open statement inside the try catch - I think it should be in there anyway. – Paul Zahra Sep 24 '12 at 12:13
  • @PaulZahra, still not working .. no errors/exceptions, but record is not being saved .. Yup you're right, logically it should be in there .. – Ahmad Sep 24 '12 at 12:15
  • I'm not seeing a direct problem. Try wrapping the entire contents of the method in a try/catch and see if there is an Exception being thrown that you are not catching. – Kevin Sep 24 '12 at 12:17
  • @Kevin, just tried that as well .. Tried wrapping the whole code inside a try catch, and debugged through it line by line ... no exceptions detected .. – Ahmad Sep 24 '12 at 12:20
  • Last thing I know to check is that the db file is not set to read only. – Kevin Sep 24 '12 at 12:22
  • Right click on file, select Properties. Make sure that Read-only attribute is not checked. – Kevin Sep 24 '12 at 12:25
  • @Kevin, I don't see that option anywhere .. EDIT: I think you meant the actual MDF file properties .. no its not checked, and also the thing is if I try the query separately, it does store .. it just does not store if I'm using it from within my application .. – Ahmad Sep 24 '12 at 12:28
  • How are you checking if your record was inserted? Judging by your connection string you are using user instances http://msdn.microsoft.com/en-us/library/bb264564(v=sql.90).aspx – Goran Sep 24 '12 at 13:01

6 Answers6

8

I found the problem ! It was very simple, and it was stupid really :) .. The code above is all correct .. Yes, people pointed out optimizations, etc, but still the code above was correct.

The problem was that when I imported the TestDB.MDF file into my Visual 2010 project, a copy of that was made inside the project's folder. When you run/debug the program, another copy of the this file is made and is put in the \bin\Debug\ folder. In the connection string I was using, I had mentioned: AttachDbFilename=|DataDirectory|\TestBuildDB.mdf .. This meant that all reads/writes were done to the copy in the bin\Debug folder. However, the TestDB.MDF file I was looking into to verify if records were inserted or not, was in the project's folder ! So basically, there were two MDF files, and I was writing the records into one file, but was trying to find them in the other :)

When you add an MDF file into your VS2010 Project, VS2010 by default makes a connection to that MDF file, from where you can browse the stuff in that MDF file .. The MDF file used for this purpose was the one placed in the project's folder, NOT the one in bin\Debug\ folder. And like I said earlier, my code used the one in the bin\Debug folder :)

So what I've done now is that I've removed the Test.MDF file reference from my project, which removes the copy present in the project's folder. However, I DO have a copy of TestDB.MDF file in the bin\Debug\ folder, which I connect to from within my application. And if I want to browse the MDf file outside my project, I use SQL Management Studio. The only problem here is that an MDF file can only be used by one program at a given time. So if I have to use it with my application, I have to take it offline from SQL Management studio, and vica versa !

I hope this explanation helps someone out there :)

Ahmad
  • 12,886
  • 30
  • 93
  • 146
3

The solution to this problem is very simple just give the full path of the original MDF file in the connection String like this:

connectionString="Data Source=(LocalDB)\v11.0;AttachDbFilename=**C:\VISUAL STUDIO 2012\PROJECTS\ENGLISHTOHINDIDICTIONARY\ENGLISHTOHINDIDICTIONARY\DICTIONARY.MDF**;Initial Catalog=Dictionary;Integrated Security=false"
        providerName="System.Data.SqlClient"

That's it, your problem is solved.

Sufian
  • 6,405
  • 16
  • 66
  • 120
2

I had the same challenge, I simply changed the database property "Copy to Output Directory" from "Copy always" to "Do not copy" then moved my database.mdf (drag & drop from my IDE) into the bin\debug folder.

Tip: The bin directory is normally hidden, use the "Show All Files" to display it

bishop
  • 129
  • 1
  • 5
0

Provide a catch clause for all Exceptions. If there something wrong other than SqlException, you will never see what is it and your db will neved be updated. Imagine there is a FormatException...

Also check the return of ExecuteNonQuery : it's the number of rows affected by the query.

Cybermaxs
  • 24,378
  • 8
  • 83
  • 112
  • I tried this .. in fact I setup 3 catches at different points .. did not go into any catch .. Return of ExecuteNonQuery is 1, meaning that the code thinks a record WAS saved, but in fact it was not .. I think there is a rights issue somewhere .. – Ahmad Sep 24 '12 at 12:44
  • also try to add one handler to SqlConnection.InfoMessage. The InfoMessage event occurs when a message with a severity of 10 or less is returned by SQL Server. – Cybermaxs Sep 24 '12 at 12:51
0

First, you should always wrap up your IDisposable objects in a using to ensure they're closed and disposed of properly (and that connection pooling can do its thing). Second, when modifying data wrap up your sql in a transaction to maintain data integrity.

Try the following code and see if any exceptions are raised. I wouldn't normally recommend catching Exception as it's too general, I'd let that bubble up to the calling mechanism and handle it there - but for this instance it will show you any and all issues. I think your particular issue is at the .Open stage of the connection, so try stepping through.

public static void PerformDBWriteTransaction(string inputSQLStatement)
{
    DataTable returnDataTable = new DataTable();

    try
    {
        using (SqlConnection sqlConnection = new SqlConnection(connectionString))
        {
            sqlConnection.Open();

            using (SqlTransaction sqlTrans = sqlConnection.BeginTransaction())
            {
                try
                {
                    using (SqlCommand cmd = new SqlCommand(inputSQLStatement, sqlConnection))
                    {
                        cmd.CommandType = CommandType.Text;
                        cmd.Transaction = sqlTrans;
                        cmd.ExecuteNonQuery();
                    }
                }
                catch (SqlException sqlEx)
                {
                    sqlTrans.Rollback();

                    throw sqlEx;
                }

                sqlTrans.Commit();
            }
        }
    }
    catch (Exception ex)
    {
        errorMessages.Clear();
        errorMessages.Append("The following errors were found in the SQL statement:\n\n");

        for (int i = 0; i < ex.Errors.Count; i++)
        {
            errorMessages.Append("Index #" + i + "\n" +
            "Message: " + ex.Errors[i].Message + "\n" +
            "LineNumber: " + ex.Errors[i].LineNumber + "\n" +
            "Source: " + ex.Errors[i].Source + "\n" +
            "Procedure: " + ex.Errors[i].Procedure + "\n");
        }

        MessageBox.Show(errorMessages.ToString());
    }
}
Paul Aldred-Bann
  • 5,840
  • 4
  • 36
  • 55
  • I just replaced my entire function with yours, and it still did not work .. :( .. I don't think you closed the connection though .. I debugged through the code line by line too .. didn't go into any catches .. – Ahmad Sep 24 '12 at 12:38
  • @Ahmad the `using` closes the connection implicitly, very strange that a line-by-line debug doesn't show anything - are ALL lines (excluding the exception handling) executed? – Paul Aldred-Bann Sep 24 '12 at 12:46
  • Yes, except the ones insides the catches .. Also, I had to comment out the 4 lines in the error printing at the bottom, because, ex.Errors does not exist in this context .. apart from that, there were no faults in execution .. also, the return from ExecuteNonQuery is 1, meaning the code thinks that 1 record WAS inserted, whereas it was actually not inserted ... I feel the issue is not in the code, rather its the way I'm attaching the MDF file .. maybe its in some 'read-only' mode ? I've tried finding any such property, but I could not .. maybe you know something ? – Ahmad Sep 24 '12 at 12:51
  • @Ahmad I've just noticed that you're using SQL Express - you cannot connect directly to the .mdf file in this case, you need to connect to the local service hosted on your machine (which express installs) you'd need to attach your .mdf to this service and then modify your connection string to `Data Source=.\SQLEXPRESS; Initial Catalog=YourDatabaseNameWhenAttached; Integrated Security=True; Connect Timeout=30; User Instance=True` – Paul Aldred-Bann Sep 24 '12 at 13:02
  • thanks for your feedback, but I didn't quite get what you said .. You're saying I need to attach the MDF file to the instance SQL Express installs, and then use the connection string you've provided ? .. How do I do this attachment then ? And what would I put in `YourDatabaseNameWhenAttached` ? – Ahmad Sep 24 '12 at 13:31
  • @Ahmad you should have SQL Server Management Studio Express installed also, connect to your hosted instance (.\SQLEXPRESS with windows credentials) and then follow the instructions here: http://www.siue.edu/~dbock/cmis495-588ADO/Notes%20and%20Slides/AttachSqlServerDatabases.htm – Paul Aldred-Bann Sep 24 '12 at 13:49
  • thanks mate for your help .. I tried out your suggestion, but it didn't address the issue I was facing .. I found the problem, and have just posted a solution ! The cause was stupid really, but still a good observation I think .. – Ahmad Sep 26 '12 at 09:29
-1

Hi I am working on library database when I add student record executionNonQuery shows error like invalid column name page opens but saving data from not happening. Here I have given the code statement

public partial class add_student_info : Form
{
    SqlConnection con = new SqlConnection(@"Data Source=DESKTOP-SPT6GLG\SQLEXPRESS;Initial Catalog=library_managment;Integrated Security=True;Pooling=False");

    public add_student_info()
    {
        InitializeComponent();
    }

    private void button1_Click(object sender, EventArgs e)
    {

            con.Open();
            SqlCommand cmd = con.CreateCommand();
            cmd.CommandType = CommandType.Text;
            cmd.CommandText = "insert into student_info values('" + textBox1.Text + "','" + textBox2.Text + "','" + textBox3.Text + "','" + textBox4.Text + "'," + textBox5.Text + "," + textBox6.Text + "," + textBox7.Text + ")";
            cmd.ExecuteNonQuery();
            con.Close();

            MessageBox.Show("Student recorc addedd sussfully");

        }
    }
}
Ali Akbarpour
  • 958
  • 2
  • 18
  • 35
  • you have not provided an answer to the question. If you need to you can create your own question and reference this on if this answer did not work for you – M31 Mar 18 '18 at 08:08