programming4us
programming4us
DATABASE

ADO.NET Programming : Microsoft SQL Server CE (part 4) - Updating a SQL Server CE Database, The SqlCeDataAdapter Class

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019

7. Updating a SQL Server CE Database

Now that we have presented data to the user, we’ll continue by allowing the user to modify that data and submit those modifications to the database. We already presented an example of this when we first populated our database. So, the code you are about to see is very similar to code you have already seen.

The application that allows the user to change the product name does so by reacting to the textProductName.Validated event as shown here:

private void textProductName_Validated(object sender,
EventArgs e)
{
   //  Update this product row in the database.
   UpdateSelectedRow(int.Parse(textProductID.Text), textProductName.Text);
}

The called routine updates the product row as shown in Listing 6.

Listing 6. The UpdateSelectedRow Method
private void UpdateSelectedRow(int intProductID,
                               string strProductName)
{
   //  A connection and a command
   SqlCeConnection connDB = new SqlCeConnection(strConn);
   SqlCeCommand cmndDB = new SqlCeCommand();
   //  Open the connection.
   connDB.Open();

   //  Update the product name for the selected product.
   cmndDB.Connection = connDB;
   cmndDB.CommandText =
      " UPDATE Products " +
      " SET ProductName = " + "'" + strProductName + "'" +
      " WHERE ProductID = " + intProductID;
   cmndDB.ExecuteNonQuery();

   //  Close the connection.
   connDB.Close();
}

If the application allowed more than one field to be updated, we would set a “needs updating” flag within the Validated event handler of each field and react to the ComboBox control’s SelectedIndexChanged event and the form’s Close event by doing the update at that point, if needed.

If this application is the only application accessing a database, it does not need to open and close the connection each time a query is submitted to the database. In that situation, we could move the Open and Close calls into the form’s Load and Closed events, respectively.

You have now seen how to use the SqlCeConnection, SqlCeCommand, and SqlCeDataReader classes to retrieve data from a SQL Server CE database, present that data to the user in controls on the form, accept changes from the user, and submit those changes back to the database. And that, in turn, completes our coverage of SQL Server CE in the two-tiered application.

8. The SqlCeDataAdapter Class

It is time to address the three-tiered approach, the approach that has you move data between your SQL Server CE database and a data set. You cannot do that without using and understanding the SqlCeDataAdapter class, the primary means for moving data between a database and a data set.

8.1. Using a SqlCeDataAdapter Object to Retrieve Data

Just as the SqlCeCommand class has a property that holds the SqlCeConnection object to be used, the SqlCeDataAdapter class has a SelectCommand property that holds the SqlCeCommand object to be used to retrieve the data. The SqlCeDataAdapter class also holds three other command properties, all optional, for inserting database records (InsertCommand), updating database records (UpdateCommand), and deleting database records (DeleteCommand).

It also has the Fill method, which is used to connect to the database, execute the SELECT command, create the data table if necessary, and place the selected rows into the data table. Thus, the following code creates a data table named Categories in a previously created data set named dsetDB, connects to the ourProduceCo database, submits the SELECT statement, and places the returned rows into the Categories table:

SqlCeDataAdapter daptDB =
      new SqlCeDataAdapter(
         "SELECT * FROM Categories",
         "Data Source=My Documents\ourProduceCo.sdf");
daptDB.Fill(dsetDB, "Categories");

When you look at the code, it seems that only one object, the SqlCeDataAdapter object, is being created, for there is only one new function call. Actually, four objects are created; one is then disposed, and the remaining three are kept. The overloaded constructor shown here created a connection object and a command object from the parameters we provided, as well as creating the data adapter object. A reference to that command object is now stored in the adapter’s SelectCommand property, and a reference to the connection object is now stored in the command object’s Connection property. A fourth object, a data reader object, was created, was used to retrieve the rows, and was then closed and disposed.

The second parameter of the Fill method is the name to be given to the new data table in the data set. This name is completely unrelated to any table name in the underlying database. It may be the same name as a database table name, but no inherent relationship is assumed based on the choice of name.

The Fill method leaves the connection object in the state in which the method found the object. If the connection is open at the time the method is called, the connection is left open. If the connection is closed at the time the method is called, the Fill method opens the connection, retrieves the rows, places them into the data table, and closes the connection.

The Fill method creates a new data table if a data table of the same name does not already exist. If the data table does exist, primary key values are used to determine whether each incoming row should create a new row or update an existing row.

