C# version here.
There is all sorts of literature on this topic but people still keep asking the same questions. I'm creating this thread so I can send people here to look at some example code that I know will demonstrate all the principles they need. These principles can be extended or adjusted and applied to any data access situation. This code uses members of the System.Data.SqlClient namespace. If you're not using SQL Server then it's a simple matter of switching to the corresponding types of the appropriate namespace for your data source. For example, if you're using an Access database then you'd use an OleDb.OleDbConnection rather than an SqlClient.SqlConnection.
Retrieving a single value. The ExecuteScalar method returns the value from the first column of the first row of the query's result set:Retrieving multiple records that will be read and discarded. The ExecuteReader method provides read-only, forward-only access to the entire result set:vb.net Code:
Using connection As New SqlConnection("connection string here") Using command As New SqlCommand("SELECT SUM(Quantity) FROM StockItem", _ connection) connection.Open() Dim totalQuantity As Double = CDbl(command.ExecuteScalar()) 'Use totalQuantity here. End Using End UsingRetrieving multiple records for display that will not be updated. The DataTable.Load method will populate a DataTable with the result set exposed by a DataReader:vb.net Code:
Using connection As New SqlConnection("connection string here") Using command As New SqlCommand("SELECT Quantity, Unit, Name FROM StockItem", _ connection) connection.Open() Using reader As SqlDataReader = command.ExecuteReader() While reader.Read() MessageBox.Show(String.Format("There are {0} {1} of {2} remaining in stock.", _ reader("Quantity"), _ reader("Unit"), _ reader("Name"))) End While End Using End Using End UsingNote that DataTable.Load is new in .NET 2.0. I have provided code here to populate a DataTable from a DataReader in .NET 1.xvb.net Code:
Using connection As New SqlConnection("connection string here") Using command As New SqlCommand("SELECT Quantity, Unit, Name FROM StockItem", _ connection) connection.Open() Using reader As SqlDataReader = command.ExecuteReader() Dim table As New DataTable table.Load(reader) 'The table can be used here to display the data. 'That will most likely be done via data-binding but that is NOT a data access issue. End Using End Using End Using
Retrieving multiple records for display and editing, then saving the changes. The DataAdapter.Fill method populates a DataTable with the contents of the result set of a query. The DataAdapter.Update method saves the changes in a DataTable in accordance with the SQL statements contained in the DeleteCommand, InsertCommand and UpdateCommand properties:Note that if your query involves only one table and it has a primary key then you can take the easy option and use a CommandBuilder instead of creating the non-query commands yourself:vb.net Code:
Private connection As New SqlConnection("connection string here") Private adapter As New SqlDataAdapter("SELECT ID, Name, Quantity, Unit FROM StockItem", _ connection) Private table As New DataTable Private Sub InitialiseDataAdapter() Dim delete As New SqlCommand("DELETE FROM StockItem WHERE ID = @ID", Me.connection) Dim insert As New SqlCommand("INSERT INTO StockItem (Name, Quantity, Unit) VALUES (@Name, @Quantity, @Unit)", Me.connection) Dim update As New SqlCommand("UPDATE StockItem SET Name = @Name, Quantity = @Quantity, Unit = @Unit WHERE ID = @ID", Me.connection) delete.Parameters.Add("@ID", SqlDbType.Int, 4, "ID") insert.Parameters.Add("@Name", SqlDbType.VarChar, 100, "Name") insert.Parameters.Add("@Quantity", SqlDbType.Float, 8, "Quantity") insert.Parameters.Add("@Unit", SqlDbType.VarChar, 10, "Unit") update.Parameters.Add("@Name", SqlDbType.VarChar, 100, "Name") update.Parameters.Add("@Quantity", SqlDbType.Float, 8, "Quantity") update.Parameters.Add("@Unit", SqlDbType.VarChar, 10, "Unit") update.Parameters.Add("@ID", SqlDbType.Int, 4, "ID") Me.adapter.DeleteCommand = delete Me.adapter.InsertCommand = insert Me.adapter.UpdateCommand = update Me.adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey End Sub Private Sub GetData() 'Retrieve the data. Me.adapter.Fill(Me.table) 'The table can be used here to display and edit the data. 'That will most likely involve data-binding but that is not a data access issue. End Sub Private Sub SaveData() 'Save the changes. Me.adapter.Update(Me.table) End SubSaving changes directly to one or more records in the database. The Command.ExecuteNonQuery method will execute any SQL statement and not return a result set. It can be used to execute a query but you'd never use it for that unless you were populating a view or temp table. Usually you'd use ExecuteNonQuery to execute a DELETE, INSERT or UPDATE command:vb.net Code:
Private connection As New SqlConnection("connection string here") Private adapter As New SqlDataAdapter("SELECT ID, Name, Quantity, Unit FROM StockItem", _ connection) Private builder As New SqlCommandBuilder(adapter) Private table As New DataTable Private Sub InitialiseDataAdapter() Me.adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey End Sub Private Sub GetData() 'Retrieve the data. Me.adapter.Fill(Me.table) 'The table can be used here to display and edit the data. 'That will most likely involve data-binding but that is not a data access issue. End Sub Private Sub SaveData() 'Save the changes. Me.adapter.Update(Me.table) End SubNote that I have not provided code for disposing objects or catching exceptions. Those are general topics that do not relate specifically to data access so they should be learned elsewhere.vb.net Code:
Using connection As New SqlConnection("connection string here") Using command As New SqlCommand("INSERT INTO StockItem (Name, Quantity, Unit) VALUES (@Name, @Quantity, @Unit)", _ connection) command.Parameters.AddWithValue("@Name", someName) command.Parameters.AddWithValue("@Quantity", someQuantity) command.Parameters.AddWithValue("@Unit", someUnit) connection.Open() command.ExecuteNonQuery() End Using End Using
Note also the DataAdapter.Fill, DataAdapter.Update and Command.ExecuteNonQuery methods are all functions. All three return an Integer that contains the number of records that were either retrieved (Fill) or saved (Update, ExecuteNonQuery).
Finally, this code uses all the "old style" data access types. In .NET 2.0 I suggest creating a Data Source to generate a typed DataSet and TableAdapters. The principles there are basically the same except that you have to write less code. All SQL statements are added via the DataSet designer and all you really have to do is create TableAdapters and call their methods. Even the connections are hidden within the TableAdapters so it's all much easier. Understanding what's above should help you understand how TableAdapters work internally though.
EDIT: Note that I have updated the code examples slightly in this post and post #3 to more accurately reflect real usage situations, particularly using a DataAdapter to get and save data in separate methods rather than in the same method.



Reply With Quote

