C# Database Basics an ADO.NET Tutorial

Total Page:16

File Type:pdf, Size:1020Kb

C# Database Basics an ADO.NET Tutorial

C# Database Basics – An ADO.NET Tutorial Chris Morgan, .NET SIG of the North Texas PC User Group April 5, 2014

This tutorial shows how to use basic ADO.NET commands and build an application with an editable grid bound to an Access or SQL Server database. It is based on the book C# Database Basics by Michael Schmalz, O’Reilly Press, 2012.

The purpose of the application is to display for edit any selected table in a given database. A DataGridView object will be used to display the data in a Windows Form. The project will have a single form with two grids and a few buttons. The user will scroll through a list of the tables in a database and select which one he wants to edit. The selected table will be displayed at the top of the form. The style of development will have a strong emphasis on writing code rather than setting properties of objects. In summary, here is what we will do to create this app:

1. Create a Window Forms project in Visual Studio and place a few controls on the form, including a DataGridView. Then, switch to the code view and start adding code to finish the application.

2. Add some class-level variables.

3. Create a DataAdapter. It needs both a connection string and a select query.

4. Create a CommandBuilder object referencing the above DataAdapter.

5. Create a DataTable object.

6. Fill the DataTable using the ‘Fill’ method of the DataAdapter. This one method does the following: opens a connection , executes the select query, defines and populates the DataTable, and then closes the connection. A lot is done with this one method!

7. Create a BindingSource object with the DataTable as the DataSource. Then, assign it as the DataSource of the DataGridView. The DataSource of the DataGridView is the BindingSource, and the DataSource of the BindingSource is the DataTable.

8. Add all the column names of the table (referenced in the Select query) to a combo box list.

9. Populate a second DataGridView on the form with a list of the “Table” objects in the database.

10. Add code to make the grid editable.

11. Create a button that will filter all the rows in the first grid, based on which cell is highlighted. Create a second button to clear the filter.

12. Create a button that will switch which table is displayed in the top grid. It will be the table currently highlighted (selected; clicked-on) in the second grid on the form.

Important classes used in this application:  DataGridView – Two of these will be used. One to display the rows of a selected table. The other will show a list of all the tables in the database.

 DataTable – This object will contain a local, disconnected representation of the selected table from either SQL Server or Access. It will contain only the columns and rows specified by the select query.

 DataAdapter – This class is used to control getting and saving data. It stands between the DataTable and the source of the data and controls all the traffic between the two.

 CommandBuilder – Takes care of creating the CRUD SQL commands used by the DataAdapter.

 BindingSource – This class has the commands used for navigation in the DataTable used by the DataGridView. It sits between the DataTable and the DataGridView.

Steps to perform for the tutorial (yellow highlighting indicates commands that would need to change if using MS SQL (or, SQL Server Compact Edition) rather than an Access database):

1. Set up Access (or a local SQL Server) running on your computer. Optionally, you can use SQL Server Compact Edition, if you have it installed.

2. Download and attach the Northwind database in this SQL Server.

http://www.microsoft.com/en-us/download/details.aspx?id=23654

The download for an Access version can be found here:

http://office.microsoft.com/en-us/templates/results.aspx?qu=northwind&ex=1&av=all&AxInstalled=1&c=0

3. Open Visual Studio. Note: Since this tutorial uses pretty basic command, you can use almost any version of Visual Studio to perform this tutorial. The commands and objects used are based on .NET 2.0+ ADO.NET.

4. File  New Project  Windows Form Application. Give it a name, like “EditingDatabase”.

5. From the toolbox on the left side of the VS screen (If not visible, go to View  Toolbox to show it)

6. Drag the following controls from the Toolbox onto the form:

a. DataGridView, from the Data section. Leave “Source” as none.

b. TextBox, from the Common section

c. ComboBox, from the Common section

d. Two Buttons, from the Common section

e. Another DataGridView – uncheck all the “Enable” checkboxes on the popup. Leave “Source” as none.

7. Go to “Code View” by pressing , or and choose it from the popup menu. 8. Add the following namespace to the list (when using Access file): using System.Data.OleDb; //System.Data.SqlClient

9. Add the following class-level variables (i.e., “fields”) to the Form1 class:

public string connString;

public string query;

public OleDbDataAdapter dAdapter; //SqlDataAdapter

public DataTable dTable;

public OleDbCommandBuilder cBuilder; //SqlCommandBuilder

public DataView myDataView;

10. In Form1, after the “initialize_component();”, add the following code:

connString = "Provider=Microsoft.ACE.OLEDB.12.0;

Data Source=C:\\users\\chris\\documents\\Northwind.accdb";

query = "SELECT * FROM Products";

dAdapter = new OleDbDataAdapter(query, connString); //SqlDataAdapter

dTable = new DataTable();

cBuilder = new OleDbCommandBuilder(dAdapter); //SqlCommandBuilder

cBuilder.QuotePrefix = "[";

cBuilder.QuoteSuffix = "]";

11. Then, after the code just entered, add the following code:

dAdapter.Fill(dTable);

BindingSource bndSource = new BindingSource();

bndSource.DataSource = dTable;

this.dataGridView1.DataSource = bndSource;

for (int q = 0; q <= dataGridView1.ColumnCount - 1; q++)

{

this.comboBox1.Items.Add(this.dataGridView1.Columns[q].HeaderText.ToString());

} OleDbConnection xyz = new OleDbConnection(connString); //SqlConnection

xyz.Open();

DataTable tbl = xyz.GetSchema("Tables");

dataGridView2.DataSource = tbl;

myDataView = dTable.DefaultView;

12. Add the following code after the Form1() method:

private void Cell_Update(object sender, DataGridViewCellEventArgs e)

{

try

{

dAdapter.Update(dTable);

this.textBox1.Text = "Updated " + System.DateTime.Now.ToString();

}

catch (OleDbException f) //SqlException

{

this.textBox1.Text = "Not Updated " + f.Source.ToString();

}

}

13. Then, to “wire up” this code to the grid so that the event of changing rows will call this method to save any row edits back to the database do the following:

a. Switch back to the Design View on Form1 – press or and select “View Designer”

b. on the first datagrid and select “Properties”

c. on the lightning bolt

d. Find the “RowValidated” event and select the “Cell_Update” method; the name of the method we just added in the previous step. 14. Now we’re going to set up some filtering on the grid. This will allow clicking on a grid cell and show only those rows which have the same value. To start, change the button on the screen to say “Set Filter” and “Clear Filter”

a. In Design View, on the button, choose properties, and change the “Text” property of each button – “Set Filter” for button1 and “Clear Filter for button2.

15. Now, enter the following code below the “Cell_Update” method. It will be called when we click on button1 to carry out the filtering action:

private void Filter_Click(object sender, EventArgs e)

{

string mystr;

if (myDataView.RowFilter == "")

{

mystr = "[" + dataGridView1.CurrentCell.OwningColumn.HeaderText.ToString() + "]";

mystr += " = '" + dataGridView1.CurrentCell.Value.ToString() + "'";

myDataView.RowFilter = mystr;

// Or, set bndSource.Filter = mystr;, if it was a “class” level variable

}

else

{

mystr = myDataView.RowFilter + " and ";

mystr += "[" + dataGridView1.CurrentCell.OwningColumn.HeaderText.ToString()+"]";

mystr += " = '" + dataGridView1.CurrentCell.Value.ToString() + "'";

myDataView.RowFilter = mystr;

// Or, set the bndSource.Filter = mystr;, if it was a “class” level var

}

}

16. Then, wire up this method to button1 by: a. Switch back to Design View

b. on the “Set Filter” button

c. Choose “Properties” and find the “Click” event

d. Choose the method “Filter_Click” from the dropdown for this event

17. Now we’ll create the code to undo the filter. Add the following method after the Filter_Click method:

private void Clear_Filter(object sender, EventArgs e)

{

myDataView.RowFilter = "";

// Or, set bndSource.Filter = ""; if it was a “class” level var

}

18. And wire up the Click event on button2 (Clear Filter) to this method.

The next change is an interesting one. What we have in the second grid is a list of the table objects in the database. We can use this grid to select which table is displayed in the upper grid with the final button we will add.

19. Add another button to the form and place it just above the second grid. Right justify it. Change the Text property to “Change Source”.

20. Add the following code after the last code added above; the Clear_Filter method.