At this point it’s reasonable to ask, “Why is a separate object needed to move the data between the database and the data set? Why can’t the data table just ‘pull’ the rows in, similar to the way an ADO Recordset object pulls data into itself by using its Open method?”

A data table cannot load itself because it is provider-independent. That is, the DataSet and DataTable classes have no knowledge of SQL Server, Pocket Access, or SQL Server CE. They do not know how to perform such tasks as translating the underlying data types into .NET data types or obtaining schema definitions from the underlying data source. We need a provider-specific class to act as the middleware. When the database is SQL Server CE, SqlCeDataAdapter is that class.

Although not mandatory, it is a good practice to have a separate instance of SqlCeDataAdapter for each data table instance. If your application uses the SqlCeDataAdapter class to update the database, having a separate SqlCeDataAdapter object for each table is highly recommended.

8.2. Using a SqlCeDataAdapter Object to Update a Database

Remember that the SqlCeDataAdapter object lies between the DataSet object and the underlying database. The SqlCeDataAdapter object is used to pull the data from the database and place it into the data table, and it can be used to push any changes made to the data in the data table back to the database. Just as a SqlCeDataAdapter object has a SelectCommand property, it also has InsertCommand, UpdateCommand, and DeleteCommand properties, each holding a SqlCeCommand object. These commands are used to push changes made to the data tables back to the database. They are called by the SqlCeDataAdapter object’s Update method. You can call them directly, but normally you let the Update method do it for you.

Coming up with the parameterized SQL statements for these command objects may be very simple or quite difficult. It all depends on the complexity of the SELECT statement in the SelectCommand property. The SqlCeDataAdapter object can build the InsertCommand, UpdateCommand, and DeleteCommand command objects for you if you give it some help (which is provided by the SqlCeCommandBuilder class) and if all of the following conditions are true.

  • The SelectCommand property’s SELECT statement accesses just one database table.

  • The table being accessed has a primary key or unique constraint.

  • The columns that make up that constraint are in the SELECT clause of the SELECT statement.

  • Each data element in the output of the SELECT statement can be traced back to a single data element in the database (no literals, aggregates, or functions).

If your SELECT statement meets these criteria, and if you have created a SqlCeCommandBuilder object and associated it with the SqlCeDataAdapter object prior to calling the SqlCeDataAdapter object’s Update method, the SqlCeCommandBuilder object builds the Insert, Update, and Delete command objects for you.

To illustrate this, we add a simple form to our project for updating category information, as shown in Figure 8.

Figure 8. The Category Modification Form


Listing  7 shows the code for this form. Most of it is familiar, consisting of creating and loading the data set and binding to the controls. New concepts in the code are the creation of the SqlCeCommandBuilder object in the Load event handler and the update-specific code in the Closing event handler.

Listing 7. The Category Modification Form Class
using System;
using System.Data;
using System.Data.Common;
using System.Data.SqlServerCe;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

namespace CreateDatabase
{
   /// 
   /// Summary description for FormUpdate
   /// 
   public class FormUpdate : System.Windows.Forms.Form
   {
      internal System.Windows.Forms.Panel panelCategory;
      internal System.Windows.Forms.ComboBox comboCategoryIDs;
      internal System.Windows.Forms.TextBox textCategoryName;
      internal System.Windows.Forms.Label lblCategoryName;
      internal System.Windows.Forms.TextBox textCategoryID;
      internal System.Windows.Forms.Label lblCategoryID;

      public FormUpdate()
      {
         InitializeComponent();
      }

      protected override void Dispose( bool disposing )
      {
         base.Dispose( disposing );
      }

      #region Windows Form Designer generated code

      //  Connection string
      private string  strConn =
         "Data Source=" + @"My Documents\ourProduceCo.sdf";

      //  The data set, adapter, table
      private DataSet dsetDB;
      private SqlCeDataAdapter daptCategories;
      private DataTable dtabCategories;

      private bool boolLoading = true;


