0

Good day everyone,

Firstly I would like to thank anyone in advance who takes the time to look through this lengthy post.

Context: I am building a simple GUI interface using windows forms and c sharp that connects to a MySql database to perform CRUD operations.

Problem: I am trying to implement a method that would take the necessary MySql code elements as arguments and pull a table into a data grid view. I have produced 2 methods - 1 that takes arguments and the other one which is hard coded to pull the data.

After pulling the data I am able to insert/amend any records in the database with a SAVE button method. The issue is that when I use the method that takes the arguments to pull the data into the grid view I am not able to SAVE my changes as I get a null reference error. However when using the hard coded method I don't get any null errors and all works fine. For some reason when the sqlDataand dataTable variables are passed to the SAVE button method AFTER the grid view gets filled with the method based on arguments they end up as null. Any experts that have experience building these applications have any advice please?

Hard coded method for pulling data into grid view:

 private void fill_grid_view1(string sequelQueryString)
    {
        using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
        {
            mysqlConn.Open();
            sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
            sqlCommandBuilder = new MySqlCommandBuilder(sqlData);

            dataTable = new DataTable();
            sqlData.Fill(dataTable);

            dataGridView1.DataSource = dataTable;
        }   
    }

The SAVE button methods:

private void bttnSave_Click(object sender, EventArgs e)
    {

        save_changes_refresh(sqlData, dataTable);

    }

private void save_changes_refresh(MySqlDataAdapter given_data_adapter, DataTable given_data_table) 

    {
        try
        {
            given_data_adapter.Update(given_data_table);

            select_both_user_tweet();

            MessageBox.Show("Your changes have been saved successfully!"); //
        }
        catch (Exception errobj)
        {
            MessageBox.Show(errobj.Message.ToString());
        }

    }

The method I want to use to pull data into grid view based on given arguments:

 private void fill_given_grid_view (string sequelQueryString, MySqlDataAdapter given_data_adapter, DataTable given_data_table, DataGridView given_grid_view,
                                        MySqlCommandBuilder given_builder)

    {
        using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
        {
            mysqlConn.Open();
            given_data_adapter = new MySqlDataAdapter(sequelQueryString, mysqlConn);
            given_builder = new MySqlCommandBuilder(given_data_adapter);

            given_data_table = new DataTable();
            given_data_adapter.Fill(given_data_table);

            given_grid_view.DataSource = given_data_table;
        }
    }

All the new method does is pull data based on arguments so that if I had let's say 5 dataGridView elements I wouldn't need to hard code all five pull methods separately like I did in the first code snippet. And it works but it doesn't let me save any changes as mentioned above because of the sqlData and dataTable variables end up as null when I try to execute the save method.

Method that passes the needed parameters to fill_given_grid_view:

private void view_users_Click(object sender, EventArgs e) 
    {
        fill_given_grid_view("SELECT * FROM new_schema.user", sqlData, dataTable, dataGridView1, sqlCommandBuilder);

    }

EDIT: I've read the possible duplicate thread and it is useful however I struggle to understand why essentially using 2 methods that do the same thing one of them drops the sqlData and dataTable variables to null and the hard coded method from the first snippet does not drop the variables and keeps the needed values to pass into the SAVE method.