private void Change_Data_Source(object sender, EventArgs e)

{

string tbl_str = dataGridView2.CurrentRow.Cells[2].Value.ToString();

query = "SELECT * FROM [" + tbl_str + "]";

dAdapter = new OleDbDataAdapter(query, connString); //SqlDataAdapter

dTable = new DataTable();

cBuilder = new OleDbCommandBuilder(dAdapter); //SqlCommandBuilder

cBuilder.QuotePrefix = "[";

cBuilder.QuoteSuffix = "]";

dAdapter.Fill(dTable);

BindingSource bSource = new BindingSource(); // NOTE: this is a different var name. bSource.DataSource = dTable; //NOTE: But the DefaultView is what is actually used.

this.dataGridView1.DataSource = bSource;

for (int q = 0; q <= dataGridView1.ColumnCount - 1; q++)

{

this.comboBox1.Items.Add(this.dataGridView1.Columns[q].HeaderText.ToString());

}

myDataView = dTable.DefaultView;

}

Important note: What is not clear about the way this is programmed is that setting the RowFilter property on the DefaultView (via the ‘myDataView’ variable) actually filters the rows displayed in the grid. That is, even though the DataTable is what was set as the DataSource on bSource, filtering the DataView actually results in the filtered set of rows being displayed. In other words, when binding a DataTable to a grid, it is, in fact, binding the ‘DefaultView’ of the DataTable to the grid rather than the DataTable itself. Hence, when we change properties of the DataView we wind up changing the set of rows (DataViewRows) that are displayed by the grid.

21. Now go back to the button just added and set the Click event to use this new method.

That’s it. If everything was entered correctly you should be able to run the program. It should look like this: Miscellaneous Notes 1. Using an Access, SQL Server, or SQL Server Compact Edition Database It is a relatively easy task to switch between different databases in this sample application. The namespace reference will be one of these: System.Data.SqlClient, System.Data.OleDb, or System.Data.SqlServerCe. Then, when creating objects that connect to one of these databases, you must create objects in the appropriate namespace. Here is a table that shows the various class names:

SQL Server SQL Server Compact Edition Access System.Data.SqlClient System.Data.SqlServerCe System.Data.OleDb SqlConnection SqlCeConnection OleDbConnection SqlCommand SqlCeCommand OleDbCommand SqlDataAdapter SqlCeDataAdapter OleDbDataAdapter SqlCommandBuilder SqlCeCommandBuilder OleDbCommandBuilder SqlException SqlCeException OleDbException SqlDataReader SqlCeDataReader OleDbDataReader Note: If the System.Data.SqlServerCe namespace isn’t available in your project, add a “reference” to the DLL in the Solution Explorer, References section: on “References”  pick “Add Reference”  click on “Extensions”  put a check on “System.Data.SqlServerCe”.

2. Using a SqlDataReader: static void RetrieveMultipleResults(SqlConnection conn) { using (conn) // “using” takes care of opening and closing the connection. { SqlCommand command = new SqlCommand( "SELECT CategoryID, CategoryName FROM dbo.Categories;" + "SELECT EmployeeID, LastName FROM dbo.Employees", conn); conn.Open(); SqlDataReader reader = command.ExecuteReader(); while (reader.HasRows) { Console.WriteLine("\t{0}\t{1}", reader.GetName(0), reader.GetName(1)); while (reader.Read()) { Console.WriteLine("\t{0}\t{1}", reader.GetInt32(0), reader.GetString(1)); } reader.NextResult(); } } }

3. LINQ to whatever: LINQ to DataSet allows developers to create complex, powerful queries over a DataSet by using LINQ. A LINQ to DataSet query returns an enumeration of DataRow objects, however, which is not easily used in a binding scenario. DataView can be created from a LINQ to DataSet query and takes on the filtering and sorting characteristics of that query. LINQ to DataSet extends the functionality of the DataView by providing LINQ expression-based filtering and sorting, which allows for much more complex and powerful filtering and sorting operations than string-based filtering and sorting. See Data Binding and LINQ to DataSet for more information. (http://msdn.microsoft.com/en-us/library/bb552413(v=vs.110).aspx)

4. Entity Framework More to come here…

Recommended publications