      private void FormUpdate_Load(object sender, EventArgs e)
         //  Present a close box.
      {
         this.MinimizeBox = false;

         //  Create the data set.
         dsetDB = new DataSet("Produce");

         //  Create the data adapter.
         daptCategories = new
            SqlCeDataAdapter("SELECT CategoryID, CategoryName " +
                             "  FROM Categories",
            strConn);

         //  Create the command builder for the adapter.
         SqlCeCommandBuilder cbldCategories =
            new SqlCeCommandBuilder(daptCategories);

         //  Create and fill the data table, and
         //     save a reference to it.
         daptCategories.Fill(dsetDB, "Categories");
         dtabCategories = dsetDB.Tables["Categories"];

         //  Bind the combo box with the category names.
         comboCategoryIDs.DataSource = dtabCategories;
         comboCategoryIDs.DisplayMember = "CategoryName";
         comboCategoryIDs.ValueMember = "CategoryID";
         comboCategoryIDs.SelectedIndex = 0;

         //  Load labels with data table column names.
         lblCategoryID.Text = "CategoryID";
         lblCategoryName.Text = "CategoryName";

         //  Bind the data table's columns to the text boxes.
         textCategoryID.DataBindings.Add
            ("Text", dtabCategories, "CategoryID");
         textCategoryName.DataBindings.Add
            ("Text", dtabCategories, "CategoryName");

         //  Give the panel some tone.
         panelCategory.BackColor = Color.Beige;
         //  Loading is finished.
         boolLoading = false;
         comboCategoryIDs.SelectedIndex = 0;
      }

      private void textCategoryName_Validated(object sender,
                                              EventArgs e)
      {
         //  Force the current modification to complete.
         this.BindingContext[dtabCategories].EndCurrentEdit();
      }

      private void FormUpdate_Closing(object sender,
                                      CancelEventArgs e)
      {
         //  Force the current modification to complete.
         this.BindingContext[dtabCategories].EndCurrentEdit();

         //  Push data set changes back to the database.
         daptCategories.Update(dsetDB, "Categories");
      }
   }
}

					  

Regardless of whether you are letting the SqlCeCommandBuilder object build the adapter’s three modification commands or you are building them programmatically yourself, calling the SqlCeDataAdapter object’s Update method pushes changes that have been made in the data set back to the database. The Update method does this by examining the row status of each row of the data table and then executing the Insert, Update, or Delete command as necessary.

As we mentioned earlier, never call the DataTable object’s AcceptChanges method just prior to calling the SqlCeDataAdapter object’s Update method. The AcceptChanges method sets all row statuses to Unchanged, which means the Update method would find no rows to update.

Unlike the adapter class for use with SQL Server, the SqlCeDataAdapter object does not detect conflicts when updating a database. Conflict detection prevents an application from modifying data that has been modified by some other application since the first application read the data. This ensures users that they are updating data whose values are still the values being presented to the user. In a multiuser environment, conflict detection is a very beneficial guardian; in the single-user world, it is a lot of overhead. If the user runs two applications to update the same data at the same time, the SqlCeDataAdapter object quite rightly lets the user trash his or her own updates if the user chooses to do so.

Even though you use an adapter to bring data into a data set, using it to push changes back to the database is always optional. You can always write your own DML statements and place them into the CommandText properties of the adapter’s command objects. As we mentioned, if the SELECT statement is sufficiently complex, the SqlCeCommandBuilder object cannot generate the Insert, Update, and Delete statements; you have to write them yourself.

You might want to write those statements yourself for additional control or application documentation reasons. Your application can always create a connection and a command object and use the command object’s ExecuteNonQuery method to submit an update to a database. And for reasons we will explain in the upcoming Microsoft SQL Server section, you are more likely to provide your own updating when connected to SQL Server rather than to SQL Server CE. But first we examine one last aspect of SQL Server CE programming: obtaining information about a database’s schema.

Other  
 
Top 10
Free Mobile And Desktop Apps For Accessing Restricted Websites
MASERATI QUATTROPORTE; DIESEL : Lure of Italian limos
TOYOTA CAMRY 2; 2.5 : Camry now more comely
KIA SORENTO 2.2CRDi : Fuel-sipping slugger
How To Setup, Password Protect & Encrypt Wireless Internet Connection
Emulate And Run iPad Apps On Windows, Mac OS X & Linux With iPadian
Backup & Restore Game Progress From Any Game With SaveGameProgress
Generate A Facebook Timeline Cover Using A Free App
New App for Women ‘Remix’ Offers Fashion Advice & Style Tips
SG50 Ferrari F12berlinetta : Prancing Horse for Lion City's 50th
- Messages forwarded by Outlook rule go nowhere
- Create and Deploy Windows 7 Image
- How do I check to see if my exchange 2003 is an open relay? (not using a open relay tester tool online, but on the console)
- Creating and using an unencrypted cookie in ASP.NET
- Directories
- Poor Performance on Sharepoint 2010 Server
- SBS 2008 ~ The e-mail alias already exists...
- Public to Private IP - DNS Changes
- Send Email from Winform application
- How to create a .mdb file from ms sql server database.......
programming4us programming4us
programming4us
 
 
programming4us