asleniovas
  • 193
  • 3
  • 21
  • Possible duplicate of [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – Renatas M. Nov 28 '18 at 13:31
  • I've read that thread and it was useful however what I am struggling to understand as to why the variables are set to null reference when using the wanted method but when using another it doesn't although both methods perform the same thing from a theoretic point of view – asleniovas Nov 28 '18 at 14:04
  • Put the breakpoint and debug. You will see when variables are initialized and when they are not. Just step through your code with debugger and watch the variables – Renatas M. Nov 28 '18 at 14:15
  • Thanks for the suggestions, I have tried that but unable to understand why the variables don't get carried over to the SAVE method, as if the wanted data pull method nullifies them on purpose after populating the grid view. The hard coded method does not nullify the variables and carries them over to the SAVE button as needed. – asleniovas Nov 28 '18 at 14:19
  • I am actually struggling to understand the flow of those method calls. When `fill_given_grid_view is called? Do `fill_given_grid_view` gets null's as parameters? Which line causing error? Add StackTrace to be able to get an idea whats going on. – Renatas M. Nov 28 '18 at 14:25
  • No, so when `fill_given_grid_view` is called it fills my grid view with a table. When I amend the grid view via the GUI and run `bttnSave_Click` that calls `save_changes_refresh` it does not work because `save_changes_refresh` takes `sqlData` and `dataTable` variables, but it does not as they come through as `null`. However, the `fill_grid_view1` method works fine and does the same thing as `fill_given_grid_view` it's just that I hard code `sqlData` and `dataTable` into the method. – asleniovas Nov 28 '18 at 14:36
  • What parameters do you pass to fill_given_grid_view? given_data_adapter is accessible in save method so it is accessible for all methods so why do you pass given_data_adapter to fill method then? Please edit question and add all class with relevant methods and variables. – Renatas M. Nov 28 '18 at 14:41
  • I've added the method which passes the parameters. I am not passing the `given_data_adapter` to fill method, it is passed from `bttnSave_Click` to the `save_changes_refresh` method that runs `given_data_adapter.Update(given_data_table)` line of code. Based on given info the correct table is updated in the database. But the `given` parameters end up `null` when the SAVE method tries to execute the first line of `Update` code, therefore it has nothing to save. The funny part is that the hard coded snippet works fine because it does not drop the `sqldata` and `dataTable` that hold needed values – asleniovas Nov 28 '18 at 15:17
  • I don't get it why you doing something like this. If you use adapter and datatable all over around - initialize them in constructor and not in separate methods - that makes code confusing. Your methods should use already initialized object or you create only method wide variables. – Renatas M. Nov 29 '18 at 08:30
  • @Reniuz Thank you for your comments. I actually initialize all variables related to MySql in the beginning of my program as `private MySqlDataAdapter sqlData = null; private DataTable dataTable = null ` etc., and then they get passed around via methods where they are populated with values. What I'm trying to achieve is have `fill_given_grid_view` handle all grid view population operations instead of having 1 method handle 1 grid view like in `fill_grid_view1`. Imagine I have 10 grid views in my GUI that handle separate tables, then I would need to write 10 `fill_grid_view1;2;3;4 etc` methods. – asleniovas Nov 29 '18 at 11:55
  • @Reniuz but as you can see, `fill_given_grid_view` brakes my SAVE code due to the variables being `null` and not initialized back in `fill_given_grid_view` to get picked up by the SAVE method . Sorry if this is confusing but I appreciate your time to comment my work. – asleniovas Nov 29 '18 at 11:58
  • Ok from my point of view...I would have fill method which only gets lets say select query and grid. It will create adapter, create datatable fill it and set datatable as grids datasource. Now save method should do same-get update query and grid. Then you create adapter with update query, get data table from grids datasource like `var dt = (DataTable)grid.DataSource;` and execute update on it. That's it. You will not require adapter and datatable anywhere else. – Renatas M. Nov 29 '18 at 12:19
  • @Reniuz Thank you very much, fixed with your suggestions! Sorry for the pain, beginner in programming. If you can copy paste this as an answer I will mark it. Last question though, in this line `var dt = (DataTable)grid.DataSource;` parameter is on the left side, does it matter if it goes left or right of `grid`? I'm always used to right side... – asleniovas Nov 29 '18 at 13:47
  • Are you asking what is difference between `(DataTable)grid.DataSource` and `grid.DataSource as DataTable`? – Renatas M. Nov 29 '18 at 15:32
  • `(DataTable)grid.DataSource` and `grid(DataTable).DataSource` – asleniovas Nov 29 '18 at 15:48
  • That one on the right should not compile. – Renatas M. Nov 30 '18 at 08:31
  • Yeah it does not make any sense. But your solution is not different to let's say `myGridView.DataSource as DataTable`, just a different way of expressing? – asleniovas Nov 30 '18 at 09:14
  • You should use [unboxing](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/types/boxing-and-unboxing), when you are sure that `DataSource` holds `DataTable`. If it holds other type and you try to unbox to `DataTable` you will get invalid cast exception. Use [as](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/as) in case when DataSource will hold other than DataTable type using `as` you will get null as result. Use it like this: `var data = DataSource as DataTable; if(data != null){//we have data and using it here }` – Renatas M. Nov 30 '18 at 09:24
  • Got it, thanks a million – asleniovas Nov 30 '18 at 09:27

1 Answers1

0

Based on @Reniuz suggestions the fill_given_grid_view and save_changes_refresh methods had to be rewritten to take in dataGridView and sequelQueryString as arguments. sqlData and dataTable variables are not used anywhere as input to a method. Code examples below:

Method to pull data into a grid view based on input:

        private void fill_given_grid_view (string sequelQueryString, DataGridView given_grid_view) /* master method that takes an SQL query and grid view as input 
                                                                                                  and displays a table accordingly */

    {
        using (MySqlConnection mysqlConn = new MySqlConnection(db_connection)) // using stored connection params
        {
            mysqlConn.Open();
            sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
            sqlCommandBuilder = new MySqlCommandBuilder(sqlData);

            dataTable = new DataTable(); // new dataTable created, filled based on given query and set as the DataSource of the grid given as input to the method
            sqlData.Fill(dataTable);

            given_grid_view.DataSource = dataTable;
        }
    }

SAVE method rewritten with grid view and sequel string as arguments:

private void save_changes(string sequelQueryString, DataGridView given_grid_view) /* master save method that initializes a new Data Adapter based on given sequel string 
                                                                                         that saves any changes inputted into the given grid view */

    {
        using (MySqlConnection mysqlConn = new MySqlConnection(db_connection))
        {
            mysqlConn.Open();
            sqlData = new MySqlDataAdapter(sequelQueryString, mysqlConn);
            sqlCommandBuilder = new MySqlCommandBuilder(sqlData);

            var current_data_table = (DataTable)given_grid_view.DataSource; // if any changes occur in given grid view db table is updated when a "SAVE" button is clicked
            sqlData.Update(current_data_table);
        }
    }
asleniovas
  • 193
  • 3
  • 21