You are on page 1of 394

How to Bind a BindingNavigator with a DataGridView in Windows Forms

Introduction In this article, I am binding a BindingNavigator with a DataGridView control. The BindingNavigator control provides a UI for navigating records in a form. It has a series of buttons for move next, previous, first, last record as well as adding and deleting records. At first we should have some records. So we create a Database and insert some records into the database table. Create Database CREATE DATABASE EMP USE EMP CREATE TABLE EMP_DETAIL ( E_ID INT PRIMARY KEY, E_NAME VARCHAR(30), E_AGE INT, E_CITY VARCHAR(30), E_DEPARTMENT VARCHAR(20) ) INSERT INSERT INSERT INSERT INSERT INSERT INTO INTO INTO INTO INTO INTO EMP_DETAIL EMP_DETAIL EMP_DETAIL EMP_DETAIL EMP_DETAIL EMP_DETAIL VALUES(11,'ALOK KUMAR',24,'DELHI','IT') VALUES(12,'RAJESH TRIPATHI',22,'ALLAHABAD','SALES') VALUES(13,'SATISH KUMAR',23,'JHANSI','PRODUCT') VALUES(14,'MANOJ SINGH',22,'NOIDA','MARKETING') VALUES(15,'AMIT MAHESHWARI',25,'ALLIGARH','IT') VALUES(16,'DEEPAK DWIJ',24,'NOIDA','IT')

I am showing a screen shot of all records of an EMP_DETAIL table so that it can become easy to understand. SELECT * FROM EMP_DETAIL

Take a Windows Form Application and follow the given steps.

Step 1 : Go to Data Sources and click at "Add New Data Source".

Step 2 : A new window will be open.

Step 3 : Click the Next button.

Step 4 : Click the Next button.

Step 5 : Click the "New connection" button to make a new database connection.

Step 6 : Write the server name, user name, password and select your Database name. Click ok button.

Step 7 : Click ok button. You will be back to "Data Source Configuration Wizard". Check the radio button for "Yes, include sensitive data in the connection string " and click the next button.

Step 8 : A new window will open asking to save the connection string.

Step 9 : Click the Next button. In the new window click the Table node to explore all the tables of your database.

Step 10 : Click the table node to explore all columns. Then check the checkbox for
each column to select them. Look at the following figure.

Step 11 : Click the finish button. Step 12 : Go to the Data Source and drag "EMP_DETAIL" onto your form. The form will look like the following figure.

Run the application.

You can move to the first and last record, next and previous records as well as you can add, delete and update records using the BindingNavigator without writing code. Now we do same work without using the wizard. Take a BindingNavigator and DataGridView control at form. The form will look like the following figure.

Write the following code using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace databindingusingbindingnavigatorapps { public partial class Form2 : Form { public Form2() { InitializeComponent(); } SqlDataAdapter dadapter; DataSet dset; BindingSource bs; string connstring = "database=emp;server=.;user=sa;password=wintellect"; private void Form2_Load(object sender, EventArgs e) { dadapter = new SqlDataAdapter("select * from emp_detail", connstring); dset = new DataSet(); dadapter.Fill(dset); bs = new BindingSource(); bs.DataSource = dset.Tables[0].DefaultView; bindingNavigator1.BindingSource = bs; dataGridView1.DataSource = bs; } } } Run the application.

Output

Now you can perform same work as above.

Using the BindingSource Class in ADO.NET


Introduction The BindingSource class is used to simplify data binding as well as various operations on records. It has different methods like AddNew( ), MoveFirst( ), MovePrevious( ), MoveNext( ), etc which provide easier way for adding new row, moving to first record, moving to previous record, moving to next record and many other operations without writing code for them. In this article I will use it in a Windows Forms application. Here, the database name is "STUDENT" and the database table is "STUDENT_DETAIL" which has some records. At first, crete a Windows Forms Application. Now follow the given steps. Step 1 : Go to Toolbox and select bindingSource by double-clicking it or draging it.

Step 2 : It will be visible at the bottom of the form.

Step 3 : Go to the property window of the bindingSource control. Click at DataSource.

Step 4 : Click at Add Project DataSource. A new window will be open.

Step 5 : Select Database and click next button.

Step 6 : Select Dataset and click next button.

Step 7 : Click the "New Connection" button. A new window will be opened for adding connections to your database. Write the server name, user name, password and select your Database name.

Step 8 : Click the ok button. A new window will be open. It will ask to save the connection string.

Step 9 : Click the Next button. In hte new window click the Table node to explore all the tables of your database.

Step 10 : Click the table node to explore all columns. Then check the checkbox for each column to select them. Look at the following figure.

Step 11 : Click the finish button. Step 12 : Go to the property window of the bindingSource. Click at DataMember and select "STUDENT_DETAIL" ( Your database table name)

Now take four Labels and four TextBox controls. And arrange them like as in the

following figure.

Now bind the TextBoxes. Select the appropriate TextBox and go to the properties and set the text property. Like, I am binding the textbox to show roll_no from the database. So, I have changed the name to "txtrollno" of the TextBox and set the text under DataBinding property to "ROLL_NO". Look at the following figure.

Do the same for other TextBoxes. Then run the application. Output

You saw in the output window that it is showing records from the table "STUDENT_DETAIL". Now we will perform an operation using methods of the BindingSource class. Add some buttons and change the text.

Write the following code. using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms;

namespace bindingsourceapps { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'sTUDENTDataSet.STUDENT_DETAIL' table. You can move, or remove it, as needed. this.sTUDENT_DETAILTableAdapter.Fill(this.sTUDENTDataSet.STUDENT_DETAIL); } private void btnfirst_Click(object sender, EventArgs e) { bindingSource1.MoveFirst(); } private void btnnext_Click(object sender, EventArgs e) { bindingSource1.MoveNext(); } private void btnprevious_Click(object sender, EventArgs e) { bindingSource1.MovePrevious(); }

private void btnlast_Click(object sender, EventArgs e) { bindingSource1.MoveLast(); } private void btnsavechanges_Click(object sender, EventArgs e) { bindingSource1.EndEdit(); } private void btncancelchanges_Click(object sender, EventArgs e) { bindingSource1.CancelEdit(); } private void btnremove_Click(object sender, EventArgs e) { bindingSource1.RemoveCurrent(); } } } Run the application. Initially it will show the first record. Output

Click the "Next" button. It will show the next record.

In the sam manner, click "Previous" to go to the previous record, click "Next" to go to the next record, "First" button to the first record and "Last" button to go to the last record. You can save the changes to the current record as well as cancel the changes.

Save, Delete, Search And Update Records in ADO.NET


Introduction In this article I am performing simple operations like save, delete, update and search operations in a Windows Forms application. At first we should have a Database. So create a database. In this example my database name is "STUDENT" and database table is "student_detail" which has four columns as "roll_no", "s_name", "age" and "course". Create a Windows Forms Application. Take some UI controls.

Now we write code to perform the operations described in this article. Code for Saving Record

conn = new SqlConnection(connstring); conn.Open(); comm = new SqlCommand("insert into student_detail values(" + txtrn.Text + ",'" + txtname.Text + "'," + txtage.Text + ",'" + txtcourse.Text + "')", conn); try { comm.ExecuteNonQuery(); MessageBox.Show("Saved..."); } catch (Exception) { MessageBox.Show("Not Saved"); } finally { conn.Close(); } Look at the above code. In the first line of code, an instance of a SqlConnection is created. In the next, an instance of a SqlCommand class is created and a SQL statement for inserting values into the database table is specified. Then I am calling the ExecuteNonQuery() method in a try block. In the finally block I am closing the SqlConnection by the Close() method. The same as writing SQL Statements for performing various operations. Look at the following code for performing all the operations. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace savedeleteupdateapp { public partial class Form1 : Form { public Form1() { InitializeComponent(); } SqlConnection conn; SqlCommand comm; SqlDataReader dreader; string connstring = "server=localhost;database=student;user=sa;password=wintellect"; private void btnsave_Click(object sender, EventArgs e) {

conn = new SqlConnection(connstring); conn.Open(); comm = new SqlCommand("insert into student_detail values(" + txtrn.Text + ",'" + txtname.Text + "'," + txtage.Text + ",'" + txtcourse.Text + "')", conn); try { comm.ExecuteNonQuery(); MessageBox.Show("Saved..."); } catch (Exception) { MessageBox.Show("Not Saved"); } finally { conn.Close(); } } private void btnclear_Click(object sender, EventArgs e) { txtage.Clear(); txtcourse.Clear(); txtname.Clear(); txtrn.Clear(); txtrn.Focus(); } private void btndelete_Click(object sender, EventArgs e) { conn = new SqlConnection(connstring); conn.Open(); comm = new SqlCommand("delete from student_detail where roll_no = " + txtrn.Text + " ", conn); try { comm.ExecuteNonQuery(); MessageBox.Show("Deleted..."); txtage.Clear(); txtcourse.Clear(); txtname.Clear(); txtrn.Clear(); txtrn.Focus(); } catch (Exception x) { MessageBox.Show(" Not Deleted" + x.Message ); } finally {

conn.Close(); } } private void btnsearch_Click(object sender, EventArgs e) { conn = new SqlConnection(connstring); conn.Open(); comm = new SqlCommand("select * from student_detail where roll_no = " + txtrn.Text + " ", conn); try { dreader = comm.ExecuteReader(); if (dreader.Read()) { txtname.Text = dreader[1].ToString(); txtage.Text = dreader[2].ToString(); txtcourse.Text = dreader[3].ToString(); } else { MessageBox.Show(" No Record"); } dreader.Close(); } catch (Exception) { MessageBox.Show(" No Record"); } finally { conn.Close(); } } private void btnupdate_Click(object sender, EventArgs e) { conn = new SqlConnection(connstring); conn.Open(); comm = new SqlCommand("update student_detail set s_name= '"+txtname.Text+"', age= "+txtage.Text+" , course=' "+txtcourse.Text+"' where roll_no = "+txtrn.Text+" ", conn); try { comm.ExecuteNonQuery(); MessageBox.Show("Updated.."); } catch (Exception) { MessageBox.Show(" Not Updated");

} finally { conn.Close(); } } private void Form1_Load(object sender, EventArgs e) { txtrn.Focus(); } } } Now run the application. You can Save, Search, Delete and Update records.

Databinding with DataGridView in ADO.NET


DataGridView is very powerful and flexible control for displaying records in a tabular (row-column) form. Here I am describing a different way of databinding with a DataGridView control. Take a windows Form Application -> take a DataGridView control.

Follow the given steps. Step 1 : Select DataGridView control and click at smart property. Look at the following figure.

Step 2 : After clicking, a pop-up window will be open.

Step 3 : Click ComboBox.

Step 4 : Click at Add Project Data Source (Look at above figure). A new window will be opened to choose Data Source Type.

Step 5 : Choose Database (By default it is selected) and click the next button. A new window will be open to Database Model.

Step 6 : Select DataSet (By default it is selected) and click the next button. A new window will be open.

Step 7 : Click at New Connection button.

Step 8 : Write Server name, User name and Password of your SQL server and select Database name. Look at the following figure.

Step 9 : Click "ok" button. After clicking ok button, you will reach the Data Source Configuration Wizard.

Step 10 : Click the next button.

Step 12 : Click on Table to explore all tables of your Database.

Step 13 : Click on the selected Database table to explore all columns.

Step 14 : Check the CheckBox to select columns.

Step 15 : Click the Finish button. You will note that the DataGridView will show all columns of the table (Here, "Student_detail").

Run the application. Output

Now we bind the DataGridView with database by code. Take another DataGridView control and write the following code on the form load event. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace DatabindingWithdataGridView { public partial class Form1 : Form { public Form1() { InitializeComponent(); } SqlDataAdapter dadapter; DataSet dset; string connstring = "server=.;database=student;user=sa;password=wintellect"; private void Form1_Load(object sender, EventArgs e) { dadapter = new SqlDataAdapter("select * from student_detail", connstring); dset = new System.Data.DataSet(); dadapter.Fill(dset); dataGridView1.DataSource = dset.Tables[0].DefaultView; } } } Run the application. Output will be same as above.

Saving record using Stored Procedure in ADO.NET


Introduction Here I am saving a record into a database using a Stored Procedure. At first we will create a Stored Procedure and then we will save records using the Stored Procedure in Windows Forms Application. Create Database CREATEDATABASE STUDENT USE STUDENT CREATE TABLE STUDENT_DETAIL ( ROLL_NO INT PRIMARYKEY, S_NAME VARCHAR(30), AGE INT, CITY VARCHAR(30), COURSE VARCHAR(20), ) Create Stored Procedure Follow the given steps to create the stored procedure. Step 1 : Open Visual Studio 2010 and create a Windows Forms Application. Step 2 : Go to Server Explorer and click the arrow to explore your database. My database name is "student" to which I am using in this example. It will look like the following screenshot.

Step 3 : Right-click Stored Procedure.

Step 4 : Click "Add New Stored Procedure". A page will be opened with default SQL statements.

Step 5: Write your own Stored procedure. I am writing for inserting value into database table.

Step 6 : Save it. You will note that if your SQL statement for stored procedure is correct, then after saving it the word "create" will be changed to "Alter".

Now take some UI Controls and arrange them like given figure.

Write the following code. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace storedprocedureinadodotnet { public partialclass Form1 :Form { public Form1() { InitializeComponent(); } SqlConnection conn; SqlCommand comm; SqlParameter prn, pname, page, pcity, pcourse; // instance of sqlparameter string connstring ="database=student;server=.;user=sa;password=wintellect"; private void btnsave_Click(object sender,EventArgs e) { conn = newSqlConnection(connstring); conn.Open(); comm = newSqlCommand(); comm.Connection = conn; comm.CommandType = CommandType.StoredProcedure; comm.CommandText = "MYSTOREDPROCEDURE";

prn = newSqlParameter("@rn",SqlDbType.Int); pname = newSqlParameter("@NAME",SqlDbType.VarChar); page = newSqlParameter("@AGE",SqlDbType.Int); pcity = newSqlParameter("@CT",SqlDbType.VarChar); pcourse = newSqlParameter("@COURSE",SqlDbType.VarChar); comm.Parameters.Add(prn); comm.Parameters.Add(pname); comm.Parameters.Add(page); comm.Parameters.Add(pcity); comm.Parameters.Add(pcourse); prn.Value = Convert.ToInt32(txtrollno.Text ); pname.Value = txtname.Text ; page.Value = Convert.ToInt32(txtage.Text ); pcity.Value = txtcity.Text; pcourse.Value = txtcourse.Text; try { comm.ExecuteNonQuery(); MessageBox.Show("Saved"); } catch (Exception) { MessageBox.Show("Not Saved"); } } } } Run the application.

Fill in the form and click the "Save" button. It will show a message "Saved" or "Not Saved".

Searching Record in DataGridView in ADO.NET


Introduction In this article I am displaying a record from a database table in a DataGridView and searching the records in a DataGridView. At first we should have a database with some records. In this example my Database name is "student" and Database table name is "student_detail" which has some records. I will bind these records with DataGridView and perform a different operation. Take a Windows Forms Application. Take some UI controls and arrange them like in the following figure.

Write the following code: using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace searchingrecord { public partialclass Form1 : Form { public Form1() { InitializeComponent(); } SqlDataAdapter dadapter; DataSet dsset; CurrencyManager cmgr; DataRowView drv; string connatring ="server=.;database=student;user=sa;password=wintellect"; private void Form1_Load(object sender,EventArgs e) { dadapter = newSqlDataAdapter("select * from student_detail", connatring); dsset = newDataSet(); dadapter.Fill(dsset); dataGridView1.DataSource = dsset.Tables[0]; cmgr = (CurrencyManager)dataGridView1.BindingContext[dsset.Tables[0]];

} private void btnfirst_Click(object sender,EventArgs e) { cmgr.Position = 0; drv = (DataRowView)cmgr.Current; txtrollno.Text = drv.Row[0].ToString(); txtname.Text = drv.Row[1].ToString(); txtcity.Text = drv.Row[2].ToString(); } private void btnnext_Click(object sender,EventArgs e) { if (cmgr.Position != cmgr.Count) { cmgr.Position += 1; drv = (DataRowView)cmgr.Current; txtrollno.Text = drv.Row[0].ToString(); txtname.Text = drv.Row[1].ToString(); txtcity.Text = drv.Row[2].ToString(); } } private void btnprevious_Click(object sender,EventArgs e) { if (cmgr.Position != 0) { cmgr.Position -= 1; drv = (DataRowView)cmgr.Current; txtrollno.Text = drv.Row[0].ToString(); txtname.Text = drv.Row[1].ToString(); txtcity.Text = drv.Row[2].ToString(); } } private void btnlast_Click(object sender,EventArgs e) { cmgr.Position = cmgr.Count; drv = (DataRowView)cmgr.Current; txtrollno.Text = drv.Row[0].ToString(); txtname.Text = drv.Row[1].ToString(); txtcity.Text = drv.Row[2].ToString(); } private void btnsearch_Click(object sender,EventArgs e) { try { DataView dview =new DataView(dsset.Tables[0]); dview.Sort = "rollno"; int i = dview.Find(txtrollnosearch.Text); if (i < 0) { MessageBox.Show("No Recods Found"); } else { cmgr.Position = i; drv = (DataRowView)cmgr.Current; txtrollno.Text = drv.Row[0].ToString(); txtname.Text = drv.Row[1].ToString(); txtcity.Text = drv.Row[2].ToString();

} } catch (Exception) { MessageBox.Show("Incorrect Input.."); txtrollnosearch.Clear(); txtrollnosearch.Focus(); } } } } Run the application. Output

I am giving a short descriptive image of the output window below.

Click the ">" button. The selected row will be moved to the next row in the DataGridView as well as the record will be displayed in the TextBoxes.

Similarly, click other buttons (such as First, Last or Previous) to move to another record. You can search for a record on the basis of the roll number of the student. For example I found a record for the student whose "rollno" is 122.

Click the "Search" button. It will select the appropriate row in DataGridView as will as show record in TextBox.

Here are some related resources

Working With DataSet in ADO.NET


Introduction DataSet is tabular representation of data. Tabular representation means it represents data into row and column format. This class is counted in a disconnected architecture

in .NET Framework. Which means it is found in the "System.Data" namespace. The Dataset can hold records of more than one Database tables or DataTables. Now we try to use it into our application. Generally DataAdapter object is used with DataSet to fill DataSet with value. Let's look a simple example to using DataSet. In this example, I am using "student" Database ( Database name ) which has a table "student_detail". Take a Windows Form Application -> a DataGridView control and write the following code. using System.Windows.Forms; using System.Data.SqlClient; namespace workingwithdataset { public partialclass frmdataset : Form { public frmdataset() { InitializeComponent(); } private void frmdataset_Load(object sender,EventArgs e) { SqlDataAdapter dadapter =new SqlDataAdapter(" select * from student_detail ", " database=student;user=sa;password=wintellect "); DataSet dset =new DataSet();//Creating instance of DataSet dadapter.Fill(dset,"student_detail");// Filling the DataSet with the records returned by SQL statemetns written in sqldataadapter dataGridView1.DataSource = dset.Tables["student_detail"];// Binding the datagridview } } } Run the application. The code is in the load event of the form. So when you run the application, the output will look like the following figure. Output

Now we fill the dataset with a record from the DataTable. In the example shown above I have filled the dataset with records from the SqlDataAdapter. Write the following code

for the form load event. using System.Windows.Forms; using System.Data.SqlClient; namespace workingwithdataset { public partialclass frmdataset : Form { public frmdataset() { InitializeComponent(); } private void frmdataset_Load(object sender,EventArgs e) { DataTable table1 =new DataTable(); DataTable table2 =new DataTable(); DataColumn dc11 =new DataColumn("ID",typeof(Int32)); DataColumn dc12 =new DataColumn("Name",typeof(string)); DataColumn dc13 =new DataColumn("City",typeof(string)); table1.Columns.Add(dc11); table1.Columns.Add(dc12); table1.Columns.Add(dc13); table1.Rows.Add(111,"Amit Kumar","Jhansi"); table1.Rows.Add(222, "Rajesh Tripathi","Delhi"); table1.Rows.Add(333, "Vineet Saini","Patna"); table1.Rows.Add(444, "Deepak Dwij","Noida"); DataSet dset =new DataSet(); dset.Tables.Add(table1); dataGridView1.DataSource = dset.Tables[0]; } } } In the above example, I am creating a DataTable and filling the DataSet with the record of DataTable. Run the application. Output

DataSet can hold the record of more than one table. Now we fill the DataSet with more records from the DataTable. You have to add a DataGrid control. Take the DataGrid control and write the following code for the form load event. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace workingwithdataset { public partialclass frmdataset : Form { public frmdataset() { InitializeComponent(); } private void frmdataset_Load(object sender,EventArgs e) { // Craeting EMPLOYEE table DataTable EMPLOYEE =new DataTable(); DataColumn dc11 =new DataColumn("ID",typeof(Int32)); DataColumn dc12 =new DataColumn("Name",typeof(string)); DataColumn dc13 = new DataColumn("City",typeof(string)); EMPLOYEE.Columns.Add(dc11); EMPLOYEE.Columns.Add(dc12); EMPLOYEE.Columns.Add(dc13); EMPLOYEE.Rows.Add(111, "Amit Kumar","Jhansi"); EMPLOYEE.Rows.Add(222, "Rajesh Tripathi","Delhi"); DataColumn dc21 =new DataColumn("ID",typeof(Int32)); DataColumn dc22 =new DataColumn("Name",typeof(string)); DataColumn dc23 =new DataColumn("Subject",typeof(string)); // Craeting TEACHER table DataTable TEACHER =new DataTable(); TEACHER.Columns.Add(dc21); TEACHER.Columns.Add(dc22); TEACHER.Columns.Add(dc23); TEACHER.Rows.Add(123, "Anil Kumar","Java"); TEACHER.Rows.Add(234, "Amar Sharma","C++"); DataColumn dc31 =new DataColumn("ID",typeof(Int32)); DataColumn dc32 =new DataColumn("Name",typeof(string));

DataColumn dc33 =new DataColumn("Course",typeof(string)); DataColumn dc34 =new DataColumn("Year",typeof(Int32)); // Craeting STUDENT table DataTable STUDENT =new DataTable(); STUDENT.Columns.Add(dc31); STUDENT.Columns.Add(dc32); STUDENT.Columns.Add(dc33); STUDENT.Columns.Add(dc34); STUDENT.Rows.Add(1, "Manoj Singh","M.Tech", 2); STUDENT.Rows.Add(2, "Sanjay Kumar","MCA", 3); STUDENT.Rows.Add(5, "Pramod Sharma","MBA", 2); STUDENT.Rows.Add(18, "Satish jain","B.Tech", 4); DataSet dset =new DataSet(); dset.Tables.Add(EMPLOYEE); dset.Tables.Add(TEACHER); dset.Tables.Add(STUDENT); dataGrid1.DataSource = dset; } } } Run the application. Output

Click at plus (+) sign to explore all tables.

You can show records of Tables by clicking the Tables links. Like I am clicking at Table1.

Now we try to show records into TextBox from DataSet. As we know DataSet holds records in a row - column format. So its data can be retrieved by specifying rows and column index. Look at the following code where I am getting the Data of the first row in the TextBox. At first take one DatagridView, three Labels, three TextBox and one Button control. Arrange them into the following format.

Write the following code. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace workingwithdataset { public partialclass frmdataset : Form { public frmdataset() { InitializeComponent(); } DataTable EMPLOYEE; DataSet dset; private void frmdataset_Load(object sender,EventArgs e) { // Craeting EMPLOYEE table EMPLOYEE= newDataTable(); DataColumn dc11 =new DataColumn("ID",typeof(Int32)); DataColumn dc12 =new DataColumn("Name",typeof(string)); DataColumn dc13 =new DataColumn("City",typeof(string)); EMPLOYEE.Columns.Add(dc11); EMPLOYEE.Columns.Add(dc12); EMPLOYEE.Columns.Add(dc13);

EMPLOYEE.Rows.Add(111, "Amit Kumar","Jhansi"); EMPLOYEE.Rows.Add(222, "Rajesh Tripathi","Delhi"); dset = newDataSet(); dset.Tables.Add(EMPLOYEE); dataGridView1.DataSource = dset.Tables[0]; } private void btnshow_Click(object sender,EventArgs e) { txtid.Text = dset.Tables[0].Rows[0][0].ToString(); txtname.Text = dset.Tables[0].Rows[0][1].ToString(); txtcity.Text = dset.Tables[0].Rows[0][2].ToString(); } } } Run the application. Output

Click at "show" button to show record into Textbox.

Here are some related resources

Databinding With ComboBox in ADO.NET


Introduction In this article I am describing various techniques of databinding with a ComboBox control. A ComboBox control shows data in a dropdown list. Before starting the databinding with ComboBox, let's know its two important properties - DisplayMember and ValueMember. DisplayMember : This property is used to specify the name of a column ( Database Table's Column ) to be displayed in the ComboBox. ValueMember : This property is used to specify the name of a column ( Database Table's Column ) to be stored as values of selected item in ComboBox. I am using a "student" database which has a table "student_detail" with some records. Now take a Windows Forms application -> Take a label and ComboBox controls as in the following figure.

Go to smart property of ComboBox control.

Follow the given steps. Step 1 : Check the CheckBox of Use Data Bound Items.

Step 2: Click on the down arrow of the Data Source.

Step 3: Click at Add Project Data Source link. A new window will open.

Step 4: Select "Database" as Data Source ( By default Database is selected ). Click the next button. A new window will open.

Step 5: Select "Dataset" as Database model ( By default Dataset is selected ). Click the next button. A new window will open.

Step 6: Click the "New Connection" button. A new window will open. In the new window enter the Server name (I have used dot), write user name and password of your SQL Server and select database ( I have selected "student" ). Look at the following figure.

Step 7: Click the "ok" button. Now a connection has been made to the student database. You will look at the "Data Source Configuration Wizard" window.

Step 8: Click the next button.

Step 9: Click the plus ( + ) sign to explore all tables of the student Database.

Step 10: Again click the plus sign for "student_detail" to show all columns of the Database table. Check the all CheckBox.

Step 11: Click the Finish button. Now set the DisplayMember and ValueMember property of ComboBox. Click at down arrow of Display Member and select "rollno". Same as set "name" as Value Member property.

Run the application. Output

It will show all values from the "RollNo" column because we have set RollNo to the DisplayMember property of combobox. Now stop the running program -> go to design window of your application and write the following code on SelectedIndexChanged event of ComboBox. private void comboBox1_SelectedIndexChanged(object sender, EventArgs e) { label1.Text = comboBox1.SelectedValue.ToString(); } Run the application. Select a different value in ComboBox. It will show the student name in Label regarding to selected Roll Number.

Now we bind the ComboBox with data by code. Take another ComboBox ( Say CombBox2) and a Label and write the following code. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace DataBindingWIthComBox {

public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { SqlDataAdapter dadpter=new SqlDataAdapter("select * from student_detail","server=.;database=student;user=sa;password=wintellect"); DataSet dset = new DataSet(); dadpter.Fill(dset); comboBox2.DataSource = dset.Tables[0]; comboBox2.DisplayMember = "rollno"; // to display roll no. in combobox comboBox2.ValueMember = "name"; // to store name as value of combobox for selected roll no. } private void comboBox2_SelectedIndexChanged(object sender, EventArgs e) { label2.Text = comboBox2.SelectedValue.ToString(); } } } Run the application. It will do same work as before.

Working With the SqlParameter Class in ADO.NET


Introduction The SqlParameter class is found in the "System.Data.SqlClient" namespace. It is a class of a connected architecture of .NET framework. It represents parameters. To work with the SqlParameter class we should have a database. In this example I am using a Database "student" which has a "student_detail" table. "RollNo", "Name" and "City" are column names. I will save and retrieve records using SqlParameter class. Here is a list of important properties of the SqlParameter class which will be used in this example. SqlDbType :It is used to set the Sql Server Data types for a given parameter. ParameterName :It is used to specify a parameter name. Direction : It is used for setting the direction of a SqlParameter. It is Input or Output or both (InputOutput). Size : It is used to set maximum size of value of parameter. Value : It is used for assigning or getting value of the parameter. Now, take a Windows Forms application in Visual Studio 2010. Take some UI Controls and arrange them as shown in the figure below.

Write the following code for saving a record into the database. using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; namespace WorkWithSqlParameterClass { public partialclass Form1 :Form { public Form1() { InitializeComponent(); } SqlConnection conn; SqlCommand comm; string connstring ="database=student;server=.;user=sa;password=wintellect"; private void btnsave_Click(object sender,EventArgs e) { conn = newSqlConnection(connstring); conn.Open(); comm = newSqlCommand(); comm.Connection = conn; //Creating instance of SqlParameter SqlParameter PmtrRollNo =new SqlParameter(); PmtrRollNo.ParameterName = "@rn";// Defining Name PmtrRollNo.SqlDbType = SqlDbType.Int;// Defining DataType PmtrRollNo.Direction = ParameterDirection.Input; // Setting the direction

//Creating instance of SqlParameter SqlParameter PmtrName =new SqlParameter(); PmtrName.ParameterName = "@nm";// Defining Name PmtrName.SqlDbType = SqlDbType.VarChar;// Defining DataType PmtrName.Direction = ParameterDirection.Input;// Setting the direction //Creating instance of SqlParameter SqlParameter PmtrCity =new SqlParameter(); PmtrCity.ParameterName = "@ct";// Defining Name PmtrCity.SqlDbType = SqlDbType.VarChar;// Defining DataType PmtrCity.Direction = ParameterDirection.Input;// Setting the direction // Adding Parameter instances to sqlcommand comm.Parameters.Add(PmtrRollNo); comm.Parameters.Add(PmtrName); comm.Parameters.Add(PmtrCity); // Setting values of Parameter PmtrRollNo.Value = Convert.ToInt32(txtrollno.Text); PmtrName.Value = txtname.Text; PmtrCity.Value = txtcity.Text; comm.CommandText = "insert into student_detail values(@rn,@nm,@ct)"; try { comm.ExecuteNonQuery(); MessageBox.Show("Saved"); } catch (Exception) { MessageBox.Show("Not Saved"); } finally { conn.Close(); } } } } Run the application. Output

Fill in the form and click the "Save" button. The record will be saved to the Database and a message box will be displayed with a confirmation message.

Now we retrieve records from the database. Take another button and set its text property as "Show". Add the following code for the "Show" button. privatevoid btnshow_Click(object sender, EventArgs e) { conn = newSqlConnection(connstring); conn.Open(); comm = newSqlCommand(); comm.Connection = conn; //Creating instance of SqlParameter SqlParameter PmtrRollNo =new SqlParameter(); PmtrRollNo.ParameterName = "@rn";// Defining Name PmtrRollNo.SqlDbType = SqlDbType.Int;// Defining DataType PmtrRollNo.Direction = ParameterDirection.Input; // Setting the direction

//Creating instance of SqlParameter SqlParameter PmtrName =new SqlParameter(); PmtrName.ParameterName = "@nm";// Defining Name PmtrName.SqlDbType = SqlDbType.VarChar;// Defining DataType PmtrName.Size = 30; PmtrName.Direction = ParameterDirection.Output;// Setting the direction //Creating instance of SqlParameter SqlParameter PmtrCity =new SqlParameter("@ct",SqlDbType.VarChar, 20); PmtrCity.Direction = ParameterDirection.Output;// Setting the direction // Adding Parameter instances to sqlcommand comm.Parameters.Add(PmtrRollNo); comm.Parameters.Add(PmtrName); comm.Parameters.Add(PmtrCity); // Setting values of Parameter PmtrRollNo.Value = Convert.ToInt32(txtrollno.Text); PmtrName.Value = txtname.Text; PmtrCity.Value = txtcity.Text; comm.CommandText = "select @nm=name,@ct=city from student_detail where rollno=@rn"; try { comm.ExecuteNonQuery(); txtname.Text = PmtrName.Value.ToString(); txtcity.Text = PmtrCity.Value.ToString(); } catch (Exception) { MessageBox.Show("Not Found"); } finally { conn.Close(); } } } Run the application. Output

Enter a roll number and click the "Show" button. It will show all the related information of the student having the given roll number.

Here are some related resources.

Searching Records in ADO.NET


Introduction In this article, I am describing searching in the manner of the Google Search style. I am searching student records by matching character of student name. I am performing this operation in a Window Forms Application. At first we should have a database with some records to be searched. I have database tables "student" and "student_detail". I am showing the records of database table so that it become easy to understand.

Create a Windows Forms Application. Take some UI controls and arrange them as in the following figure.

Write the following code using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace SearchingInAdoDotNet { public partialclass Form1 : Form {

public Form1() { InitializeComponent(); } private void Form1_Load(object sender,EventArgs e) { txtsearch.Focus(); lblrollno.Visible = false; dgvshow.Visible = false; dadapter = newSqlDataAdapter(sqlstate, connstring); dset = newDataSet(); dadapter.Fill(dset); } SqlDataAdapter dadapter; DataSet dset; DataView dview; string connstring ="database=student;server=.;user=sa;password=wintellect"; string sqlstate ="select name,rollno from student_detail"; private void txtsearch_KeyUp(object sender,KeyEventArgs e) { if (e.KeyCode !=Keys.Enter) { dview = newDataView(dset.Tables[0]); dview.RowFilter = "name like '" + txtsearch.Text + "%' "; if (dview.Table.Rows.Count > 0) { dgvshow.Visible = true; } dgvshow.DataSource = dview; dgvshow.Columns["rollno"].Visible = false; if (e.KeyCode ==Keys.Down) { dgvshow.Focus(); } } } private void dgvshow_KeyPress(object sender,KeyPressEventArgs e) { } private void dgvshow_KeyUp(object sender,KeyEventArgs e) { txtsearch.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex ].Value.ToString(); lblrollno.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex + 1].Value.ToString(); } private void dgvshow_KeyDown(object sender,KeyEventArgs e) { if (e.KeyCode ==Keys.Enter) {

e.SuppressKeyPress = true; txtsearch.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex ].Value.ToString(); lblrollno.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex + 1].Value.ToString(); showdetail(); } } private void bntgo_Click(object sender,EventArgs e) { showdetail(); } void showdetail() { dadapter = newSqlDataAdapter("select * from student_detail where rollno=" + lblrollno.Text +"", connstring); dset = newDataSet(); dadapter.Fill(dset); if (dset.Tables[0].Rows.Count > 0) { txtrollno.Text = dset.Tables[0].Rows[0][0].ToString(); txtname.Text = dset.Tables[0].Rows[0][1].ToString(); txtcourse.Text = dset.Tables[0].Rows[0][2].ToString(); txtcity.Text = dset.Tables[0].Rows[0][3].ToString(); } else { MessageBox.Show("Nothing to Show....."); } } private void dgvshow_CellContentClick(object sender,DataGridViewCellEventArgs e) { txtsearch.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex ].Value.ToString(); lblrollno.Text = dgvshow.Rows[dgvshow.CurrentCell.RowIndex].Cells[dgvshow.CurrentCell.ColumnIndex + 1].Value.ToString(); } } } Run the application

Enter a name in textbox. You will note that it will show all matching names depending on the given input.

You can press the down arrow key to select a different name to search or can select by mouse.

Click the "Go" button. It will show the full record of that student.

Using The SQLCommand And SQLDataReader


1. Introduction Almost every business web application makes use of databases to store and retrieve data. ADO.NET is the next generation to the ADO (Activex data Objects). In this article we will retrieve some column data from the employee table of the NorthWnd database. Look at the following illustration of how we are going to take data from the database.

2. About the Sample Look at the screenshot of the sample below:

Our sample in the explorer looks like the one above. When the sample loads the page, it contacts the SQL Server NorthWind database and retrieves the data to display the label shown in yellow color. There is nothing more to specify here. Let us move to the next section. 3. Connection String in Web Configuration We know that the web page is going to connect to a database and pull data from the employee table. The first thing every database programmer

should do is to specify a way to connect to the database. In our sample we are going to connect to the SQLServer database NorthWnd to pull some information from the employee table. The Connection object tells the application how to connect to the database. Using the methods or constructor of the Connection object one can specify the information required to connect the database with your application. Here, we are going to use the connection stringand we will place that constant string as part of the web configuration file. Once you start a new web site you can see the web configuration file in the Solution Explorer. This is marked in the following picture.

A web configuration file is the one in which you specify all the web application related settings. Doing so will avoid the further builds to your application. Say for example you have the connection string to connect to the Database db1 at server Srv1. When you want to connect to a different database db2 on a different machine Srv2, all you need to do is change that information in the configuration file and your web site keep working without any code change. The changed portion of the web configuration file is shown below:

The box shows that we added a connectionstrings section that spawns the information between the tags open <> and end </>. Note that we are using the System.Data.SQLClient provider. A provider is a bridge between your application and the database and they are the communication channel acting as translator. In the above connection string I specified the Server Name as System (My Local machine name). If your database is not in the local machine you should specify the name of the computer in the network or IP address of the machine name. NorthWnd is the database I am going to connect on my local machine for this example to access the employees table. And finally the connection string contains the qualified (of course it is. As sa is admin user) user id sa and password rohith. Now the connection string informs that you are

going to connect to Northwnd database in the Local machine System using the database credential sa&rohith. To know your system name or name of the system in the network in which the database in running, right click on the MyComputer icon and select properties. From the displayed dialog's second tab pick the Full Computer name. This is shown below:

4. Page Design
Once the connection string is specified in the web configuration file, the default aspx file name is changed to datareader.aspx. Then in the design view of the page three labels are added as shown below:

To change the label name go to the source (Highlighted in red) and change the ID for the control. Sometimes changing the ID in the property window of the control will not reflect back and hence it is good to make the change in the html source of the page. This is shown in the following video. Video :Link OK. Now let us move to the Source code of the form. Note when the page load we are going to connect to the SQL Server database and will retrieve some data from the employees table of the NorthWnd database.

5. Source: Config File


We have already looked at the configuration file. In this file we specified our connection string to the database which is shown below:

<!-- DRead 001: Open the connectiontring section--> <connectionStrings> <addname="SQLServerDatabase"providerName="System.Data.SqlClient" connectionString= "Server=SYSTEM; Database=NorthWnd; User ID=sa; Password=rohith; Trusted_Connection=False;"/>
</connectionStrings>

6. Source: Reading the configuration


First the form load event handler is handled and in the form load event handler we need to connect to the database. To connect to the database we need the connection string. And, we already specified our connection string in the Web Config file. So this situation now leads us to the task of reading the information from the web configuration file. By default the namespace System.Configuration is included in your source file. If not include it using the statement as shown below:

using System.Configuration; Then have a look at the following code:

//DRead 003: Get the connection string from the configuration file ConnectionStringSettings appsettings = ConfigurationManager.ConnectionStrings["SQLServerDatabase"]; string ConnString = null; if (appsettings != null)
ConnString = appsettings.ConnectionString;

In the above code snippet, we are reading our connection string from ConfigurationManager using the Name SQLServerDatabasefrom the collection ConnectionStrings, which is the collection of objects of type ConnectionStringSettings. This value is stored in the appsettings. Note that in the webconfig file we used only one connection string. But you can have multiple connection strings between the tags<connectionStrings> < /connectionStrings>
Finally the string format of connection string is stored in the ConnString. Now we know the connection information to the database in the form of a string.

7. Source: Connection Object

The connection object knows where your database and how to access it. So the connection object can be created easily by supplying the connectionstring as it has all the information a connection object needs. The following is the piece of code that creates the connection object in our example:

//DRead 004: Create the Connection to SQL Server 8. Source: Command Object

SqlConnection Connection_toSQL = newSqlConnection(ConnString); The command object will say what you want to do with the database. It usually contains SQL Statement that needs to be executed in the database and well as connection information to know where it should be executed. In the following piece of code a table select query is stored in the string. Then supplying the query string and connection object creates a command object. Now command object is capable enough to retrieve some fields from the employee table of the Northwnd database in SQL Server.

//DRead 005: Form the command object string Query = "Select FirstName, TitleOfCourtesy, Title from employees";
SqlCommand command = newSqlCommand(Query, Connection_toSQL);

9. Source: DataReader and Iterating through it OK. The command is capable of executing the SQL statements. When the SQL statement is Select statement, then the database will give back one more rows of information. Where to we store that information? In our sample (There are other ways too. We will see that in some other article) we are making use the DataReader object to collect that table of information. The datareader is forwardonly and that means you can read the information only once and move forward. This tells you that once you read something store it in your local variable, as you cannot read it again. The following is the piece of code, which first executes the command object, gets the resultant record collection in the reader of type SqlDataReaderand then it iterates through reader to get the column name queried. //DRead 006: Open the connection and get result in DataReader Connection_toSQL.Open(); SqlDataReader reader = command.ExecuteReader();

//DRead 007: Iterate through the reader while (reader.Read()) { string line = ""; line = string.Format("{0} {1} is Working as {2} </br>", reader["TitleOfCourtesy"], reader["FirstName"], reader["Title"]); lblResult.Text = lblResult.Text + line; } The resultant string is the combination of some constant with the data retrieved from the database. And the string assigned to the label with the </br> tag to insert a new line after reading one complete record. Also note that the column Read method of the X will return column of columns that forms a complete a row of what is queried. To refer a particular column, you can use the column name or the index. The reader["FirstName"]states that we want to get the value for the columnFirstName.

Database Updates From DatagridView


Introduction A DataGridView control can be used to display data from a database. A table can be displayed from a database in a DataGridView, using the DataAdapter class and data logic. You can easily update a database from a DataGridView.

Step 1 Create a Windows Forms Application Project, and place a DataGridView on the form. Step 2 Click on the pin button on right-up side of DataGridView and click add project DataSource. And follow these simple steps. Choose DataSourceType Database New Connection, Make Connection Select Table and Column names

Finish

Step 3 Your DataSet now has been created. You can see it from the Solution Explorer.

Step 4 See the properties of the Adapter on DataSet, whether it has a query for updating or not. If not then add an update query.

Step 5 A line is auto generated, when you bind the DataGridView to the dataset. As: privatevoid testGrid_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'gridTestDataSet.Emp' table. You can move, or remove it, as needed. this.empTableAdapter.Fill(this.gridTestDataSet.Emp);

} On Click Event of Update button privatevoid button3_Click(object sender, EventArgs e) { //Update button update dataset after insertion,upadtion or deletion DialogResult dr = MessageBox.Show("Are you sure to save Changes", "Message", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Information); if (dr == DialogResult.Yes) { this.empTableAdapter.Update(gridTestDataSet.Emp); dataGridView1.Refresh(); MessageBox.Show("Record Updated"); } } Points of Interest You can insert a row and click the update button; a row in the database will be inserted. If you update any cell and click the update button, then the database will be updated. To delete, select the rows and then press the Delete key and click the update button; the rows will be deleted. All your insertions, updates, and deletions will be effected by the single button.

Working With AutoIncrement Property of DataColumn Class in ADO.NET


Introduction The column's value of a new row can be incremented by the AutoIncrement property of the DataColumn class. At first, set the AutoIncrement property to true. The two other properties used with the AutoIncrement property are AutoIncrementSeed and AutoIncrementStep. AutoIncrementSeed : It is used to set initial value for increment. AutoIncrementStep : It is used to set value to be increment.

Now we use these properties in our application. I am creating a simple application in which I am sending the value from textbox to DataTable's row and showing the value of DataTable into DataDridView. Open Visual Studio 2010 and take a Window Form Application. Write the following code. using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq;

using System.Text; using System.Windows.Forms; namespace parameterclass { public partialclassForm1 : Form { public Form1() { InitializeComponent(); } private void btnok_Click(object sender,EventArgs e) { // Creating new row and assigning value to column DataRow dr = dtable.NewRow(); dr[1]=textBox1.Text; dr[2] = int.Parse(textBox2.Text); dr[3] = textBox3.Text; // Adding DataRow to DataTable dtable.Rows.Add(dr); // Binding DataGridView to DataTable dataGridView1.DataSource = dtable; } DataTable dtable; private void Form1_Load(object sender,EventArgs e) { // Creating Intance of DataTable dtable = new System.Data.DataTable(); // Creating Instance to DataColumns DataColumn dcid =new System.Data.DataColumn("ID",typeof(int)); DataColumn dcname =new System.Data.DataColumn("NAME",typeof(string)); DataColumn dcage =new System.Data.DataColumn("AGE",typeof(int)); DataColumn dccity =new System.Data.DataColumn("CITY"); // Adding Columns to DataTable dtable.Columns.Add(dcid); dtable.Columns.Add(dcname); dtable.Columns.Add(dcage); dtable.Columns.Add(dccity); // Set AutoIncrement property to true dcid.AutoIncrement =true; // Set starting value for increment dcid.AutoIncrementSeed = 11; // Set increment value dcid.AutoIncrementStep = 2; // Binding DataGridView to DataTable dataGridView1.DataSource = dtable; } } } Run the application. Output

Fill the textboxes

Click the "ok" button. You will note that you are not assigning any value for "ID". But when you click the button, It shows 11 as "ID" DataGridView. Because the AutoIncrementSeedproperty is set to 11. Look at the following figure.

Again fill the textboxes with a value.

Click the button. You will note that "ID" will be incremented by 2. Because the AutoIncrementStep property is set to 2. Which means it is incremented by 2. Look at the following figure.

Here are some related resources. Get a database table properties Data Column in ADO.NET Working with the SqlTransaction Class in ADO.NET Working with DataTable and its Methods in ADO.NET Data Binding in DataGrid Control - Part 1

Working with the SqlConnection and SqlCommand Classes in ADO.NET


Introduction SqlConnection and SqlCommand are classes of a connected architecture and found in the System.Data.SqlClient namespace. The SqlConnection class makes the connection with the database. Further this connection (database connection) is used by the SqlCommand to work with that database. The SqlCommand class is used to execute the SQL statements. Let's work with the SqlConnection and SqlCommand classes with simple examples. SqlConnection Class Here, we will use two important methods of SqlConnection. Open() : The open() method is used to open the Database connection. Close() : The close() method is used to close the Database connection. Look at the following code: using System; using System.Data; using System.Data.SqlClient;

namespace sqlconnectionANDsqlcommand { public partialclass Form1 :Form { public Form1() { InitializeComponent(); } private void btnclick_Click(object sender,EventArgs e) { SqlConnection conn =new SqlConnection("Database=student;Server=.;user=sa;password=aaaaaaa"); conn.Open(); // Open the connection // body // body conn.Close(); // Close the connection } } } In the preceding code, I have added the namespace "System.Data.SqlClient". On the button click event, I have created an instance as "conn" of SqlConnection and passing a connection string (database) as parameter. Then, I have opened the connection by the open() method and closed to it by the close() method. We can also check whether the connection is open or closed by it's state property. Add the following code to the application. privatevoid btnclick_Click(object sender, EventArgs e) { // connection is opened. so if you click button then messagebox will be shown with the message "Open" SqlConnection conn =new SqlConnection("Database=student;Server=.;user=sa;password=aaaaaaa"); conn.Open(); MessageBox.Show(conn.State.ToString()); conn.Close(); } private void btnok_Click(object sender,EventArgs e) { // connection is not opened. so if you click button then messagebox will be shown with the message "Closed" SqlConnection conn =new SqlConnection("Database=student;Server=.;user=sa;password=aaaaaaa"); MessageBox.Show(conn.State.ToString()); } SqlCommand Class The main role of SqlCommand is to execute SQL statements. Properties CommandText: The commandText property is used to set the SQL statement. Connection: This property is used to get connection to the database source which is specified in SqlConnection.

Method ExecuteNonQuery() : TheExecuteNonQuery() method does not return any record. Which means we use ExecuteNonQuery() in all operations with databases except retrieving records from a database. It only returns the number of affected rows. Now we use this method in our application. There is a database "student" and a database "student_detail" which has no record. I am giving a simple example to insert a record into database. Take 3 labels, 3 textboxes and 1 button and arrange them as in the following figure.

Write the following code using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace sqlconnectionANDsqlcommand { public partialclass Form1 :Form { public Form1() { InitializeComponent(); } private void Form1_Load(object sender,EventArgs e) { }

private void btnclick_Click(object sender,EventArgs e) { // Creating instance of SqlConnection SqlConnection conn =new SqlConnection("Database=student;Server=.;user=sa;password=aaaaaaa"); conn.Open();// open the database connection SqlCommand cmd =new SqlCommand();// Creating instance of SqlCommand cmd.Connection = conn; // set the connection to instance of SqlCommand cmd.CommandText = "insert into student_detail values (" + txtrollno.Text + ",'" + txtname.Text + "','" + txtcourse.Text + "')"; // set //the sql command ( Statement ) cmd.ExecuteNonQuery(); MessageBox.Show("Record Saved"); // showing messagebox for confirmation message for user conn.Close();// Close the connection } } } Output Enter the RollNo., Name and Course and click the "save" button. It will save the record into database. ExecuteScalar() : The ExecuteScalar() returns a single value from the database. Generally it is used with an aggregate function (a function which returns a single value). Suppose there is a need to check how many records are in the database table. Then we use this function. Add another button to your application and set its text property to "Count" and write the following code on button click. privatevoid btncount_Click(object sender, EventArgs e) { SqlConnection conn =new SqlConnection("Database=student;Server=.;user=sa;password=aaaaaaa"); conn.Open();// open the database connection SqlCommand cmd =new SqlCommand();// Creating instance of SqlCommand cmd.Connection = conn; // set the connection to instance of SqlCommand cmd.CommandText = "select count (*) from student_detail" ; // set the sql command ( Statement ) string record= cmd.ExecuteScalar().ToString(); MessageBox.Show("Total records : "+ record ); conn.Close();// Close the connection } Output When you click the "count" button, a MessageBox will be displayed to show the total number of records in the database table. ExecuteReader() : The ExecuteReader() method can return a set of records from a database. I will explain more about the ExecuteReader() method in my next article.... Here are some related resources.

How to: Easily Query a Database Creating Sql and ODBC Command Objects in ADO.NET SQLCommand Class Constructor Working with the SqlTransaction Class in ADO.NET Working with DataTable and its Methods in ADO.NET

DataRelation class in ADO.NET


Introduction The DataRelation is a class of disconnected architecture in the .NET framework. It is found in the System.Data namespace. It represents a relationship between database tables. It correlates tables on the basis of matching column. Now we create an application using DataRelation. At first, create a database and table. I have created a database as STUDENT and two tables as AllStudent and StudentRecords. Insert some records into database. Create Database And Table createdatabase STUDENT use student createtable AllStudent ( RollNo int constraint pk primary key, F_Name varchar(30), L_Name varchar(30), City varchar(20) ) createtable StudentRecords ( RollNumber int constraint fk foreignkey references AllStudent(RollNo), Course varchar(20), Duration int ) Now insert records into table. I have inserted some records. I am giving screen - shot of records for better understanding of working of DataRelation.

Now create a windows form application. Add a DataGrid control into Toolbox. Follow the given steps. Go to Toolbox Right click

Click at Choose items Check the CheckBox of DataGrid and Click ok button

Now DataGrid control has added in the Toolbox. Create 2 dataGridViews, 1 DataGrid and 3 button controls. Arrange these into the given order.

Write the following code using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; namespace datarelation

{ public partialclass Form1 :Form { public Form1() { InitializeComponent(); } SqlDataAdapter dad1, dad2; DataSet ds; DataRelation drel; string connstr ="Data Source=.;Initial Catalog=STUDENT;User ID=aa;password=aaaaaaa"; private void btnRecodFromAllStudent_Click(object sender,EventArgs e) { dad1 = newSqlDataAdapter("select * from AllStudent", connstr); ds = new DataSet(); dad1.Fill(ds); dataGridView1.DataSource = ds.Tables[0]; } private void btnstudentrecord_Click(object sender,EventArgs e) { dad2 = newSqlDataAdapter("select * from StudentRecords", connstr); ds = new DataSet(); dad2.Fill(ds); dataGridView2.DataSource = ds.Tables[0]; } private void btngettingrecordbydatarelation_Click(object sender, EventArgs e) { dad1 = newSqlDataAdapter("select * from AllStudent", connstr); ds = new DataSet(); dad1.Fill(ds, "AllStudent"); dad1.SelectCommand.CommandText ="select * from StudentRecords"; dad1.Fill(ds, "StudentRecords"); drel = newDataRelation("All", ds.Tables[0].Columns[0], ds.Tables[1].Columns[0]); ds.Relations.Add(drel); dataGrid1.DataSource = ds; } private void Form1_Load(object sender,EventArgs e) { } } } Run the application Output

Click at all Buttons. Output

Look at DataGrid records (At last). Now, click at + sign.

Click at both links to show records. Records of StudentRecods table

Records of AllStudent table

Now click At + sign of first row.

Click at All ( As looking in above figure). It will show records from both table. Note here, RollNo is primary key of "AllStudent" table also foreign key of "StudentRecords" table. So it shows all records from both table.

If you want to show record of a student whose RollNo is not in "StudentRecords", then it will show it as the below.

Working with DataTable and its Methods in ADO.NET


Introduction A DataTable is a class of Disconnected architecture in the .NET Framework. It is found in the System.Data namespace and represents a single table. We can create a table and can add columns and rows of that table. Now, we will create an window application and use the DataTable class. Create a windows application > create a dataGridView control and write the following code on the form load event. using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms;

namespace datatable {

public partialclass Form1 :Form { public Form1() { InitializeComponent(); } DataTable dt; private void Form1_Load(object sender,EventArgs e) { //Adding Columns dt = newDataTable(); dt.Columns.Add("ID",typeof(int)); dt.Columns.Add("Name",typeof(string)); dt.Columns.Add("Department",System.Type.GetType("System.String")); dt.Columns.Add("City",typeof(string)); //Adding Rows dt.Rows.Add(111, "Alok","IT", "Delhi"); dt.Rows.Add(222, "Satish","IT", "Jhansi"); dt.Rows.Add(333, "Amitabh","Management", "Noida"); } } } Run the application. Output

It is a simple example for creating a datatable and adding column and value to its row. Now we work with its different method. Working with it's methods AcceptChanges() This method saves changes which made with records in a Datatable. Take another dataGridView control and a Button. Add below code. privatevoid btnacceptchanges_Click(object sender, EventArgs e) { dt.AcceptChanges(); dataGridView2.DataSource = dt; }

Run the application. Make some changes in rows value. I have changed department name as "cs" for first row and added a new row at last. Output

Click the "AcceptChanges" button. Second dataGridView will show updated record.

Clear() This method clears (removes) all data from datatable. Take a button and write the following code on click event.

privatevoid btnclear_Click(object sender, EventArgs e) { dt.Clear(); } Output

Click the "Clear" button. It will clear all the data. Output

Clone() The clone method copy the structure of Datatable. Means it copy only schema not full records of Datatable. Take another dataGridView control and a Button. Add below code. privatevoid btnclone_Click(object sender, EventArgs e) { DataTable dt1 = dt.Clone(); dataGridView2.DataSource = dt1;

} Output

Click the "Clone" button. Output

Copy() The copy method copy the whole records with structure of Datatable. Take another dataGridView control and a Button. Write the following code on button click. privatevoid btncopy_Click(object sender, EventArgs e) { DataTable dt1 = dt.Copy(); dataGridView2.DataSource = dt1; } Output

Click the "copy" button. It will copy all the data with structure of datatable into another datatable and show records in dataGridView. Output

GetChanges() This method does copy of all records of datatable with changes made with record. Add a button and dataGridView and write the following code on button click. privatevoid btnGetChanges_Click(object sender, EventArgs e) { dt.GetChanges(); dataGridView2.DataSource = dt; } Output I have changed some column value like department as "CS" of first row and city as "Varanasi" for last row.

Click the "GetChanges" button. It will show all record. Output

NewRow() The NewRow method creates a new row with same schema of datatable. Take a button > Set it's Text property to "NewRow" and write the following code. private void btnnewrow_Click(object sender,EventArgs e) { DataRow dr = dt.NewRow(); dr["ID"] = 444; dr["Name"] ="Pramod"; dr["Department"]="CS"; dr["City"] ="Allahabad"; //Add the row to datatable dt.Rows.Add(dr); } Run the application. Output

Click the "NewRow" button. It will add new row to datatable. Output

Working with the SqlTransaction Class in ADO.NET


Introduction: The SqlTransaction class is very important class of .NET Framework. The SqlTransaction class is used for satisfying the ACID property of DBMS (I am not describing ACID property here.). It ensure that a body of code will affect a Database or keep the same as previous (Rollback). In this article, I am giving an example of using the SqlTransaction

class in .NET using C#. At first we should know about it's two most important method which will be used here. They are given below. Commit(): It commits the transaction. It save changes made in Database during transaction. In simple term we can say also that it shows the end of transaction at that time. Rollback(): It is used to rollback the transaction. It set the Database in previous stage which was, before the begin of transaction.

Now we write a simple program to understand how it works. At first we create a Database. We are writing a program for transaction, so we create two tables. I am creating two tables as userdet and moneytrans insert some records in userdet table. Below, I am giving a screen shot of the output of a select command for showing the records of the tables. select* from userdet select* from moneytrans

Writing Program: Create a windows application and arrange U.I. controls.( I have arranged it as below)

using using using using using using using using using

System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms; System.Data.SqlClient;

namespace SqlTransactionClassinAdodotNet { public partialclass Form1 :Form { public Form1() { InitializeComponent(); } SqlConnection conn; SqlCommand comm1, comm2, comm3; SqlTransaction trans; SqlDataAdapter adapter1, adapter2; DataSet ds1, ds2; string constring =@"Data Source=SERVER_NAME;Initial Catalog=EMP;Integrated Security=True"; private void Form1_Load(object sender,EventArgs e) { conn = newSqlConnection(constring); conn.Open(); comm1 = newSqlCommand("select userid from userdet", conn); SqlDataReader reader = comm1.ExecuteReader(); while (reader.Read()) { cmbuserid.Items.Add(reader[0]); } reader.Close(); conn.Close(); } private void btnshowrecord_Click(object sender,EventArgs e) { adapter1 = newSqlDataAdapter("select * from userdet", constring); adapter2 = newSqlDataAdapter("select * from moneytrans", constring); ds1 = new System.Data.DataSet(); adapter1.Fill(ds1); ds2 = new System.Data.DataSet(); adapter2.Fill(ds2); dgvforuserdet.DataSource = ds1.Tables[0]; dgvformoneytrans.DataSource = ds2.Tables[0]; } private void btnok_Click(object sender,EventArgs e) { if (txtamount.Text =="" || cmbuserid.Text =="") { MessageBox.Show("Plz, Write Amout");

} else { conn = newSqlConnection(constring); conn.Open(); comm2 = newSqlCommand("insert into moneytrans values(" + cmbuserid.SelectedItem.ToString() +"," + txtamount.Text +")", conn); comm3 = newSqlCommand("update userdet set amount=amount-'" + txtamount.Text +"' where userid="+ cmbuserid.SelectedItem.ToString()+" ", conn); trans = conn.BeginTransaction(); comm2.Transaction = trans; comm3.Transaction = trans; try { comm2.ExecuteNonQuery(); comm3.ExecuteNonQuery(); trans.Commit(); MessageBox.Show("Transaction Complted. "); } catch (Exception) { trans.Rollback(); MessageBox.Show("Transaction Failed.."); } } conn.Close(); } } } Note here (In the try block of code), I have used commit() method after both ExecuteNonQuery. Suppose first ExecuteNonQuery() statement has executed (Means amount has been transferred to moneytrans table) and any error has occurred. Then inconsistency will be generated in Database because error has occurred after execution of first ExecuteNonQuery statement. So, although Amount has transferred from userdet table but Database table will show full amount as previous). So commit() should be used after execution of all transaction statement. If there will be any error, then control will jump to catch block where we have used Rollback(), which will rollback the transaction. Output:

Click at "Show All Record" button. It will show the all records of both table. Output:

Now, fill the form and click "ok" button.

After clicking ok button, a messagebox will is appeared with confirm message of transaction. Like as below figure.

Now see the record of Database table to view all transaction.

Suppose a user writes the wrong amount( Non numeric value) in the amount field, then the transaction will be rolledback. Like the below figure. Entering Wrong Input:

Output:

Fastest way to populate datatable from database using IDataReader


Alright folks! Who knows the panic of using a SqlDataAdapter class to fill the Datatable. If you require only a single table to be filled from the database, then this post is to show you there's an alternate way to get a DataTable. That alternate way is returning a DataReader from the command object after executing the command. Well I always thought of a DataReader when it comes to performance but I can't forget to keep the data in memory and also keep in mind that the DataReader works in connected mode. So I came up with a mixed approach; reading the fetched the data from a DataReader and then put the data into a DataTable. The next thing was to make it reusable so finally I did some juggling with the code and came up with the code below that can convert your DataReader object to a DataTable. I always use IDataReader to receive the object returned from the Command.ExecuteReader() method. You can get the schema of the Table a by method that is available through the IDataReader interface GetSchemaTable(). I'll use this method to get the schema of the table that IDataReader is holding. Then I create a new DataTable using the data we received from the schema and start populating it by using the data in the DataReader. See the below snippet; I've put all the ideas together and created this method GetDataTableFromDataReader(). public DataTable GetDataTableFromDataReader(IDataReader dataReader) { DataTable schemaTable = dataReader.GetSchemaTable(); DataTable resultTable = new DataTable(); foreach (DataRow dataRow in schemaTable.Rows) { DataColumn dataColumn = new DataColumn();

dataColumn.ColumnName = dataRow["ColumnName"].ToString(); dataColumn.DataType = Type.GetType(dataRow["DataType"].ToString()); dataColumn.ReadOnly = (bool)dataRow["IsReadOnly"]; dataColumn.AutoIncrement = (bool)dataRow["IsAutoIncrement"]; dataColumn.Unique = (bool)dataRow["IsUnique"]; resultTable.Columns.Add(dataColumn); } while (dataReader.Read()) { DataRow dataRow = resultTable.NewRow(); for (int i = 0; i < resultTable.Columns.Count - 1; i++) { dataRow[i] = dataReader[i]; } resultTable.Rows.Add(dataRow); } return resultTable; } Now you can use this method to fetch the data in the DataReader and then get the DataTable from it. Its really fast I'm telling you! Yeah people can ask me about the complexity of creating another table's schema and looping through the records, but this method is still worth using over the SqlDataAdapter class. Let me go though a small demo over this. Let's create a DB connection and use this method and the Adapter method to get the Performance records. public class DAL { static SqlConnection connection; public DAL() { connection = new SqlConnection(); connection.ConnectionString = System.Configuration.ConfigurationSettings.AppSettings["myConnectionString"]; } public DataTable GetDataTableByAdapter(string query) { connection.Open(); DateTime start = DateTime.Now; DataTable dt = new DataTable(); new SqlDataAdapter(query, connection).Fill(dt); TimeSpan ts = DateTime.Now.Subtract(start); System.Diagnostics.Trace.Write("Time Elapsed in Adapter: "+ts.TotalMilliseconds); connection.Close(); return dt; } public DataTable GetDataTableFast(string query) { connection.Open(); DateTime start = DateTime.Now; IDataReader rdr = new SqlCommand(query, connection).ExecuteReader();

DataTable resultTable = GetDataTableFromDataReader(rdr); TimeSpan ts = DateTime.Now.Subtract(start); System.Diagnostics.Trace.Write("Time Elapsed in Custom : " + ts.TotalMilliseconds); connection.Close(); return resultTable; } } Now lets call this method in a console application and then we'll go through the Trace where the code will be writing the elapsed time in individual operation. static void Main(string[] args) { DAL dal = Singleton<DAL>.Instance; string query = "Select * from Production.Product"; DataTable dt1 = dal.GetDataTableFast(query); DataTable dt = dal.GetDataTableByAdapter(query); System.Console.Read(); } Now Run the code and let's have a look at figures. I ran this program 2 times just to make sure counts are correct First Run - Time Elapsed in Adapter: 93.0053 Time Elapsed in Custom : 13.0008 Second Run - Time Elapsed in Adapter: 129.0074 Time Elapsed in Custom: 14.0008 So I'm sure you must be impressed with the performance here. Moreover you can make it faster by using the Parallel.For() and Parallel.Foreach() loop if you are working on .NET 4.0 and have a multicore processor. Get Smarter. Get Faster!! Nobody wants to wait.

Generic Data Access Layer: Part 1


In this article we will be discussing how we can create a Generic Data Access Layer which we could use in developing our Business Applications. Lets start by creating a Data Model. Create a ADO.NET Entity Data Model as shown below :

Once the Data Model is added to my project, I can then move to the next step, Creating a Repository. Creating a Repository Class publicclass Repository<T>where T : EntityObject { IObjectSet<T> _objectSet; /// <summary> /// This method is used to pass the Context object as a parameter to the Respository ///</summary> ///<param name="objectContext"></param> public Repository(ObjectContext objectContext) { _objectSet = objectContext.CreateObjectSet<T>(); } /// <summary> /// This method we manually pass the Context Object /// ///</summary> public Repository() { DataEntities context =new DataEntities (); _objectSet = context.CreateObjectSet<T>(); } public IQueryable<T> AsQueryable() { return _objectSet; } public IEnumerable<T> GetAll() {

return _objectSet.ToList(); } public IEnumerable<T> Find(Expression<Func<T,bool>> where) { return _objectSet.Where(where); } public T Single(Expression<Func<T,bool>> where) { return _objectSet.Single(where); } public T First(Expression<Func<T,bool>> where) { return _objectSet.First(where); } public void Delete(T entity) { _objectSet.DeleteObject(entity); } public void Add(T entity) { _objectSet.AddObject(entity); } public void Attach(T entity) { _objectSet.Attach(entity); } } I can now use this Repository Class in a Client Project and easily access or modify the Entities using the Above methods. The client code would look like below : Repository<Company> company = new Repository<Company>(); foreach (Company comp in company.GetAll()) { Console.WriteLine(comp.Name); } Console.ReadLine(); Note that here I am not using the context object at all to get the entities as I have already taken care of that in the below code in Repository Class . /// <summary> /// This method we manually pass the Context Object /// /// </summary> public Repository() {

DataEntities context =new DataEntities (); _objectSet = context.CreateObjectSet<T>(); } Thanks . In my next post we will look into how we can improve on this Data access Layer which we have just created.

ADO .NET Evolution: Part I: 2-Tier to 3-Tier


Hey .Net Experts. You might have started using .Net 4.0 and Visual Studio 2010. But are you sure that you all are using most of the advance features of .Net or still you are using the same boring .Net 1.1 features, as someone said "Old Wine in New Bottle". If so, I think this article will help you to implement some new features available in .Net 2.0/3.5/4.0. Abstract This article will guide you to migrate your application from 2-Tier architecture (was possible in VB6.0, .Net 1.0/1.1) to the most advance Data Access methodology available in .Net 4.0. Please keep watching all migration articles one by one. If it really helps you out then please don't forget to put your feedback and comments. Old Wine in New Bottle If you are writing all the data access logic inside your code behind, I guess your code looks like this. While Inserting Data into Database:

SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["EmployeeConString"].C onnectionString); SqlCommand sqlCommand = new SqlCommand(string.Format("INSERT INTO Department (DepartmentId, Name, Budget, StartDate) VALUES ({0}, '{1}', {2}, '{3}')", txtDeptId.Text, txtDeptName.Text, txtBudget.Text, txtStartDate.Text), sqlConnection); sqlConnection.Open(); sqlCommand.ExecuteNonQuery(); sqlConnection.Close(); While Binding Data to ComboBox /DropDownList: SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["EmployeeConString"].C onnectionString); SqlDataAdapter sqlDataAdapter = new SqlDataAdapter("SELECT DepartmentId, Name FROM Department", sqlConnection);

DataTable deptList = new DataTable("Department"); sqlDataAdapter.Fill(deptList); cmbDepartment.DataSource = deptList; cmbDepartment.DisplayMember = "Name"; cmbDepartment.ValueMember = "DepartmentId"; OR While Binding Data to DataGridView: SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["EmployeeConString"].C onnectionString); SqlCommand sqlCommand = new SqlCommand("SELECT DepartmentId, Name FROM Department", sqlConnection); sqlConnection.Open(); SqlDataReader dataReader = sqlCommand.ExecuteReader(); while (dataReader.Read()) cmbDepartment.Items.Add(dataReader["Name"].ToString()); dataReader.Close(); While Binding Data to ListView: SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["EmployeeConString"].C onnectionString); SqlCommand sqlCommand = new SqlCommand("SELECT DepartmentId, Name, Budget, StartDate FROM Department", sqlConnection); sqlConnection.Open(); SqlDataReader dataReader = sqlCommand.ExecuteReader(); while (dataReader.Read()) { ListViewItem item = new ListViewItem(dataReader["DepartmentId"].ToString()); item.SubItems.Add(dataReader["Name"].ToString()); item.SubItems.Add(dataReader["Budget"].ToString()); item.SubItems.Add(dataReader["StartDate"].ToString()); lvwDepartment.Items.Add(item); } dataReader.Close(); So, all your data access code is being meshed up within the code behind and these practices were very old compared to the new advanced design patterns. Let's do this application in a 3-Tier approach. Although the 3-Tier approach is obsolete, still it is the base for any advanced design pattern. So it's very much essential to learn and know the pattern. Let's see the fundamental diagram of a 3-Tier architecture. Basics of 3-tier Architecture:

Basic 3-Tier architecture

Figure 1: Basic 3-Tier architecture The above describes a very simple architecture of a 3-tier model. DAL (Data Access Layer) interacts with Database directly, so all the SQL operation are being done within DAL only. BLL (Business Logic Layer) works like a mediator between DAL and the Presentation Tier. No direct communication is allowed between DAL and Presentation Layer. Although there is no physical presence of the Entity Layer, but Entity encapsulates all the information/data and passes it from one layer to the other. So all the Database object name and the Database Schema is being restricted inside the DAL which gives an extra security layer to the application. As Business rules/logics are being defined inside BLL, any update to business logic will not impact the DAL and the presentation layer.

Figure 2: Complex 3-Tier Architecture This diagram describes an actual implementation of a 3-tier model. Data Access Service and the Database Server can be hosted in single Server. Mostly SQL Server 2000/2005/2008 or Oracle can be hosted on Windows 2000/2003 Server. Business Server exposes all the operation through Web Service /Remoting/WCF. A highly configured server with Windows 2000/2003 can be used to host the Business Service, or else Microsoft BizTalk Server also can be used for this. Presentation Tier or the Client Consumes the Service exposed at Business Server by using the Proxy through http:// pipeline. Client can be any standalone machine with the application is being installed in case of Desktop Application (Win-Form or Console Application), or having a Browser to run Web Application. Data/Information are being encapsulated by entity and transferred from one location to another over network followed by all the network protocol.

To know more about 3-Tier Architecture please visit my next Article ADO .NET Evolution: Part I: 2-Tier to 3-Tier.

Database Installer For Production

Objective Many times it is necessary to install a database to a production machine which is not accessible from the development environment. This article explains how to install a database to production and build a tool do so. Free source code of the tool is available for download. Note : If your zip archiver is unable to open the download, please use 7 Zip (free) to do so. Implementation The tool I have made uses VSDBCMD.exe for actually deploying the database from a model of the database. The first step is to create a Database Project in Visual Studio for the database. This project should contain all the SQL for the tables, stored procedures, post-deployment script etc. Then build the database project. This creates model files in the sql\release folder of the project. The following image shows the files that are created by the build.

The tool (following image) uses these model files to install the database.

Use the browse button to get the path to the model files. The connection string contains the Data Source, User ID and Password (or Integrated Security, if the database can be accessed by the logged in user account). The database name is the name of the database created from the model. After entering this information, when you click install, VSDBCMD.exe is invoked in a Process. This installs the database on the server. Process installProcess = new Process { StartInfo = new ProcessStartInfo { CreateNoWindow = true, WindowStyle = ProcessWindowStyle.Hidden, FileName = "VSDBCMD.exe", Arguments = @"/a:Deploy /dd /cs:""" + ConnStr + @""" /dsp:Sql /model:" + modelName + @".dbschema /p:TargetDatabase=" + DbName + @" /manifest:" + modelName + @".deploymanifest" } }; installProcess.Start(); installProcess.WaitForExit(); For uninstalling (deleting) the database, just enter the connection string and the name of the database. This drops the database. SqlConnection conn = new SqlConnection(ConnStr); SqlCommand command = new SqlCommand("DROP DATABASE " + DbName, conn); conn.Open(); command.ExecuteNonQuery(); conn.Close(); You will see the installed database on the server (as shown below).

So, you can copy the tool and the output of the database project (model) to the production machine and install the database using the tool.

There is also a Setup project which produces a Setup.exe. This can be used to install the tool on a computer. Note : The tool needs .Net 4.0 Runtime to run. It can install models created in VS 2008 and VS 2010 database projects for SQL Server 2005/2008.

How to Create a Strongly Typed DataSet


In this article we are going to see how to create a Strongly Typed DataSet using the Visual Studio .NET IDE . Follow these steps to create a Strongly Typed DataSet : 1. In Visual Studio .NET 2008/2010, click File > New > Project. 2. Select your desired programming language and then select the Console Application template. 3. Right-click on the project in Solution Explorer and click Add > New Item. On the Add New Item dialog select DataSet from the items list. Name the DataSet StronglyTypedDataSet.xsd. Click on Add button to create the DataSet.

4. Now, If you do not already have a Database Connection, create a new one >

Open Server Explorer by selecting View > Server Explorer from the main menu. Right click on the Data Connections node and select Add Connection from the context menu.

5. In the next dialog box, select the SQL Server. In the Add Connection dialog select Server name. Under Log on to the server, do one of the following: o o Click Use Windows Authentication to use your current Windows user name and password. Click Use SQL Server Authentication and then type your user name and password in the corresponding User Name and Password boxes.

Here we are using log on mode as Windows Authentication. Under Connect to a database select or enter a database name. We are using AdventureWorks database. Click on Test Connection button and then OK button to create the connection.

6. Now expand the Tables node in Server Explorer for the Data Connection that you just added. Select the Customer (Sales) and CustomerAddress (Sales) tables and drag them onto the DataSet Designer surface. 7. This adds both tables to the strongly typed DataSet. If you don't want all of the columns in a table, expand a table and drag just the columns you need onto the design surface. The designer now shows the two tables together with the data relation between the tables.

8. The strongly typed DataSet is complete and you can now use it.

How to Create a DataTable And Add it to a DataSet


In this article we are going to see how to create a DataTable and add it to a DataSet. Example : using System; using System.Data; namespace CreateDataTable { classProgram { static void Main(string[] args) { DataSet objDs = newDataSet(); // Add a DataTable to DataSet directly DataTable objDt1 = objDs.Tables.Add("Table 1"); // add some columns here // Creating the table and adding it to the DataSet DataTable objDt2 = newDataTable("Table 2"); // add some columns here objDs.Tables.Add(objDt2);

// Add multiple DataTables to the DataSet DataTable objDt3 = newDataTable("Table 3"); DataTable objDt4 = newDataTable("Table 4"); // add some columns here objDs.Tables.AddRange(newDataTable[] { objDt3, objDt4 }); Console.WriteLine("DataSet has {0} DataTables \n", objDs.Tables.Count); foreach (DataTable objDt in objDs.Tables) Console.WriteLine("{0}", objDt.TableName); Console.WriteLine("\nPress any key to continue."); Console.ReadLine(); } } } In this example we are using the Add() and AddRange() methods of the DataTableCollection of the DataSet to add a DataTable to a DataSet. Here are examples of three different techniques to add a DataTable to a DataSet. 1. Add a DataTable directly to a DataSet 2. Create a DataTable and Add it to a DataSet 3. Create multiple DataTable objects and add them to DataSet using the AddRange() method of the DataTableCollection of the DataSet. The DataTableCollection contains all of the DataTable objects for a particular DataSet. You can access the DataTableCollection of a DataSet using the Tables property. The key methods of the DataTableCollection are Add(), AddRange(), AddRange(), Clear(), Contains(), CopyTo(), IndexOf(), Remove(), RemoveAt() Add() method has four overloads: Add() Add(DataTable dataTable) Add(string tableName) Add(string tableName, string namespace)

Output :

Learn ADO.Net Entity Framework: Performing Basic CRUD Operation


This article is a walkthrough of performing basic CRUD operations using the ADO.Net Entity Framework. Database design I am going to use a School Database. You can find the School database script here. To be precise, I am going perform CRUD operations on only one table; Person. The schema of the Person table is as below.

I am going to perform CRUD operations on the Person table from a console application. Create Data Model 1. Right-click on the console application and select "Add | New Item..." 2. From the Data tab select ADO.Net Entity Data Model. If you want you can change the name of the model.

3. Click the Add button; you will get a dialog box. From there select the "Generate
from database" option:

4. Create a new connection

5. Give database server name and choose database from the drop down as given
below,

After clicking on Ok button, notice that you have returned to the previous dialog box and a connection setting has been created. The name of the connection setting is as below: Database name + Entities = default connection setting name If the database is School then the default connection setting name would be schoolentites. However, if you want you can change the default connection setting name as desired.

6. Now you need to choose Data objects to make them a part of the Data Model.
From the following dialog box you can choose tables, stored procedures and views. Since we are going to perform CRUD operations only on the Person table, I will choose only the Person table to be part of Data Model.

If you want, you can change the Model Namespace name. By default it would be Database name suffixed with Model. Now click Finish to create the data model. Performing CRUD operation Retrieving all the records You can fetch all the records as below.

Add a person You can add a person in three steps:

1. Create object of Person 2. Call add object on pluralize Person entity. In this case this is People 3. Call save changes on entities

Modify a Person To modify a person you need to perform three steps 1. Fetch the Person to be modified 2. Modify the desired values of the columns Call save changes on the entities

Delete a Person To delete a person you need to perform three steps: 1. Fetch the Person to be deleted 2. Call delete object on entities 3. Call save changes on the entities

The full source code is given below: using using using using System; System.Collections.Generic; System.Linq; System.Text;

namespace ADONetEntityModelfirstDemo {

class Program { static void Main(string[] args) { #region Reterive a Person SchoolEntities entities = new SchoolEntities(); var result = from r in entities.People select r; foreach (var r in result) { Console.WriteLine(r.PersonID + r.LastName); } Console.ReadKey(true); #endregion #region Add a Pesron entities.People.AddObject(new Person { FirstName = "dhananjay", LastName = "kumar" }); entities.SaveChanges(); #endregion #region Modify a Person Person personToModofy = (from r in entities.People.Where (a => a.PersonID == 1) select r).FirstOrDefault(); personToModofy.LastName = "Jamshedpur"; entities.SaveChanges(); #endregion #region Delete a Person Person personToDelete = (from r in entities.People.Where (a => a.PersonID == 1) select r).FirstOrDefault(); entities.People.DeleteObject(personToDelete); entities.SaveChanges(); #endregion #region Reterive a Person var result1 = from r in entities.People select r; foreach (var r in result1) { Console.WriteLine(r.PersonID + r.LastName); } Console.ReadKey(true); }

#endregion } } In a future article, we will discuss other aspects of the ADO.Net Entity framework. I hope this article was useful. Thanks for reading.

Working With the DataTable Class in C#


A DataTable object represents tabular data as an in-memory, tabular cache of rows, columns, and constraints. You typically use the DataTable class to perform any disconnected data access. The DataTable is a central object in the ADO.NET library. Other objects that use the DataTable include the DataSet and the DataView. DataTable objects are conditionally case-sensitive. For example, if you are using one DataTable named "ObjDataTable" and another one named "objDataTable", a string used to search for one of the tables is regarded as case-sensitive. However, if "ObjDataTable" exists and "objDataTable" does not, the search string is regarded as case-insensitive. For creating a DataTable you first create an instance of the DataTable class, and then add DataColumn objects that define the type of data to be held and insert DataRow objects that contain the data. The following code demonstrates the creation of a data table: //Create the DataTable named "Order" DataTable order = new DataTable ("Order"); Using this code you are creating an empty data table for which the TableName property is set to Order. You can use this property to access this data table from a DataTableCollection. Adding DataColumn Objects and Create a Schema A DataTable contains a collection of DataColumn objects referenced by the Columns property of the table. This collection of columns, along with any constraints, defines the schema, or structure, of the table. The DataTable object is not useful until it has a schema, which is created by adding DataColumn objects and setting the constraints of each column. Constraints help maintain data integrity by limiting the data that can be placed in the column. The following example adds DataColumn objects to an order DataTable object. //Add the DataColumn using all properties DataColumn ordId = new DataColumn("OrderID"); ordId.DataType = typeof(int); ordId.Unique = true; ordId.AllowDBNull = false; ordId.Caption = "ORDER ID"; order.Columns.Add(ordId); //Add the DataColumn using defaults DataColumn quant = new DataColumn("Quantity"); quant.MaxLength = 35;

quant.AllowDBNull = false; order.Columns.Add(quant); DataColumn deDate = new DataColumn("DeliveryDate", typeof(DateTime)); deDate.AllowDBNull = false; order.Columns.Add(deDate); //Derived column using expression DataColumn yearMake = new DataColumn("Year and Make"); yearMake.DataType = typeof(string); yearMake.MaxLength = 70; yearMake.Expression = "Year + ' ' + Make"; order.Columns.Add(yearMake); DataColumn Properties Name Description AllowDBNull Gets or sets a value that indicates whether null values are allowed in this column for rows that belong to the table. Autoincrement Gets or sets a value that indicates whether the column automatically increments the value of the column for new rows added to the table. AutoincrementSeed Gets or sets the starting value for a column that has its Autoincrement property set to true. AutoincrementStep Gets or sets the increment used by a column with its Autoincrement property set to true. Caption Gets or sets the caption for the column. ColumnName Container DataType Expression MaxLength Unique Gets or sets the name of the column in the DataColumnCollection . Gets the container for the component. Gets or sets the type of data stored in the column. Gets or sets the expression used to filter rows, calculate the values in a column, or create an aggregate column. Gets or sets the maximum length of a text column. Gets or sets a value that indicates whether the values in each row of the column must be unique.

Creating Primary Key Columns The primary key of a DataTable object consists of a column or columns that make up a unique identity for each data row. The following code shows how to set the PrimaryKey property for the order DataTable object: //Set the Primary Key order.PrimaryKey = new DataColumn[] { OrderID }; Automatic Numbering for the Primary Key Column You can set up an auto-increment column, by setting the AutoIncrement property of your data column to true. After that, you set AutoIncrementSeed to the value of the first number you want and set AutoIncrementStep to the value you want to increment each time a new row is added.

The following example shows how to set the AutoIncrement, AutoIncrementSeed, and AutoIncrementStep properties. private void AddAutoIncrementColumn() { DataColumn column = new DataColumn(); column.DataType = System.Type.GetType("System.Int32"); column.AutoIncrement = true; column.AutoIncrementSeed = 1000; column.AutoIncrementStep = 10; // Add the column to a new DataTable. DataTable table = new DataTable("table"); table.Columns.Add(column); } Creating DataRow Objects After the DataTable object is created and contains DataColumn objects, you can populate the DataTable object by adding DataRow objects. Use the DataRow object and it's properties and methods to retrieve and evaluate; and insert, delete, and update the values in the DataTable. The DataRowCollection represents the actual DataRow objects in the DataTable. DataRowCollection has an Add method that accepts a DataRow object. The Add method is also overloaded to accept an array of objects instead of a DataRow object. The following sample demonstrates how to create and add data into the order DataTable object: //Add New DataRow by creating the DataRow first DataRow newOrder = order.NewRow(); newOrder ["OrderID "] = "O12345"; newOrder ["Quantity"] = 5; newOrder ["Year and Make"] = 2002; order.Rows.Add(newOrder); //Add New DataRow by simply adding the values order.Rows.Add("O9876", 10 , 2001); Note : nothing has been permanently stored to a database. Deleting the Data Row You can delete a DataRow from the DataRowCollection by calling the Remove method of the DataRowCollection, or by calling the Delete method of the DataRow object. The Remove method removes the row from the collection. In contrast, Delete marks the DataRow for removal. The actual removal occurs when you call AcceptChanges method. The DataRow object doesn't have an Undelete method. However, in some situations, you can use the RejectChanges method to roll back to a previous state when the deleted row was still there. Be aware that executing the RejectChanges method copies the Original data row version to the Current data row version. Enumerating the Data Table You can loop through the rows and columns of the data table by using a foreach statement. The following example shows how to enumerate through the rows and

columns of a data table. public string EnumerateTable(DataTable orders) { System.Text.StringBuilder objSB = new System.Text.StringBuilder(); foreach (DataColumn objDc in orders.Columns) { objSB.AppendFormat("{0,15} ", objDc.ColumnName); } objSB.Append("\r\n"); foreach (DataRow objDr in orders.Rows) { if (objDr.RowState == DataRowState.Deleted) { objSB.Append("Deleted Row"); } else { foreach (DataColumn objDc in orders.Columns) { objSB.AppendFormat("{0,15} ", objDr[objDc]); } } objSB.Append("\r\n"); } return objSB.ToString(); } Copying and Cloning the Data Table If you want to create a full copy of a data table you can do this by using the DataTable object's Copy method, which copies the DataTable object's schema and data. The following example shows how to invoke the Copy method. private void CopyDataTable(DataTable myDataTable) { // Create an object variable for the copy. DataTable copyDataTable; copyDataTable = myDataTable.Copy(); // Insert code to work with the copy. } In some cases you need a copy of the DataTable schema without data. To copy just the schema without data, you can invoke the DataTable object's Clone method. The following example shows how to invoke the Clone method. private void GetClone(DataTable myDataTable) { // Get a clone of the original DataTable. DataTable cloneTable; cloneTable = myDataTable.Clone(); // Insert code to work with clone of the DataTable. }

Importing DataRow Objects into a Data Table DataTable contains an ImportRow method, which you can use to copy a data row from a data table that has the same schema. The ImportRow method is useful when the Current and Original data row version must be maintained. Example : DataTable clone = order.Clone(); clone.ImportRow(order.Rows[0]);

How To Create The Multi-level Class Library DataEntityTier


Step:1 Click the File menu and choose New Project. In the New Project dialog box, select Windows in the Project Types pane. Click the Class Library template and DataEntityTier Specify the name of the project. Specify the name of the solution and NTierWalkthrough OK. This creates a solution containing the draft NTierWalkthrough DataEntityTier that is added to Solution Explorer. Step 2: To create a new class library for the TableAdapter: Right click on the Solution Explorer and choose Add New Project so just add a new project to the solution NTierWalkthrough. In the Templates pane of the New Project dialog box, click Class Library, and DataAccessTier Give the project name, then click OK. DataAccessTier the project is created and added to the solution NTierWalkthrough. Step 3: To create the dataset Click DataAccessTier in Solution Explorer and choose Show Data Sources from the Data menu. In the Data Sources window, click Add New Data Source to start the Configure Data Source wizard. On the Select a data source type, click Database and click Next. In the Choose Your Data Connection page do one of the following:

Select the data connection to the Northwind sample database, drop-down list, if present.

or Click New Connection to open the Add Connection dialog box and choose a database on SQL Server. Click Next on the Save connection string in application configuration files Expand the Tables node in the page. Choose your database objects. Select the check boxes for the Customers and Orders tables, and then click Finish. DataAccessTier NorthwindDataSet is added to the project and appears in the Data Sources window. Step 4: To separate the TableAdapter in the dataset: Double-click NorthwindDataSet.xsd in Solution Explorer to open the dataset in the Dataset Designer. Click an empty area of the designer. Locate the DataSet Project node in the Properties window. DataSet Project list, click DataEntityTier. Select Build Solution from the Build menu. Step 5: To create a new WCF service application: To add a new project, right-click Solution Explorer, choose Add New Project. In the New Project dialog box, select WCF in the Project Types pane. In the Templates pane, click Library and WCF Service. Name the project DataService name, then click OK. DataService the project is created and added to the solution NTierWalkthrough. Step 6: Create a method in the data access layer to return the Customers table and Orders table. Double NorthwindDataSet.xsd on in Solution Explorer to open the dataset in the Dataset Designer. Click the right mouse button and select Add Query on CustomersTableAdapter to open the Query Wizard TableAdapter. On the Select a type of command to leave the default Use SQL Statements and click

Next. In the Choose a Query Type page, leave the default SELECT statement that returns rows, then click Next. On the Specify a SQL SELECT query, leave the default and click Next. On the Choose the type GetCustomers methods to generate the method name in the Return a DataTable. Click Finish. Please note that the same procedure must be repeated for the Orders table, ok? And then from the Build menu, click Rebuild Solution and compiled. Step 7: To add references to the data service: In Solution Explorer, right-click the right mouse button and choose Add Reference on DataService. In the Add Reference dialog box, click the Projects tab and select both projects and DataAccessTier DataEntityTier. And OK. Step 8: Create functions and GetCustomers GetOrders in the data service: DataService in the project, double-click IService1.cs. and add the following code below the comment . Then double-click Service1.cs.e and add the following code to the Service1 class. Then fill in the Solution. Step 9: Create the presentation layer: To add a new project, right-click Solution Explorer, choose Add New Project. In the New Project dialog box, select Windows in the Project Types pane and in the Templates pane, click Windows Application. Forms Give the project name PresentationTier, then click OK. PresentationTier The project is created and added to the solution NTierWalkthrough. To set the new project as startup project, in Solution Explorer, right-click the right mouse button and click on PresentationTier.

Set as StartUp Project. Now we PresentationTier please add a project reference, then click the right-click and PresentationTier. Choose Add Reference. In the Add Reference dialog box, click the Projects tab and then click Select DataEntityTier. OK. At this point you dinuovo click the right-click and choose Add Reference PresentationTier service. In the Add Reference dialog box, click Find in the service and select Service1 and OK. Step 10: Add two data-bound DataGridView to the form: In Solution Explorer, select the project and PresentationTier In the Data Sources window, expand NorthwindDataSet, then find the node Customers. Drag the Customers node onto Form1. In the Data Sources window, expand the Customers node and find the related Orders, nested in the Customers node. Drag the node onto Form1 and related Orders Create a handler for the Form1_Load event by double-clicking an empty area of the form. Add the following code to the Form1_Load event handler. Now double-click app. Config and Project PresentationTier apritelo.Trovare the dimension attribute and maxReceivedMessageSize change the value to 6553600. Now press F5 and you will notice that the Customers and Orders tables of data are retrieved from the data service and displayed on the form. Have fun everyone! By Anna.

Inserting Images and Reading the Images Through ADO.NET


In this article we are going to learn about storing an image in a database like that of SQL Server 2005. And after storing, how to retrieve stored images. As we all know the size of an image is large; in a database like Oracle we need to store the image in the form of Blob data type or a bfile data type, but in SQL Server we have

one data type for storing the images and that is image data type. So for storing the image we need to create one table with image data type; the following is the SQL code. create database Test create table TestBlob ( imPhoto image not null ) In the above code we just created one database and within that database we created one table whose name is TestBlob which contains only one column imPhoto whose data type is image. Now for adding the image from the front end to the back end we need to create a user interface; the design is:

We specified the anchor property of the button to be the top and right and that of the textbox to be top and left. We are using six buttons: 1. 2. 3. 4. 5. 6. One for browsing For inserting data into database Getting the first images from the database Getting the Previous image from the database Moving to next image Moving to last image.

Now the following is the coding which will add the data to the database and we can read the data as and when we need it. using using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Text; System.Windows.Forms; System.IO; System.Data.SqlClient;

namespace ImagePractice { public partial class Form1 : Form { SqlConnection con; SqlCommand cmd; SqlDataReader dr; OpenFileDialog ofd; SqlDataAdapter da; DataSet ds; int indexno = 0; public Form1() { InitializeComponent(); } //for Browing the image files from our computer. private void button1_Click(object sender, EventArgs e) { ofd = new OpenFileDialog(); //ofd.InitialDirectory = @"c:\"; // for filtering the openfiledialog so that it should display only the images file ofd.Filter = "Image Files(*.bmp;*.jpg;*.gif)|*.bmp;*.jpg;*.gif"; if (ofd.ShowDialog() == DialogResult.OK) { textBox1.Text = ofd.FileName; } else if(ofd.ShowDialog()==DialogResult.Cancel) { MessageBox.Show("You Clicked Cancelled"); } } private void Form1_Load(object sender, EventArgs e) { con = new SqlConnection("Data Source=localhost;Initial Catalog=Test;User Id=sa;Password=faculty"); LoadImage(); } private void LoadImage() { da = new SqlDataAdapter("Select * from TestBlob", con); ds = new DataSet(); da.Fill(ds, "TestBlob");

if (ds.Tables[0].Rows.Count > 0) { byte[] photo = (byte[])ds.Tables["TestBlob"].Rows[indexno][0]; MemoryStream ms = new MemoryStream(photo); pictureBox1.Image = Image.FromStream(ms); } } private void btnNext_Click(object sender, EventArgs e) { try { if (indexno < ds.Tables[0].Rows.Count) { indexno++; LoadImage(); } else { MessageBox.Show("You are on Last Record"); } } catch (Exception e1) { MessageBox.Show("You are on Last Record"); } } private void btnInsert_Click(object sender, EventArgs e) { FileStream fs = new FileStream(textBox1.Text, FileMode.OpenOrCreate, FileAccess.ReadWrite); byte[] rawbyte = new byte[fs.Length]; fs.Read(rawbyte, 0, Convert.ToInt32(fs.Length)); con.Open(); cmd = new SqlCommand("Insert into TestBlob values(@photo)", con); cmd.Parameters.AddWithValue("@photo", rawbyte); int rows = cmd.ExecuteNonQuery(); if (rows > 0) { MessageBox.Show("Inserted Successfully"); textBox1.Text = ""; } else { MessageBox.Show("Error Inserting Data"); } } private void btnPrev_Click(object sender, EventArgs e) { if (indexno > 0) { indexno--; LoadImage(); } else {

MessageBox.Show("You are on First Image"); } } private void btnFirst_Click(object sender, EventArgs e) { indexno = 0; LoadImage(); } private void btnLast_Click(object sender, EventArgs e) { indexno = ds.Tables[0].Rows.Count - 1; LoadImage(); } } }

Code Snippet for Fetching Data from Excel Using ADO.Net


Today one of my team members asked me a very simple yet very important question: "How could we fetch Excel Records using ADO.Net? Could you give me code snippet of same? " I replied to him; it is pretty possible using OledDbConnection. I told him to add the following reference. I gave him the following straightforward code snippet. This function is: 1. Returning DataTable 2. Reading XLS file called YourFile.xls from F Drive. 3. Reading Sheet1

public static DataTable GetItemsFromExcel1() { DataTable dt = new DataTable(); OleDbConnection excelConnection = new OleDbConnection(@"Provider=Microsoft.Jet.OLEDB.4.0;" + @"Data Source=F:\YourFile.xls;" + @"Extended Properties=""Excel 8.0;HDR=Yes;IMEX=1;"""); excelConnection.Open(); try { OleDbDataAdapter dbAdapter = new OleDbDataAdapter ("SELECT * FROM [Sheet1$]", excelConnection); dbAdapter.Fill(dt);

} finally { excelConnection.Close(); } return dt; } After using this function in his code, he was very happy and paid my coffee bill...

Inserting records into a database table using a stored procedure and ADO.NET
This article demonstrates how to use ASP.NET and ADO.NET with Visual C# .NET to create and to call a Microsoft SQL Server stored procedure. Stored Procedure A stored procedure is a batch of Transact-SQL statements (like select, insert and update) compiled into a single execution that can be re-used. If you find yourself using the same query over and over again, it would make sense to put them into a stored procedure. Every time you write a query it is parsed in the database. If you have written a stored procedure for it, it will be compiled once and can be executed multiple times. There are two steps involved in executing a stored procedure from your program. First, you set the command object property CommandText as the stored procedure name; second, you set the CommandType property as CommandType.StoredProcedure. Step 1 Now we Create a table in a database named logintab and it has the three columns Login, Password and Id. The Database table looks like the Figure 1 shown below.

Figure 1 Step 2 Now we create a stored procedure in the database named storlog. The stored procedure looks like Figure 2.

Figure 2 Step 3: Calling stored procedure Taking three TextBoxes, one Button and a Label control on the form, the form looks like this.

Figure 3

Now double-click on the Save button control and add the following code. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Web.UI.WebControls; using System.Data.SqlClient; using System.Data; namespace StoreProcedure { public partial class WebForm1 : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { } protected void ButtonSave_Click(object sender, EventArgs e) { string str = "Data Source=.;uid=sa;pwd=Password$2;database=master"; SqlConnection con = new SqlConnection(str); con.Open(); SqlCommand com = new SqlCommand("storlog", con); com.Parameters.Add("@username", SqlDbType.VarChar).Value = TextBoxUsername .Text; com.Parameters.Add("@Password", SqlDbType.VarChar).Value = TextBoxPassword.Text; com.Parameters.Add("@Id", SqlDbType.Int).Value = TextBoxId.Text ; com.CommandType = CommandType.StoredProcedure; com.ExecuteNonQuery(); Label1 .Text= "record has been saved"; con.Close(); } } } The above code defines the connection with the database and command object property CommandText as the stored procedure name; second, you set the CommandType property as CommandType.StoredProcedure. Step 4 Now run the application and enter the username, password and Id in the textboxes. The form looks like this.

Figure 4 Step 5 Now click on the save Button. All record has been saved in the database.

Figure 5 Step 6 Now open the database and test it.

Figure 6

DataBase Operations Using DataSet

Consider a table called employee having two columns employeeid and eployeename. Here we will use the five buttons insert, update, delete, first, previous, next and new. Using Microsoft.VisualBasic; Class declarations sqlConnection Con;sqldataadapter da;sqlcomandbuilder cb;dataset ds;int rno; Under form load Con=new OleDbConnection("User Id=sa;pwd=123;database=dbname"); Da=new sqldataadapter("select * from employee",con); Ds=new dataset(); Da.missingschemaschema=MissingSchemaAction.AddWithkey; Da.Fill(ds,"employee"); Showdata(); Private Void ShowData() { textBox1.Text=ds.tables[].Rows[rno][0].ToString(); textBox2.Text=ds.tables[].Rows[rno][1].ToString(); } Under First Button Rno=0; ShowData(); Under previous Button if( rno>0); {rno-=1; showdata();} Else messageBox.Show("First Record"); Under Next Button if( rno<ds.Tables[0].Rows.Count-1) {rno+=1; showdata();} Else messageBox.Show("Last Record"); Under Last Button Rno=ds.Tables[0].rows.count-1; Showdata(); Under New Button Textbox1.text=textbox2.text=""; Textbox1.readonly=false;textBox1.Focus(); How to add a New Record To add a new record to the datatable adopt the following process: 1. create a new empty row by calling method NewRow() on DataTable

2. Assign values to new row by treating it as a single dimensional array 3. call add method on data table and add row to RowsCollection. Under InserButton DataRow dr=ds.Tables[0].NewRow(); Dr[0]=textBox1.Text; Dr[1]=textBox2.Text; Ds.tables[0].Rows.Add(dr); MessageBox.show("Record Added"); textBox1.Readonly=true; button1.PerformClick(); Under Update Button Ds.tables[0].Rows[rno][1]=textBox1.Text; Under DeleteButton Ds.tables[0].Rows[rno].Delete(); MessageBox.show("Record Deleted"); Under save Button Cb=new SqlCommandBuilder(da); Da.Update(ds,"students"); MessageBox.Show("Data Saved to database"); Under search Button Int employeeid=int.parse(interaction.inputBox("Enter id to search","search",""100,100)); Datarow dr=ds.tables[0].Rows.Finf(employeeid); If(dr!=null) { Textbox1.text=dr[0].ToString(); TextBox2.Text=dr[1].ToString(); } Else MessageBox.Show("Invalid id");}

Treeview Operations Using Database


Description: This article will show you operations on TreeView using Database. It will show you mainly three kinds of operations such as Add, Update & Delete; then after performing those operations the effect will immediately be shown in the Treeview & the GridView. I have written two main functions; the first one is for adding data into a TreeView from the database & the second function is for adding data into DataGridView from the database.

private void BindDataInTreeView() { MyTreeView.Nodes.Clear(); try { conn.Open(); //It will show Name of the Students into TreeView. SqlCommand cmd = new SqlCommand("SELECT StudentName FROM Student", conn); dr = cmd.ExecuteReader(); while (dr.Read()) { //Here "Node" Means It Will Add Nodes As All Root Nodes... MyTreeView.Nodes.Add(dr.GetValue(0).ToString()); } dr.Close(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } finally { conn.Close(); } } private void BindDataInGridView() { try { conn.Open(); //It will show all data of Students into DataGridView. SqlCommand cmd = new SqlCommand("SELECT * FROM Student", conn); DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(ds); MyDataGridView.DataSource = ds.Tables[0]; dr.Close(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } finally { conn.Close(); } } "Student" Table Data Definition :

Data which I have stored:

When you will run this it will show you a window like below:

In the above window it will display a student's name in the TreeView & all data into the DataGridView in the form load event. private void Form1_Load(object sender, EventArgs e) { BindDataInTreeView(); BindDataInGridView(); }

private void btnSaveAdd_Click(object sender, EventArgs e) { if ((txtStudId.Text != null) && (txtStudName.Text != null)) { try { conn.Open(); SqlCommand cmd = new SqlCommand("Insert Into Student Values(" + txtStudId.Text + ",'" + txtStudName.Text + "'," + txtStudContactNo.Text + ");", conn); cmd.ExecuteNonQuery(); MessageBox.Show("Successfully Insert Your Record In Database."); NotVisibleAll(); btnSaveAdd.Visible = false; conn.Close(); BindDataInTreeView(); BindDataInGridView(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); } finally {

conn.Close(); } } else { MessageBox.Show("Please Fill Up Values In Blank Field."); } }

When you click the "Add" button then it will show you textboxes & then you can add new data into the database. Once you have added new data then it will automatically add that new entry in both TreeView & DataGridView.

private void btnSaveUpdate_Click(object sender, EventArgs e) { if ((txtStudId.Text != null) && (txtStudName.Text != null)) { try { conn.Open(); SqlCommand cmd = new SqlCommand("Update Student Set StudentName='" + txtStudName.Text + "', StudentContactNo=" + txtStudContactNo.Text + " WHERE StudentId=" + txtStudId.Text + ";", conn); cmd.ExecuteNonQuery(); MessageBox.Show("Successfully Updated Your Record In Database."); NotVisibleAll(); btnSaveUpdate.Visible = false; conn.Close(); BindDataInTreeView(); BindDataInGridView(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); }

finally { conn.Close(); } } else { MessageBox.Show("Please Fill Up Values In Blank Field."); } }

When you click the "Update" button it will show you textboxes & then you can update data into the database. Once you have updated data then it will automatically be updated in both TreeView & DataGridView.

private void btnSaveDelete_Click(object sender, EventArgs e) { if (txtStudId.Text != null) { try { conn.Open(); SqlCommand cmd = new SqlCommand("DELETE FROM Student WHERE StudentId=" + txtStudId.Text + ";", conn); cmd.ExecuteNonQuery(); MessageBox.Show("Successfully Deleted Your Record In Database."); lblStudId.Visible = false; txtStudId.Visible = false; btnSaveDelete.Visible = false; conn.Close(); BindDataInTreeView(); BindDataInGridView(); } catch (Exception ex) { MessageBox.Show(ex.ToString()); }

finally { conn.Close(); } } else { MessageBox.Show("Please Fill StudentId Field."); } }

When you click on "Delete" button then it will show you textboxes & then you can Delete data from database. Once you deleted Data then it will automatically delete in both TreeView & DataGridView.

Configuring Visual Studio to work with MY SQL Database


To configure Visual Studio to work with MY SQL Database we need to install MYSQL Connector (ADO.NET Driver for MYSQL).

To determine whether we have the MYSQL connector installed in your machine, please perform the following steps. 1) Go to Visual Studio -> View -> Server Explorer. 2) Right Click -> Data Connections -> Add Connection -> Got to Choose Data Source Window -> Check for MYSQL Database.

3) The preceding screen shot confirms that the MY SQL Connector needs to be installed since the MYSQL Database is not displayed in the list. Installing MYSQL Connector 1) Download latest MYSQL Connector (mysql-connector-net-6.3.6.zip) from URL -> http://www.mysql.com/downloads/connector/net/ 2) As of now the latest version of connector available is mysql-connector-net-6.3.6.zip. 3) Unzip the downloaded folder and start installing.

4) Click Set Up Type - Complete

5) During installation we can see (screen shots below) that it reconfigures available Visual Studio instances in our machine to work with MY SQL.

(For Visual Studio 2008)

6) Click Finish- to complete the installation.

7) Once SQL Connector is installed - We can Check in Server Explorer -> Data Connections -> Add New Connection - > in Change Data Source Window->

8) This time we see that the MYSQL Database is being displayed. So in this way we can configure Visual Studio instances in our machine - so that we can work with MYSQL Database.

Server side evaluation of Gridview Data

How to: Easily Query a Database


Introduction Often there is a need to obtain data from a database and sometimes it becomes hectic to write pieces of code again and again. Like Connection Open statement, Error Message Coding, Connection string etc. This can be optimized by making a class and calling the methods of the class with the appropriate query string. Normally one comes across two types of SQL Queries Data Selection Queries i.e. SELECT Data Modification Query i.e. INSERT, DELETE etc

Both return Different Type of Data, in case 1st a single row consisting of few columns or a collection of rows i.e. table is returned. In later case, an int number of effects rows are returned. Using the code Make a Class Query, which has two methods, one for each above mentioned type. The methods take query and connection string as argument and returns appropriate type data. First look at Select Query Method, Here DataSet is used as return type. Complete Code is placed in try catch block to ensure smooth functioning. First SqlConnection is created, and then SqlCommand is created which takes query string and SqlConnection as argument in Constructor. Then Connection is opened. A DataSet is created and then SqlDataAdapter is used to fill the DataSet. Finally Connection is closed and DataSet is returned. public DataSet select_query(string query,string con_str) { try { SqlConnection con = new SqlConnection(con_str); SqlCommand comd = new SqlCommand(query, con); con.Open(); DataSet ds = new DataSet(); SqlDataAdapter da = new SqlDataAdapter(comd); da.Fill(ds); con.Close(); con.Dispose(); return ds; } catch (Exception ex) { data.mymsgshow(ex.Message, 0); return null; } } Now for 2nd type, we need int return type for number of rows affected by the Sql

command. Only Difference here is that ExecuteNonQuery method is used. public int modify_query(string query,global_data data) { try { SqlConnection con = new SqlConnection(data.Con_Str); SqlCommand comd = new SqlCommand(query,con); con.Open(); int x = comd.ExecuteNonQuery(); con.Close(); return x; } catch (Exception ex) { data.mymsgshow(ex.Message, 0); return -1; } } From Main these can be called as Query myquery = new Query(); DataSet ds; ds = myquery.select_query("select * from tablename" , con_str); An Alternate to the above is as following(posted by a nice guy to help) but for a bit advance users. A better solution is to allow the exception to fail: public DataSet select_query(string query, string con_str) { using (SqlConnection con = new SqlConnection(con_str)) { using (SqlCommand comd = new SqlCommand(query, con)) { using (SqlDataAdapter da = new SqlDataAdapter(comd)) { DataSet ds = new DataSet(); da.Fill(ds); // Automatically opens/closes connection. return ds; } } } } } public int modify_query(string query, global_data data) { using (SqlConnection con = new SqlConnection(data.Con_Str)) { using (SqlCommand comd = new SqlCommand(query, con)) { con.Open(); try { int x = comd.ExecuteNonQuery(); return x;

} finally { con.Close(); } } } } }

Create your dataset in C#


In my experience, datasets have always been annoying, because when you need to modify a property of the database you always have to update the tables and table adapters in your xds file and republish the new version of the software. But creating connection and queries with Datasets is easier and faster than creating a Connection Manager class, (but not always the best way). If you are about to create an application involving a Data Grid View, and you need to insert, update or delete; a dataset is your best option. Create your dataset and table adapter 1. Create your frame 2. Drop a Data Grid View control 3. Create a Dataset (xsd) File.

4. Open your xsd file.

5. Drag the table that you want to work with from the server explorer. Your table and table adapter will be created.

If you click the Table Adapter and check its properties you will see that the select, insert, update and delete command are automatically generated. That depends on how your table is designed. When I was working with a table with no primary key, the updated command was not generated. You can add the command, but when it is time to update a record in the data grid view, it could generate some issues and you will not able to update. If you do not want to deal with these problems, set a primary key field to your table when you are designing it; if you do not want to deal these problems, set a primary key field to your table when you are designing it in your data base. Now you check the code that is created automatically in the load form event. This code will fill the data grid view with the current data in your table. 6. Enable the insert, update and delete properties in your data grid view control clicking the option control button .

7. In that same box, choose your data table as your data source

Now your data grid view columns will be generated automatically. Also as your table adapter object, binding source object and dataset object.

Also in the Load Form event this code will appear to fill with the table info every time this window form is loaded.

private void dsDemo001GUI_Load(object sender, EventArgs e) {

// TODO: This line of code loads data into the 'dsDemoDatabase.People' table. You can move, or remove it, as needed.

this.peopleTableAdapter.Fill(this.dsDemoDatabase.People); } 8. Now you need to add a button that will deleted a selected record. 9. Now is time to use the event to update the records from the data grid view. Select the grid view and go to event properties section. 10. Create a CellEndEdit Event. 11. In the code go the event method and type the following code private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e) { this.peopleTableAdapter.Update(dsDemoDatabase); } Now set your grid view needs the Allow User to Add Row to TRUE. Now create a click event button, and type the following code private void button1_Click(object sender, EventArgs e) { foreach (DataGridViewRow row in dataGridView1.SelectedRows) dataGridView1.Rows.Remove(row); this.peopleTableAdapter.Update(dsDemoDatabase); } The button will delete the selected rows from the data grid view and then call the method Update from the Table Adapter object. Also the grid view selection mode property is change to full row selection to avoid exceptions while the row is deleting. Depends of what you are doing the Table Adapter Object call the Update method, and update table in the Dataset and in the base. If you remove rows, calls the delete query; if you add a new row, calls the insert query; and if you are modifying an existing cell calls the update query. Conclusion To use a dataset in a table you must have a good table design in your database (With a Primary Key and an auto-increment column). Dataset can save you a lot time in creating and connection string and queries.

Jump Start to ADO.Net Entity Framework

Well most of our applications are driven by a relational database and business layer associated with it. The amount of time spent to establish a communication between these two can be substantial. So Microsoft has introduced a framework for easy data abstraction called Entity Framework (AEF). AEF does wonders in support of LINQ to Entity and in this article we will have a detailed demonstration.

What Is Entity Framework


The Entity Framework is an abstraction conceptual schema over the logical database schema (Relational database). It allows us to eradicate the O-R mismatch between RDBMS and the application logic which is common in data driven applications. (O-R impedance mismatch; (Details can be found here)). It was introduced with .Net Framework 3.5 Sp1 and extensively improved in .Net 4.0.

Jump Start To Entity Framework


In the following example I am going to use Nortwind Database (SQL CE). Northwind is a Microsoft sample database for customers and order management. (NorthWind Schema , NorthWind Database SQLCE) . Let's add the Northwind database to our project (Refer My post to add a 1. SQLCE database to VS). Then add Entity Data Model to the project. Let's name the Entity Model as 2. "NWModel".

3.

On click of Add it will guide us through a wizard and follow the steps by

selecting Northwind database.

4.

When click on finish VS will create the Entity for us. Also will add a reference

to System.Data.Entity.

To check the Field to property mapping, select Customer entity in data model and on right click we will find Table Mapping

5.

. You will find the Scalee Fields of RDBMS to property mapping.

6.

We Also check the App.config file; it will add a line for connection string.

7.

Now to check with the business entities lets select

in

the solution explorer and click on View the class diagram.

So Except NWEntity all other Business Entities are inherited from Entity Object for easier management and coordination among themselves.

8.

Let's go to the code and check how it will work to restive data. NwEntity is a

wrapper around the entities and can be used to retrieve data related to entities. Have a look at the NwEntity Class bellow.

9. So In our current application we need to load all the customers and orders on their respective load click. And we can do that with a very small piece of code as below. Code Snippet

1.
2.

private void btnLoadCustomers_Click(object sender, RoutedEventArgs e) { NWEntity objContext = new NWEntity(); var customers= objContext.Customers.ToList(); lstData.ItemsSource = (from c in customers select c.Company_Name); } private void btnLoadOrders_Click(object sender, RoutedEventArgs e) { NWEntity objContext = new NWEntity(); var orders = objContext.Orders.ToList(); lstData.ItemsSource = (from o in orders select o.Order_ID); }

3. 4. 5.
6.

7.
8.

9. 10. 11.
12. 13.

This is how Entity Framework eases the enterprise application development.

Windows application for database information


This example deals with displaying databases installed on the current computer, the tables of the selected database and the data of the selected table. For this 2 comboboxes and one datagridview has been taken in a windows application. The queries that have been used are as follows. 1. select name from sysdatabases - It displays databases installed on the current server. 2. select table_name from information_schema.tables where table_type='base table' and table_catalog=@a" It displays tables of the selected database. The tables displayed are user-defined, but for the system defined databases, some system-defined tables are also displayed. 3. To display the data of the selected tables, the appropriate query has been written.

Code of Form1.cs file using using using using using using using using System; System.Collections.Generic; System.ComponentModel; System.Data; System.Drawing; System.Linq; System.Text; System.Windows.Forms;

using System.Data.SqlClient; namespace windowsdata { public partial class Form1 : Form { SqlConnection cn; SqlCommand cmd; public Form1() { InitializeComponent(); } private voidForm1_Load(object sender, EventArgs e) { //all the databases on the server cn = new SqlConnection("server=.;uid=sa;pwd=1234;database=master"); cmd = new SqlCommand("select name from sysdatabases", cn); cn.Open(); SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read() == true) { comboBox1.Items.Add(dr[0].ToString()); } dr.Close(); cn.Close(); } private voidcomboBox1_SelectedIndexChanged(object sender, EventArgs e) { //tables of the selected database comboBox2.Text = ""; //clear the combobox of earlier data if (comboBox2.Items.Count != 0) { comboBox2.Items.Clear(); } //clear the datagridview of earlier data dataGridView1.DataSource = null; string s = comboBox1.SelectedItem.ToString(); cn = new SqlConnection("server=.;uid=sa;pwd=1234;database="+s); cmd = newSqlCommand("select table_name from information_schema.tables where table_type='base table' and table_catalog=@a", cn); cmd.Parameters.AddWithValue("@a", s); cn.Open(); SqlDataReader dr = cmd.ExecuteReader(); while (dr.Read() == true) { comboBox2.Items.Add(dr[0].ToString()); } dr.Close(); cn.Close(); } private voidcomboBox2_SelectedIndexChanged(object sender, EventArgs e) { //data of the selected table string s = comboBox2.SelectedItem.ToString(); SqlDataAdapter da = new SqlDataAdapter("select * from" + " " + s, cn); DataTable dt = new DataTable();

da.Fill(dt); dataGridView1.DataSource = dt; } } } The snapshot of the application is as follows.

All the best.

View database structure using C#


Introduction: This article describes an easy approach to examining all of the tables, views, and columns in a database, the article is written to describe an example application that may be used to connect to a database (Oracle, SQL Server, or MS Access), view that database's tables and views, and drill down into each table or view to generate a list of all of its contained columns. Further, the application will allow the user to examine the definition associated with each column (e.g., its data type, caption, default value, etc.) through a context menu option. The application does not serve any particular purpose and has only a few key methods associated with it. While the application does not perform any sort of useful task, the application could be used to form the basis for some useful tool, such as one that would

map the fields in one database table to the fields in another database table, or it could be used as the basis for a tool that allowed a user to formulate an ad hoc query using a developer defined query builder.

Figure 1: The demonstration application running

Figure 2: Pulling up information on a specific field Getting Started: In order to get started, unzip the included project and open the solution in the Visual Studio 2005 environment. In the solution explorer, you should note three significant files: frmDataDisplay.cs: Containing the main application and most of the code. frmConnect.cs: Containing a dialog used to connect to a database.

Application Properties: The application properties are used to store elements of the connection string as well as the connection string itself. In the project, open up the properties and select the settings tab to see the collection of properties used in this application. The scope of each property is set to "User" which will allow application users to set and save the properties between uses of the application. Each value is set to temp initially. The property names describe the purpose of each specific property; for example "ConnString", as you can probably guess, is used to hold the connection string property.

Figure 3: Application Properties Connection Dialog. The connection dialog is contained in frmConnect.cs; this dialog is used to capture the variables necessary to create a viable connection to an Oracle, SQL Server, or MS Access database. The dialog contains a tabbed pane with three panels, one for each connection type. Each panel contains all of the controls necessary to generate a connection. The user may test the connections from this dialog, and once the user accepts the dialog, the connection information will be persisted and made available to the application.

Figure 4: Connection Dialog with SQL Server Options Displayed The code is pretty simple, if you'd care to open the code view up in the IDE you will see that the code file begins as follows: using using using using using using using using using System; System.Collections; System.Configuration; System.ComponentModel; System.Data; System.Data.OleDb; System.Drawing; System.Text; System.Windows.Forms;

The class begins with the import of the required libraries; most notably the System.Data and System.Data.OleDb libraries are required to interact with the three database types used by the application (Oracle, Access, and SQL Server). Following the imports, the namespace and class are defined and a default constructor added. namespace DBSpy { public partial class frmConnect : Form

{ /// <summary> /// Default constructor /// </summary> public frmConnect() { InitializeComponent(); } Next up is the button click event handler for the button used to save a defined connection to an Oracle database as property settings made available across the application. The handler saves all of the user defined elements of the connection string as well as the formatted connection string itself and also tests the connection string to make sure that it works. The code is annotated to describe what is happening in each section of the code. /// <summary> /// Store the Oracle settings and test the connection /// string /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOracleOK_Click(object sender, EventArgs e) { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MyOracle"; Properties.Settings.Default.CurrentDatabaseType = "Oracle"; // Set the actual connection string properties into // the application settings Properties.Settings.Default.ProviderString = txtOracleProvider.Text; Properties.Settings.Default.Password = txtOraclePassword.Text; Properties.Settings.Default.UserID = txtOracleUserID.Text; Properties.Settings.Default.ServerName = txtOracleDBname.Text; // Set the connection string Properties.Settings.Default.ConnString = "Provider=" +Properties.Settings.Default.ProviderString + ";Password=" + Settings.Default.Password + ";User ID="+Properties.Settings.Default.UserID + ";Data Source=" + Properties.Settings .Default.ServerName; // Save the property settings Properties.Settings.Default.Save(); //Test Connection if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // test with an open attempt conn.Open(); this.Dispose(); }

catch (Exception ex) { // if the connection fails, inform the user // so they can fix the properties MessageBox.Show(ex.Message, "Connection Error"); } } } }

The next section of the code is used to handle the Oracle connection string test; even though attempts to save the connection properties also tests the connection, this method is made available to allow the user to test a connection and view whether or not the connection string passes. Again, the code is annotated to describe each section of the code.
/// <summary> /// Test the Oracle Connection String /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOracleTest_Click(object sender, EventArgs e) { try { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MyOracle"; Properties.Settings.Default.CurrentDatabaseType = "Oracle"; // Set the actual connection string properties into // the application settings Properties.Settings.Default.ProviderString = txtOracleProvider.Text; Properties.Settings.Default.Password = txtOraclePassword.Text; Properties.Settings.Default.UserID = txtOracleUserID.Text; Properties.Settings.Default.ServerName = txtOracleDBname.Text; // Set the connection string Properties.Settings.Default.ConnString = "Provider="+ Properties.Settings.Default.ProviderString + ";Password=" +Properties .Settings.Default.Password + ";User ID="+ Properties.Settings.Default.UserID + ";Data Source=" + Properties.Settings.Default.ServerName; // Save the property settings Properties.Settings.Default.Save(); } catch (Exception ex) { MessageBox.Show(ex.Message, "Error saving connection informaiton"); } //Test Connection if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) {

try { // test the connection with an open attempt conn.Open(); MessageBox.Show("Connection attempt successful.","Connection Test"); } catch (Exception ex) { // inform the user if the connection fails MessageBox.Show(ex.Message, "Connection Error"); } } } }

The next method is merely used to close the form if the user decides to cancel the operation.
/// <summary> /// Close the form /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnOracleCancel_Click(object sender, EventArgs e) { this.Dispose(); }

The next bit of code handles the check changed event for the integrated security check box control found on the SQL Server tab. If the control is checked, the user name and password are not used and the connection string will be formatted to use integrated security.
/// <summary> /// SQL Server /// Configure for the use of integrated /// security /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void cbxIntegratedSecurity_CheckedChanged(object sender, EventArgs e) { // if the user has checked the SQL Server connection // option to use integrated security, configure the //user ID and password controls accordingly if (cbxIntegratedSecurity.Checked == true) { txtSqlServerUserID.Text = string.Empty; txtSqlServerPassword.Text = string.Empty; txtSqlServerUserID.Enabled = false; txtSqlServerPassword.Enabled = false; } else { txtSqlServerUserID.Enabled = true; txtSqlServerPassword.Enabled = true;

} }

The next event handler closes the form if the user decides to cancel the operation.
/// <summary> /// Close the form /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSQLserverCancel_Click(object sender, EventArgs e) { this.Dispose(); }

The next section of code is used to test the SQL Server connection string; it functions much the same as does the Oracle connection test with the only exception being that it formats the connection string differently based upon the user's selection of the Use Integrated Security check box control.
/// <summary> /// Test the SQL Server connection string /// based upon the user supplied settings /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnSqlServerTest_Click(object sender, EventArgs e) { try { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MySqlServer"; Properties.Settings.Default.CurrentDatabaseType = "SqlServer"; // Set the properties for the connection string Properties.Settings.Default.ProviderString = txtSqlServerProvider.Text; Properties.Settings.Default.Password = txtSqlServerPassword.Text; Properties.Settings.Default.UserID = txtSqlServerUserID.Text; Properties.Settings.Default.ServerName = txtSqlServerDBName.Text; Properties.Settings.Default.InitialCatalog = txtSqlServerInitialCat.Text; // configure the connection string based upon the use // of integrated security if (cbxIntegratedSecurity.Checked == true) { Properties.Settings.Default.ConnString = "Provider=" + Properties.Settings.Default.ProviderString + ";Data Source=" + Properties.Settings.Default.ServerName + ";Initial Catalog=" + Properties.Settings.Default.InitialCatalog + ";Integrated Security=SSPI;"; } else {

Properties.Settings.Default.ConnString = "Provider=" +Properties.Settings.Default.ProviderString + ";Password="+Properties.Settings.Default.Password+ ";User ID=" + Properties.Settings.Default.UserID + ";Data Source=" +Properties.Settings.Default.ServerName + ";Initial Catalog=" + Properties.Settings.Default.InitialCatalog; } // Save the property settings Properties.Settings.Default.Save(); } catch (Exception ex) { // inform the user if the connection was not saved MessageBox.Show(ex.Message, "Error saving connection information"); } //Test Connection if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnectionProperties.Settings.Default.ConnString)) { try { // test the connection with an open attempt conn.Open(); MessageBox.Show("Connection Attempt Successful.", "Connection Test"); } catch (Exception ex) { // inform the user if the connection test failed MessageBox.Show(ex.Message, "Connection Test"); } } } }

The following event handler sets the connection string and tests the SQL Server connection as defined by the user's entries into the form.
private void btnSqlServerOK_Click(object sender, EventArgs e) { try { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MySqlServer"; Properties.Settings.Default.CurrentDatabaseType = "SqlServer"; // Set the properties for the connection Properties.Settings.Default.ProviderString = txtSqlServerProvider.Text; Properties.Settings.Default.Password = txtSqlServerPassword.Text; Properties.Settings.Default.UserID = txtSqlServerUserID.Text; Properties.Settings.Default.ServerName = txtSqlServerDBName.Text; Properties.Settings.Default.InitialCatalog = txtSqlServerInitialCat.Text;

// configure the connection string based upon // the use of integrated security if (cbxIntegratedSecurity.Checked == true) { Properties.Settings.Default.ConnString = "Provider=" +Properties.Settings.Default.ProviderString +";Data Source=" + Properties. Settings. Default.ServerName +";Initial Catalog=" +Properties.Settings.Default.InitialCatalog +"; Integrated Security=SSPI;"; } else { Properties.Settings.Default.ConnString = "Provider=" + Properties .Settings.Default.ProviderString Password= "+ Properties.Settings.Default.Password + ";User ID=" + Properties.Settings.Default.UserID +";Data Source=" + Properties.Settings.Default.ServerName + ";Initial Catalog=" +Properties.Settings.Default.InitialCatalog; } // Save the property settings Properties.Settings.Default.Save(); } catch (Exception ex) { // inform the user if the connection information was not // saved MessageBox.Show(ex.Message, "Error saving connection information."); } //Test Connection if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // test the connection with an open attempt conn.Open(); this.Dispose(); } catch (Exception ex) { // inform the user if the connection was not saved MessageBox.Show(ex.Message, "Connection Test"); } } } }

The next event handler closes the form if the user decides to cancel the operation.
/// /// /// /// <summary> Close the form </summary> <param name="sender"></param>

/// <param name="e"></param> private void btnAccessCancel_Click(object sender, EventArgs e) { this.Dispose(); }

This event handler is used to open an open file dialog used to allow the user to navigate to and select an Access database.
/// <summary> /// Browse for an access database /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnBrowse_Click(object sender, EventArgs e) { OpenFileDialog openFile = new OpenFileDialog(); openFile.Title = "MS Access Database"; openFile.DefaultExt = "mdb"; openFile.Filter = "Access Database (*.mdb)|*mdb"; openFile.ShowDialog(); txtAccessDBname.Text = openFile.FileName; }

The next bit of code is used to test a connection to an Access database.


/// <summary> /// Test an MS Access database connection /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAccessTest_Click(object sender, EventArgs e) { try { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MyAccess"; Properties.Settings.Default.CurrentDatabaseType = "Access"; // Set the access database connection properties Properties.Settings.Default.ProviderString = txtAccessProvider.Text; Properties.Settings.Default.Password = txtAccessPassword.Text; Properties.Settings.Default.UserID = txtAccessUserID.Text; Properties.Settings.Default.ServerName = txtAccessDBname.Text; // Set the access database connection string Properties.Settings.Default.ConnString = "Provider=" + Properties.Settings.Default.ProviderString +";Password="+ Properties.Settings.Default.Password + ";User ID=" +Properties.Settings.Default.UserID +";Data Source=" + Properties.Settings.Default.ServerName; // Save the properties Properties.Settings.Default.Save(); }

catch (Exception ex) { // inform the user if the connection could not be saved MessageBox.Show(ex.Message, "Error saving connection information."); } //Test Connection if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // test the connection with an open attempt conn.Open(); MessageBox.Show("Access connection test successful","Connection Test"); } catch (Exception ex) { // inform the user if the connection failed MessageBox.Show(ex.Message, "Connection Error"); } } } }

The next event handler is used to persist and test a connection string for an MS Access database.
/// <summary> /// Persist and test an Access database connection /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnAccessOK_Click(object sender, EventArgs e) { try { // Future use; if a current data model and database // type need to be identified and saved with the connect // string to identify its purpose Properties.Settings.Default.CurrentDataModel = "MyAccess"; Properties.Settings.Default.CurrentDatabaseType = "Access"; // Set the access database connection properties Properties.Settings.Default.ProviderString = txtAccessProvider.Text; Properties.Settings.Default.Password = txtAccessPassword.Text; Properties.Settings.Default.UserID = txtAccessUserID.Text; Properties.Settings.Default.ServerName = txtAccessDBname.Text; // Set the access database connection string Properties.Settings.Default.ConnString = "Provider=" + Properties.Settings.Default.ProviderString +";Password= "+Properties.Settings.Default.Password+";User ID=" + Properties.Settings.Default.UserID + ";Data Source=" +Properties.Settings.Default.ServerName;

// Save the properties Properties.Settings.Default.Save(); } catch (Exception ex) { // Inform the user if the connection was not saved MessageBox.Show(ex.Message, "Error saving connection information."); }

//Test Connection
if (Properties.Settings.Default.ConnString != string.Empty) { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // test the database connection string with an open // attempt conn.Open(); this.Dispose(); } catch (Exception ex) { // inform the user if the connection failed MessageBox.Show(ex.Message, "Connection Error"); } } } } } }

The Data Display Form The main application is contained in the frmDataDisplay.cs class. This form is used to gain access to the connection dialog, and to load the database information into the form's controls. The form is structured with a menu at the top; this menu contains the options to exit the application, to create a new connection, to view the current connection, and to load the schema information for the current database associated with the connection. In the main area of the form, there are three group boxes, one contains a list box control used to display the tables contained in the current database, one contains a list box control used to display the views contained in the current database, and one contains a list box used to display the columns contained in any view or table selected from the table or view list box controls.

Figure 5: The Main Form with an SQL Server Connection Active The class starts out with the following code used to import the required libraries:
using using using using using using using using using System; System.Collections; System.Configuration; System.ComponentModel; System.Data; System.Data.OleDb; System.Drawing; System.Text; System.Windows.Forms;

The next section of code declares the namespace, some local variables, and the default constructor. The array lists are used to contain the views and tables displayed on this form.
namespace DBSpy { public partial class frmDataDisplay : Form { #region Declarations public string mSelectedTable; private bool mTableSelected; ArrayList arrViews; ArrayList arrTables; #endregion /// <summary> /// default constructor /// </summary>

public frmDataDisplay() { InitializeComponent(); }

The next section of code defines a method used to capture and store the table and view names for the database identified by the connection string. The schema is stored in a data table populated with the results of calling the connection's GetOleDbSchemaTable method. This method is called twice; once to obtain the list of views and once to obtain the list of tables; these items are then added to new instances of the array lists used to hold the view and table lists. The code is annotated and should be pretty straight forward.
/// <summary> /// Populate to arrays with list of all of the tables and views used /// in the database defined by the current connection string /// </summary> public void StoreTableAndViewNames() { // temporary holder for the schema information for the current // database connection DataTable SchemaTable; // used to hold a list of views and tables arrViews = new ArrayList(); arrTables = new ArrayList(); // clean up the menu so the menu item does not // hang while this function executes this.Refresh(); // make sure we have a connection if (Properties.Settings.Default.ConnString != string.Empty) { // start up the connection using the current connection // string using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // open the connection to the database conn.Open(); // Get the Tables SchemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null,TABLE} // Store the table names in the class scoped array // list of table names for (int i = 0; i < SchemaTable.Rows.Count; i++) { arrTables.Add(SchemaTable.Rows[i]. ItemArray[2].ToString()); }

// Get the Views SchemaTable = conn.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, new Object[] { null, null, null,"VIEW" }); // Store the view names in the class scoped array // list of view names for (int i = 0; i < SchemaTable.Rows.Count; i++) { arrViews.Add(SchemaTable.Rows[i]. ItemArray[2].ToString()); } } catch (Exception ex) { // break and notify if the connection fails MessageBox.Show(ex.Message, "Connection Error"); } } } }

The next method is used to close the main form and terminate the application.
/// <summary> /// Close the form /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void CloseToolStripMenuItem_Click(object sender, EventArgs e) { // dispose of this form this.Dispose(); }

The next method is used to create an instance of the connection form. Once displayed, the user may define a new connection string.
/// <summary> /// Open a new connection to a database - present the connection /// string builder /// form so the user can define a connection /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void OpenANewConnectionToolStripMenuItem_Click(object sender, EventArgs e) { // open an instance the connect form so the user // can define a new connection frmConnect f = new frmConnect(); f.Show(); }

This method is used to display the value stored for the connection string in the application's settings

/// <summary> /// Display the current connection string to the user /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ViewCurrentConnectionToolStripMenuItem_Click(object sender, EventArgs e) { // display the current connection string MessageBox.Show(Properties.Settings.Default.ConnString, "Current Connection"); }

Based upon the current connection string, this method will recover the tables and views for the current database connection and will display those items in the form's table and view list view controls.
/// <summary> /// Get and display the current tables and views contained in the /// database /// pointed to by the connection string /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void LoadDataForCurrentConnectionToolStripMenuItem_Click(object sender, EventArgs e) { // get tables and views StoreTableAndViewNames(); // clear internal lists lstTables.Items.Clear(); lstViews.Items.Clear(); // update the lists from the arrays holding the // tables and views lstTables.Items.AddRange(arrTables.ToArray()); lstViews.Items.AddRange(arrViews.ToArray()); }

The next method will display the list of columns displayed for the last selected table.
private void lstTables_SelectedIndexChanged(object sender, EventArgs e) { mTableSelected = true; string tblName; try { tblName = lstTables.SelectedItem.ToString(); } catch { return; } // make sure we have a connection

if (Properties.Settings.Default.ConnString != string.Empty) { // start up the connection using the current connection // string using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { try { // open the connection to the database conn.Open(); lstFields.Items.Clear(); DataTable dtField =conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[]{null,null,blName}); foreach (DataRow dr in dtField.Rows) { lstFields.Items.Add(dr["COLUMN_NAME"].ToString()); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Connection Error"); } } } else { MessageBox.Show("There is no connection string current defined.", "Connection String"); } }

The next method will display the list of columns displayed for the last selected view.
private void lstViews_SelectedIndexChanged(object sender, EventArgs e) { mTableSelected = false; string tblName; try { tblName = lstViews.SelectedItem.ToString(); } catch { return; } // make sure we have a connection if (Properties.Settings.Default.ConnString != string.Empty) { // start up the connection using the current connection // string using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) {

try { // open the connection to the database conn.Open(); lstFields.Items.Clear(); // get the schema table DataTable dtField =conn.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, new object[]{null, null, tblName}); // read the column names into the fields list foreach (DataRow dr in dtField.Rows) { lstFields.Items.Add(dr["COLUMN_NAME"].ToString()); } } catch (Exception ex) { MessageBox.Show(ex.Message, "Connection Error"); } } } else { MessageBox.Show("There is no connection string current defined.", "Connection String"); } }

This method will display the field information associated with the last selected column for the last selected view or table.
/// <summary> /// Collect and display the field information for a selected column /// name /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void GetFieldInformationToolStripMenuItem_Click(object sender, EventArgs e) { try { using (OleDbConnection conn = new OleDbConnection(Properties.Settings.Default.ConnString)) { string sSql = string.Empty; if (mTableSelected == true) { sSql = "SELECT [" + lstFields.SelectedItem.ToString().Trim() + "] FROM ["+ lstTables.SelectedItem.ToString ().Trim()+ "]"; } else {

sSql = "SELECT [" + lstFields.SelectedItem.ToString().Trim() + "] FROM [" + lstViews.SelectedItem.ToString.Trim () + "]"; } OleDbCommand cmd = new OleDbCommand(sSql, conn); conn.Open(); OleDbDataReader rdr = cmd.ExecuteReader(CommandBehavior.KeyInfo); DataTable schemaTable = rdr.GetSchemaTable(); StringBuilder sb = new StringBuilder(); foreach (DataRow myField in schemaTable.Rows) { foreach (DataColumn myProperty in schemaTable.Columns) { sb.Append(myProperty.ColumnName + " = " + myField[myProperty].ToString() +Environment.NewLine); } // report MessageBox.Show(sb.ToString(), "Field Information"); // burn the reader rdr.Close(); // exit return; } } } catch { MessageBox.Show("Unable to attach to this table with current user; check database security permissions.", "Field information"); } } } }

Summary: This application is intended to demonstrate one approach to building an application capable of viewing the contents of a database dynamically and based strictly upon making a connection to either an MS Access, Oracle, or SQL Server database. It is not the only way to accomplish this task, it is just one way to do it. You can easily modify the approach to use other connection types, or to add new connection types, and you can modify the application to display information that I did not address in this demonstration.

Inserting images into MS Access file using OLEDB


Objective: To insert images into m.s.access file and also to perform search, update and delete operations. Design:

Design the form as above with a OpenFileDialog contol, 3 Labels, 3 TextBoxes, 11 buttons. PictureBox1 Properties: BorderStyle=Fixed3D; SizeMode=StrechImage Note that OpenFileDialog control appears below the form(not on the form), which can be used for browsing an image. Introduction: Inorder to use OleDb Connection include the namespace: 'using System.Data.OleDb' For accesing records from M.S.Access-2003 file we use 'Jet' driver, And for accesing records from M.S.Access-2007 file we use 'Ace' driver. As we want to insert images into the msaccess, first we have to create a table in the m.s.access file, we can use the data type 'ole object' for storing the image. In this application, we will search a record by taking input from the InputBox. For this we have to add reference to Microsoft.VisualBasic. Adding a Reference: Goto Project Menu->Add Reference -> select 'Microsoft.VisualBasic' from .NET tab. Inorder to use this we have to include the namespace: 'using Microsoft.VisualBasic' Converting image into binary data:

We can't store an image directly into the database. For this we have two solutions: 1. To store the location of the image in the database 2. Converting the image into binary data and insert that binary data into database and convert that back to image while retrieving the records. If we store the location of an image in the database, and suppose if that image is deleted or moved from that location, we will face problems while retrieving the records. So it is better to convert image into binary data and insert that binary data into database and convert that back to image while retrieving records. We can convert an image into binary data using 1. FileStream (or) 2. MemoryStream 1. FileStream uses file location to convert an image into binary data which we may/may not provide during updation of a record. Ex: FileStream fs = new FileStream(openFileDialog1.FileName,FileMode.Open, FileAccess.Read); byte[] photo_aray = new byte[fs.Length]; fs.Read(photo_aray, 0, photo_aray.Length); 2. So it is better to use MemoryStream which uses image in the PictureBox to convert an image into binary data. Ex: MemoryStream ms = newMemoryStream(); pictureBox1.Image.Save(ms, ImageFormat.Jpeg); byte[] photo_aray = new byte[ms.Length]; ms.Position = 0; ms.Read(photo_aray, 0, photo_aray.Length); Inorder to use FileStream or MemoryStream we have to include the namespace: 'using System.IO'. OpenFileDialog Control: We use OpenFileDialog control inorder to browse for the images (photos) to insert into the record. Creating a primary key in the dataTable: In this app. we use Find() method to search a record, which requires details of primarykey column for database tables this provided using statement: adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey But as we don't have any primarykey column in M.S.Access table, we have to create a primary key column in datatable. Eg: ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true); Code: using System;

using using using using using using using

System.Data; System.Drawing; System.Drawing.Imaging; System.Data.OleDb; System.Windows.Forms; System.IO; Microsoft.VisualBasic;

namespace access_img { public partial class Form1 : Form { public Form1() { InitializeComponent(); } OleDbConnection con; OleDbCommand cmd; OleDbDataAdapter adapter; DataSet ds; int rno=0; MemoryStream ms; byte[] photo_aray; private voidForm1_Load(object sender, EventArgs e) { con = new OleDbConnection(@" provider=microsoft.ace.oledb.12.0; data source=e:\prash\stud.accdb; persist securityiInfo=false");//stud.accdb->access07 filename //con = new OleDbConnection(@" provider=microsoft.jet.oledb.4.0; data source=e:\prash\stud.mdb");//stud.mdb->access03 filename loaddata(); showdata(); } void loaddata() { adapter = new OleDbDataAdapter("select * from student", con); ds = new DataSet();//student-> table name in stud.accdb/stud.mdb file adapter.Fill(ds, "student"); ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true);//creating primary key for Tables[0] in dataset } void showdata() { textBox1.Text = ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text = ds.Tables[0].Rows[rno][1].ToString(); textBox3.Text = ds.Tables[0].Rows[rno][2].ToString(); pictureBox1.Image = null; if (ds.Tables[0].Rows[rno][3] != System.DBNull.Value) { photo_aray = (byte[])ds.Tables[0].Rows[rno][3]; MemoryStream ms = new MemoryStream(photo_aray); pictureBox1.Image = Image.FromStream(ms); } } private voidbtnBrowse_Click(object sender, EventArgs e) {

openFileDialog1.Filter = "jpeg|*.jpg|bmp|*.bmp|all files|*.*"; DialogResult res = openFileDialog1.ShowDialog(); if (res == DialogResult.OK) { pictureBox1.Image = Image.FromFile(openFileDialog1.FileName); } } private voidbtnInsert_Click(object sender, EventArgs e) { cmd = new OleDbCommand("insert into student(sno,sname,course,photo) values(" + textBox1.Text + ",'"+ textBox2.Text + "','" + textBox3.Text + "',@photo)", con); conv_photo(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("record inserted"); loaddata(); rno++; } else MessageBox.Show("insertion failed"); } void conv_photo() { //converting photo to binary data if (pictureBox1.Image != null) { //using MemoryStream: ms = new MemoryStream(); pictureBox1.Image.Save(ms, ImageFormat.Jpeg); byte[] photo_aray = new byte[ms.Length]; ms.Position = 0; ms.Read(photo_aray, 0, photo_aray.Length); cmd.Parameters.AddWithValue("@photo", photo_aray); } } private voidbtnSearch_Click(object sender, EventArgs e) { try { int n = Convert.ToInt32(Interaction.InputBox("Enter sno:", "Search", "20", 100, 100)); DataRow drow; drow = ds.Tables[0].Rows.Find(n); if (drow != null) { rno = ds.Tables[0].Rows.IndexOf(drow); textBox1.Text = drow[0].ToString(); textBox2.Text = drow[1].ToString(); textBox3.Text = drow[2].ToString(); pictureBox1.Image = null; if(drow[3] != System.DBNull.Value) { photo_aray = (byte[])drow[3]; MemoryStream ms = new MemoryStream(photo_aray); pictureBox1.Image = Image.FromStream(ms);

} } else MessageBox.Show("Record Not Found"); } catch { MessageBox.Show("Invalid Input"); } } private voidbtnUpdate_Click(object sender, EventArgs e) { cmd = new OleDbCommand("update student set sname='" + textBox2.Text + "', course='" + textBox3.Text + "', photo=@photo where sno=" + textBox1.Text, con); conv_photo(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Updated"); loaddata(); } else MessageBox.Show("Updation Failed"); } private voidbtnDelete_Click(object sender, EventArgs e) { cmd = new OleDbCommand("delete from student where sno=" + textBox1.Text, con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Deleted"); loaddata(); rno = 0; showdata(); } else MessageBox.Show("Deletion failed"); } private voidbtnFirst_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = 0; showdata(); MessageBox.Show("First Record"); } else MessageBox.Show("no records"); } private voidbtnPrevious_Click(object sender, EventArgs e) { if(ds.Tables[0].Rows.Count > 0) {

if (rno > 0) { rno--; showdata(); } else MessageBox.Show("First Record"); } else MessageBox.Show("no records"); } private voidbtnNext_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { if (rno < ds.Tables[0].Rows.Count - 1) { rno++; showdata(); } else MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private voidbtnLast_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = ds.Tables[0].Rows.Count - 1; showdata(); MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private voidbtnClear_Click(object sender, EventArgs e) { textBox1.Text = textBox2.Text = textBox3.Text = ""; } private voidbtnExit_Click(object sender, EventArgs e) { this.Close(); } } } Note: 'stud.accdb' and 'stud.mdb' files are provided in access_img.zip file along with source code

Inserting & Retrieving records from MS Excel 2003 using OLEDB


Objective:

To develop a windows application using C#.Net to insert, search and update records from M.S.Excel-2003 file using OleDb Connection. Design:

Design the form as above with a DataGridView, 3 Labels, 3 TextBoxes and 9 buttons. Introduction: As we want to use OleDb Connection include the namespace: 'using System.Data.OleDb' For accesing records from M.S.Excel-2003 file we use 'Jet' driver. In this application, we will search a record by taking input from the InputBox. For this, we have to add a reference to Microsoft.VisualBasic. Adding Reference to Microsoft.VisualBasic: Goto Project Menu->Add Reference -> select 'Microsoft.VisualBasic' from .NET tab. In order to use this we have to include the namespace: 'using Microsoft.VisualBasic' Creating a primary key in the dataTable: In this app. we use Find() method to search a record, which requires details of primarykey column. For database tables this is provided using statement: adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey But since we don't have any primarykey column in M.S.Excel table, we have to create a primary key column in datatable. Eg:

ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true); Pointing to current record in dataTable: After searching for a record, we have to get the index of that record so that we can navigate the next and previous records. Eg: rno= ds.Tables[0].Rows.IndexOf(drow); Code: using using using using using System; System.Data; System.Data.OleDb; System.Windows.Forms; Microsoft.VisualBasic;

namespace xloledb03 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } OleDbConnection con; OleDbCommand cmd; OleDbDataAdapter da; DataSet ds; int rno = 0; private void Form1_Load(object sender, EventArgs e) { con = new OleDbConnection(@"Provider=Microsoft.Jet.Oledb.4.0;data source=E:\prash\xldb.xls;Extended Properties=""Excel 8.0;HDR=Yes;"" "); //xldb.xls ->MS.Excel-2003 file, hdr=yes-> 1st row is treated as header loaddata(); showdata(); } void loaddata() { da = new OleDbDataAdapter("select * from [student$]", con); //student-> sheet name in xldb.xls file, which should be specified as [student$] ds = new DataSet(); da.Fill(ds, "student"); ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true); //creating primary key in Tables["student"] of dataset(for using Find() method) dataGridView1.DataSource = ds.Tables[0]; } void showdata() { textBox1.Text = ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text = ds.Tables[0].Rows[rno][1].ToString(); textBox3.Text = ds.Tables[0].Rows[rno][2].ToString(); }

private void btnInsert_Click(object sender, EventArgs e) { cmd = new OleDbCommand("insert into [student$] values(" + textBox1.Text + ",' " + textBox2.Text + " ',' " + textBox3.Text + " ')", con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("record inserted"); loaddata(); } else MessageBox.Show("insertion failed"); } private void btnSearch_Click(object sender, EventArgs e) { int n = Convert.ToInt32(Interaction.InputBox("Enter sno:", "Search", "20", 200, 200)); DataRow drow = ds.Tables[0].Rows.Find(n); if (drow != null) { textBox1.Text = drow[0].ToString(); textBox2.Text = drow[1].ToString(); textBox3.Text = drow[2].ToString(); } else MessageBox.Show("Record not found"); } private void btnUpdate_Click(object sender, EventArgs e) { cmd = new OleDbCommand(" update [student$] set sname='" + textBox2.Text + "',course='" + textBox3.Text + "' where sno=" + textBox1.Text + " ", con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Updated"); loaddata(); } else MessageBox.Show("Update failed"); } private void btnFirst_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = 0; showdata(); MessageBox.Show("First Record"); } else MessageBox.Show("no records"); } private void btnPrevious_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0)

{ if (rno > 0) { rno--; showdata(); } else MessageBox.Show("First Record"); } else MessageBox.Show("no records"); } private void btnNext_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { if (rno < ds.Tables[0].Rows.Count - 1) { rno++; showdata(); } else MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private void btnLast_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = ds.Tables[0].Rows.Count - 1; showdata(); MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private void btnClear_Click(object sender, EventArgs e) { textBox1.Text = textBox2.Text = textBox3.Text = ""; } private void btnExit_Click(object sender, EventArgs e) { this.Close(); } } } Note: 'xldb.xls' file is provided in xloledb03.zip file along with source code.

Inserting & Retrieving records from MS Access 2007 using ODBC


Objective:

To develop a windows application for performing insert, search, update, delete operations & navigation of M.S.Access 2007 records using ODBC connection. Introduction: Create a table in M.S.Access 2007 file and populate it. In our application we use 'stud.accdb' (M.S.Access 2007) file, which consists of a 'student' table. (Note: 'stud.accdb' is placed in 'prash_access07.zip' along with source code) Creating and Configuring ODBC Data Source (DSN): Go to Start Menu -> Control Panel -> Administrative Tools -> Data Sources (ODBC)

Click on 'Add' button -> Select 'Microsoft Access Driver (*.mdb, *.accdb)' ->click on 'Finish' button.

Give a name to your Data Source Click on 'Select' button and select your M.S.Access 2007 file (*.accdb) -> OK -> OK

Your Data Source Name will be specified in 'ODBC Data Source Administrator' window ->Click on 'OK' button. Thus, your Data Source (dsn) is configured. Design:

Design the form as above with a DataGridView, 3 Labels, 3 TextBoxes, 10 buttons. Introduction to Code: As we want to use ODBC Connection include the namespace: 'using System.Data.ODBC' For accesing records from M.S.Access-2003 file we use 'Jet' driver, But for accesing records from M.S.Access-2003 file we use 'Ace' driver. In this application, we will search a record by taking input from the InputBox. For this we have to add reference to Microsoft.VisualBasic. Adding a Reference: Goto Project Menu ->Add Reference -> select 'Microsoft.VisualBasic' from .NET tab. In order to use this we have to include the namespace: 'using Microsoft.VisualBasic' ODBC connection string: Syntax: OdbcConnection con = new OdbcConnection("dsn=<Data Source Name>");

Ex: OdbcConnection con = new OdbcConnection("dsn=myaccess07dsn "); You just need to specify the Data Source Name(dsn) in the Connection String, no need to specify the driver details and path of the file, your dsn will take care of it. Creating a primary key in the dataTable: In this app. we use Find() method to search a record, which requires details of primarykey column for database tables; this is provided using statement: adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey But as we don't have any primarykey column in M.S.Access table, we have to create a primary key column in datatable. Ex: ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0],true); Pointing to current record in dataTable: After searching a record, we have to get the index of that record so that we can show next and previous records when we press '>>'(next) and '<<'(previous) buttons.Ex: rno= ds.Tables[0].Rows.IndexOf(drow); Code: using using using using using System; System.Data; System.Windows.Forms; System.Data.Odbc; Microsoft.VisualBasic;

namespace prash_access07 { public partial class Form1 : Form { public Form1() { InitializeComponent(); } OdbcConnection con; OdbcCommand cmd; OdbcDataAdapter adapter; DataSet ds; int rno; private void Form1_Load(object sender, EventArgs e) { con = new OdbcConnection("dsn=myaccess07dsn"); //stud.accdb->access07 filename loaddata(); showdata(); } void loaddata() { adapter = new OdbcDataAdapter("select * from student", con);

ds = new DataSet();//student-> table name in stud.accdb file adapter.Fill(ds, "student"); ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true);//creating primary key for Tables[0] in dataset dataGridView1.DataSource = ds.Tables[0]; } void showdata() { textBox1.Text = ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text = ds.Tables[0].Rows[rno][1].ToString(); textBox3.Text = ds.Tables[0].Rows[rno][2].ToString(); } private void btnFirst_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = 0; showdata(); } else MessageBox.Show("no records"); } private void btnPrevious_Click(object sender, EventArgse) { if (ds.Tables[0].Rows.Count > 0) { if (rno > 0) { rno--; showdata(); } else MessageBox.Show("First Record"); } else MessageBox.Show("no records"); } private void btnNext_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { if (rno < ds.Tables[0].Rows.Count - 1) { rno++; showdata(); } else MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private void btnLast_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = ds.Tables[0].Rows.Count - 1;

showdata(); } else MessageBox.Show("no records"); } private void btnInsert_Click(object sender, EventArgs e) { cmd = new OdbcCommand("insert into student values("+ textBox1.Text + ",' " + textBox2.Text + " ',' " + textBox3.Text + " ')", con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("record inserted"); loaddata(); } else MessageBox.Show("insertion failed"); } private void btnSearch_Click(object sender, EventArgs e) { int n = Convert.ToInt32(Interaction.InputBox("Enter sno:", "Search", "20", 200, 200)); DataRow drow = ds.Tables[0].Rows.Find(n); if (drow != null) { rno = ds.Tables[0].Rows.IndexOf(drow); textBox1.Text = drow[0].ToString(); textBox2.Text = drow[1].ToString(); textBox3.Text = drow[2].ToString(); } else MessageBox.Show("Record not found"); } private void btnUpdate_Click(object sender, EventArgs e) { cmd = new OdbcCommand("update student set sname='" + textBox2.Text + "',course='" + textBox3.Text + "' where sno=" + textBox1.Text, con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Updated"); loaddata(); } else MessageBox.Show("Update failed"); } private void btnDelete_Click(object sender, EventArgs e) { cmd = new OdbcCommand("delete from student where sno=" + textBox1.Text, con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) {

MessageBox.Show("Record Deleted"); loaddata(); } else MessageBox.Show("Deletion failed"); } private void btnClear_Click(object sender, EventArgs e) { textBox1.Text = textBox2.Text = textBox3.Text = ""; } private void btnExit_Click(object sender, EventArgs e) { this.Close(); } } }

Creating & Retrieving records from M.S.Access2007 using Oledb in C#.net


Design:

Design the form as above with a DataGridView, 3 Labels, 3 TextBoxes, 10 buttons. Note: In order to perform operations on M.S.Access-2007 records, M.S.Office-2007 should be installed in your system. Introduction:

As we want to use OleDb Connection include the namespace: 'using System.Data.OleDb' For accesing records from M.S.Access-2003 file we use 'Jet' driver, But for accesing records from M.S.Access-2007 file we use 'Ace' driver. In this application, we will search a record by taking input from the InputBox. For this we have to add reference to Microsoft.VisualBasic. Adding a Reference: Goto Project Menu ->Add Reference -> select 'Microsoft.VisualBasic' from .NET tab. In order to use this we have to include the namespace: 'using Microsoft.VisualBasic' Creating a primary key in the dataTable: In this app. we use Find() method to search a record, which requires details of primarykey column for database tables; this is provided using statement: adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey But as we don't have any primarykey column in M.S.Access table, we have to create a primary key column in datatable. Eg: ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true); Pointing to current record in dataTable: After searching a record, we have to get the index of that record so that we can show next and previous records when we press '>>'(next) and '<<'(previous) buttons. Eg: rno= ds.Tables[0].Rows.IndexOf(drow); ------------Code: using using using using using System; System.Data; System.Windows.Forms; System.Data.OleDb; Microsoft.VisualBasic;

namespace prash_access07 { public partial class Form1 : Form { public Form1() {

InitializeComponent(); } OleDbConnection con; OleDbCommand cmd; OleDbDataAdapter adapter; DataSet ds; int rno; private void Form1_Load(object sender, EventArgs e) { con = new OleDbConnection(@" provider=Microsoft.ace.Oledb.12.0; data source=E:\prash\stud.accdb;Persist Security Info=False");//stud.accdb->access07 filename loaddata(); showdata(); } void loaddata() { adapter = new OleDbDataAdapter("select * from student", con); ds = new DataSet();//student-> table name in stud.accdb file adapter.Fill(ds, "student"); ds.Tables[0].Constraints.Add("pk_sno", ds.Tables[0].Columns[0], true);//creating primary key for Tables[0] in dataset dataGridView1.DataSource = ds.Tables[0]; } void showdata() { textBox1.Text = ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text = ds.Tables[0].Rows[rno][1].ToString(); textBox3.Text = ds.Tables[0].Rows[rno][2].ToString(); } private void btnFirst_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = 0; showdata(); } else MessageBox.Show("no records"); } private void btnPrevious_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { if (rno > 0) { rno--; showdata(); } else MessageBox.Show("First Record"); } else

MessageBox.Show("no records"); } private void btnNext_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { if (rno < ds.Tables[0].Rows.Count - 1) { rno++; showdata(); } else MessageBox.Show("Last Record"); } else MessageBox.Show("no records"); } private void btnLast_Click(object sender, EventArgs e) { if (ds.Tables[0].Rows.Count > 0) { rno = ds.Tables[0].Rows.Count - 1; showdata(); } else MessageBox.Show("no records"); } private void btnInsert_Click(object sender, EventArgs e) { cmd = new OleDbCommand("insert into student values(" + textBox1.Text + ",' " + textBox2.Text + " ',' " + textBox3.Text + " ')", con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("record inserted"); loaddata(); } else MessageBox.Show("insertion failed"); } private void btnSearch_Click(object sender, EventArgs e) { int n = Convert.ToInt32(Interaction.InputBox("Enter sno:", "Search", "20", 200, 200) ; DataRow drow = ds.Tables[0].Rows.Find(n); if (drow != null) { rno = ds.Tables[0].Rows.IndexOf(drow);

textBox1.Text = drow[0].ToString(); textBox2.Text = drow[1].ToString(); textBox3.Text = drow[2].ToString(); } else MessageBox.Show("Record not found"); } private void btnUpdate_Click(object sender, EventArgs e) { cmd = new OleDbCommand("update student set sname='" + textBox2.Text + "',course='" + textBox3.Text + "' where sno=" + textBox1.Text, con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Updated"); loaddata(); } else MessageBox.Show("Update failed"); } private void btnDelete_Click(object sender, EventArgs e) { cmd = new OleDbCommand("delete from student where sno=" + textBox1.Text, con); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Deleted"); loaddata(); } else MessageBox.Show("Deletion failed"); } private void btnClear_Click(object sender, EventArgs e) { textBox1.Text = textBox2.Text = textBox3.Text = ""; } private void btnExit_Click(object sender, EventArgs e) { this.Close(); } } }

Inserting & retrieving images from SQL Server database using stored procedures
Objective: To insert & retrieve images from SQL server database using stored procedures and also to perform insert, search, update and delete operations & navigation of records. Introduction: As we want to insert images into database using stored procedures, we have to create a table and stored procedures in the database. Query for creating table in our application: create table student(sno int primary key,sname varchar(50),course varchar(50),fee money,photo image) Stored procedures: create procedure get_student as select sno,sname, course, fee, photo from student ----------create procedure insert_student (@sno int, @sname varchar(50), @course varchar(50), @fee smallmoney,@photo image=null) as insert into student(sno, sname,course, fee, photo) values (@sno, @sname, @course, @fee, @photo) --------------create procedure update_student(@sno int, @sname varchar(50),@course varchar(50), @fee smallmoney,@photo image=null) as update student set sname=@sname, course=@course, fee=@fee, photo=@photo where sno=@sno -----------create procedure delete_student(@sno int=null) as if not(@sno=null) delete from student where sno=@sno --------------------------------------------Design:

Design the form as above with 1 PictureBox control, 1 OpenFileDialog control, 4 Labels, 4 TextBoxes and 11 Buttons. PictureBox1 Properties: BorderStyle=Fixed3D; SizeMode=StrechImage Note that OpenFileDialog control appears below the form (not on the form). Introduction to code: In order to communicate with SQL sever database, include the namespace using System.Data.SqlClient. In this application, we will search a record by taking input from the InputBox. For this we have to add reference to Microsoft.VisualBasic. Adding a Reference to 'Microsoft.VisualBasic': Goto Project Menu ->Add Reference -> select 'Microsoft.VisualBasic' from .NET tab. In order to use this reference we have to include the namespace: 'using Microsoft.VisualBasic' in the code. Converting image into binary data: We can't store an image directly into the database. For this we have two solutions: i) To store the location of the image in the database ii) Convert the image into binary data and insert that binary data into database and convert that back to image when retrieving the records. If we store the location of an image in the database, and suppose if that image is deleted or moved from that location, we will face problems while retrieving the records. So it is better to convert image into binary data and insert that binary data into database and convert that back to image while retrieving records. ->We can convert an image into binary data using 1. FileStream (or) 2. MemoryStream 1. FileStream uses file location to convert an image into binary data which we may/may not provide when updating a record.

Ex: FileStream fs = new FileStream(openFileDialog1.FileName, FileMode.Open,FileAccess.Read); byte[] photo_aray = new byte[fs.Length]; fs.Read(photo_aray, 0, photo_aray.Length); 2. So it is better to use MemoryStream which uses image in the PictureBox to convert an image into binary data. Ex: MemoryStream ms = new MemoryStream(); pictureBox1.Image.Save(ms, ImageFormat.Jpeg); byte[] photo_aray = new byte[ms.Length]; ms.Position = 0; ms.Read(photo_aray, 0, photo_aray.Length); ->In order to use FileStream or MemoryStream we have to include the namespace: 'using System.IO'. OpenFileDialog Control: We use OpenFileDialog control to browse for the images (photos) to insert into the record. Using DataAdapter with StoredProcedures: We can use command object to work with stored procedures by passing stored procedure name to command object and specifying CommandType as StoredProcedure Ex: cmd = new SqlCommand("get_student", con); cmd.CommandType = CommandType.StoredProcedure; DataAdapter can't interact directly with the stored procedures, but if we need to use DataAdapter while working with stored procedures, we can achieve this by passing the command object to the DataAdapter. Loading the constraint details into the dataTable: In this app. we use Find() method to search a record, which requires details of primarykey column, which can be provided using the statement: adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; Pointing to current record in dataTable: After searching a record, we have to get the index of that record so that we can show next and previous records when we press '>>'(next) and '<<'(previous) buttons. Ex: rno= ds.Tables[0].Rows.IndexOf(drow); Code:

using using using using using using using using

System; System.Windows.Forms; System.Data; System.Data.SqlClient; System.Drawing; System.Drawing.Imaging; System.IO; Microsoft.VisualBasic;

namespace inserting_imgs { public partial class Form1 : Form { public Form1() { InitializeComponent(); } SqlConnection con; SqlCommand cmd; SqlDataAdapter adapter; DataSet ds; int rno = 0; MemoryStream ms; byte[] photo_aray; private void Form1_Load(object sender, EventArgs e) { con = new SqlConnection("user id=sa;password=123;database=prash"); loaddata(); showdata(); } void loaddata() { cmd = new SqlCommand("get_student", con); cmd.CommandType = CommandType.StoredProcedure; adapter = new SqlDataAdapter(cmd); adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; ds = new DataSet(); adapter.Fill(ds, "student"); } void showdata() { if (ds.Tables[0].Rows.Count > 0) { textBox1.Text = ds.Tables[0].Rows[rno][0].ToString(); textBox2.Text = ds.Tables[0].Rows[rno][1].ToString(); textBox3.Text = ds.Tables[0].Rows[rno][2].ToString(); textBox4.Text = ds.Tables[0].Rows[rno][3].ToString(); pictureBox1.Image = null; if (ds.Tables[0].Rows[rno][4] != System.DBNull.Value) { photo_aray = (byte[])ds.Tables[0].Rows[rno][4]; MemoryStream ms = new MemoryStream(photo_aray); pictureBox1.Image = Image.FromStream(ms); } } else MessageBox.Show("No Records"); }

private void browse_Click(object sender, EventArgs e) { openFileDialog1.Filter = "jpeg|*.jpg|bmp|*.bmp|all files|*.*"; DialogResult res = openFileDialog1.ShowDialog(); if (res == DialogResult.OK) { pictureBox1.Image = Image.FromFile(openFileDialog1.FileName); } } private void clear_Click(object sender, EventArgs e) { textBox1.Text = textBox2.Text = textBox3.Text = textBox4.Text = ""; pictureBox1.Image = null; } private void insert_Click(object sender, EventArgs e) { cmd = new SqlCommand("insert_student", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@sno", textBox1.Text); cmd.Parameters.AddWithValue("@sname", textBox2.Text); cmd.Parameters.AddWithValue("@course", textBox3.Text); cmd.Parameters.AddWithValue("@fee", textBox4.Text); conv_photo(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("record inserted"); loaddata(); } else MessageBox.Show("insertion failed"); } void conv_photo() { //converting photo to binary data if (pictureBox1.Image != null) { ms = new MemoryStream(); pictureBox1.Image.Save(ms, ImageFormat.Jpeg); byte[] photo_aray = new byte[ms.Length]; ms.Position = 0; ms.Read(photo_aray, 0, photo_aray.Length); cmd.Parameters.AddWithValue("@photo", photo_aray); } } private void search_Click(object sender, EventArgs e) { try { int n = Convert.ToInt32(Interaction.InputBox("Enter sno:", "Search", "20", 100, 100)); DataRow drow; drow = ds.Tables[0].Rows.Find(n); if (drow != null) { rno = ds.Tables[0].Rows.IndexOf(drow);

textBox1.Text = drow[0].ToString(); textBox2.Text = drow[1].ToString(); textBox3.Text = drow[2].ToString(); textBox4.Text = drow[3].ToString(); pictureBox1.Image = null; if (drow[4] != System.DBNull.Value) { photo_aray = (byte[])drow[4]; MemoryStream ms = new MemoryStream(photo_aray); pictureBox1.Image = Image.FromStream(ms); } } else MessageBox.Show("Record Not Found"); } catch { MessageBox.Show("Invalid Input"); } } private void update_Click(object sender, EventArgs e) { cmd = new SqlCommand("update_student", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@sno", textBox1.Text); cmd.Parameters.AddWithValue("@sname", textBox2.Text); cmd.Parameters.AddWithValue("@course", textBox3.Text); cmd.Parameters.AddWithValue("@fee", textBox4.Text); conv_photo(); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Updated"); loaddata(); } else MessageBox.Show("Updation Failed"); } private void delete_Click(object sender, EventArgs e) { cmd = new SqlCommand("delete_student", con); cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.AddWithValue("@sno", textBox1.Text); con.Open(); int n = cmd.ExecuteNonQuery(); con.Close(); if (n > 0) { MessageBox.Show("Record Deleted"); loaddata(); rno = 0; showdata(); } else MessageBox.Show("Deletion Failed");

} private void first_Click(object sender, EventArgs e) { rno = 0; showdata(); MessageBox.Show("First record"); } private void previous_Click(object sender, EventArgs e) { if (rno > 0) { rno--; showdata(); } else MessageBox.Show("First record"); } private void next_Click(object sender, EventArgs e) { if (rno < ds.Tables[0].Rows.Count - 1) { rno++; showdata(); } else MessageBox.Show("Last record"); } private void last_Click(object sender, EventArgs e) { rno = ds.Tables[0].Rows.Count - 1; showdata(); MessageBox.Show("Last record"); } private void exit_Click(object sender, EventArgs e) { this.Close(); } } }

Using Dynamic Database Connections


The DataLinksClass class in the Microsoft OLE DB Service Component Library can be used to dynamically create or modify a connection string during execution. The DataLinksClass class will show a dialog similar to the one shown by the Server Explorer in Visual Studio. I am not aware of an equivalent for ADO or for .Net but the connection string created by the DataLinksClass class can be used in the .Net OLE DB classes. The DataLinksClass can be used to create a connection string for most databases, including Access and SQL Server. The following shows samples of the dialog box from the DataLinksClass.

To use the DataLinksClass class, you must have a reference to the "Microsoft OLE DB Service Component 1.0 Type Library". Use the COM tab of the dialog for adding references to a project to add the reference. You will also need to use the OleDbConnection class in the COM version of ADO so you will need to have a reference to the "Microsoft ActiveX Data Objects 6.0 Library", except the version (6.0) can probably be a different version. Creating a Connection String Creating a connection string can be as easy as: MSDASC.DataLinksClass dl = new MSDASC.DataLinksClass(); ADODB.Connection c = dl.PromptNew() as ADODB.Connection; if (c == null) ConnectionString = ""; else ConnectionString = c.ConnectionString; The DataLinksClass class can do all the prompting for a connection string. Modifying a Connection String Modifying a connection string can be as easy as: MSDASC.DataLinksClass dl = new MSDASC.DataLinksClass(); ADODB.Connection c = new ADODB.Connection(); c.ConnectionString = ConnectionString; Object o = c; if (!dl.PromptEdit(ref o)) ConnectionString = "";

else

ConnectionString = c.ConnectionString;

The DataLinksClass class can do all the prompting for a connection string. SQL Server Express If you are not familiar with the Express edition of SQL Server, then you might have difficulty figuring out what to use for the server name. In the Provider property page, select SQL Server Native Client. The default for the server name is "(local)\sqlexpress". Also, ensure that SQL Server Express is started; it appears to be installed by Visual Studio in a stopped state and it does not start on it's own. If no servers are listed when you click on the dropdown for the server names, then it is likely that SQL Server is not started. Also use Windows authentication. The following shows what works for me with the Express edition of SQL Server.

Final Comment There is not much relevant documentation so a lot of this is the result of guessing and such. I hope it works but I can't guarantee it. I have not explored the possibility of using the connection string with ADO .Net but it should be relatively easy to do.

A RoadMap For ADO.NET


In this article I would like to show the basic steps of using specific objects of Microsoft ADO .NET. Most of them are used in typical database application for example recording customer form or show the customer information on a datagrid. Let's think about a flowchart which shows the objects and operations, and the usage orderly.

Figure: Flowchart for choosing and using ADO .NET objects. Firstly, connection object must be specified. Connection object specifies the server, database and the authentication information. A typical declaration for SQL Server connection string is: Data Source = FARUK; Initial Catalog = FCELEKTRONIK; Integrated Security = true; In this declaration: SQL Server instance name: FARUK, Database name: FCELEKTRONIK Secondly, perform the data operations: In this stage we must decide how the data will be accessed. It can be direct or indirect. In other words "connected" or "disconnected".

DataSet objects are used generally in a disconnected style. A DataSet is a buffer which stores data just like a database that we navigate for data or processing data. For example create a dataset then run a SQL select statement against it. Fill the customer records to dataset then populate a datagrid from the dataset which is done by DataAdapter object. A typical example: [Visual C#] string conStr = @"Data Source=FARUK ;Initial Catalog=FCELEKTRONIK;Integrated Security=True"; string sql = "SELECT * FROM CUSTOMERS"; SqlConnection con = new SqlConnection(conStr); SqlCommand cmd = new SqlCommand(sql, con); SqlDataAdapter dataadapter = new SqlDataAdapter(cmd); DataSet ds = new DataSet(); con.Open(); dataadapter.Fill(ds, "CUSTOMERS"); con.Close(); dataGridView1.DataSource = ds.Tables[0].DefaultView; Note that the connection never opened and closed. Because this operations done by DataAdapter automatically. How about the connected style? Command objects are used generally in this style. Connection is opened then a SQL Operation is done directly. For example an INSERT INTO statement. These operations are directly made on the database; that is why they are called "direct". This means database is opened, operation is done and database is closed manually. Typical adding (insert): SqlConnection conn = new SqlConnection(); conn.ConnectionString = @"Data Source=FARUK; Initial Catalog=FCELEKTRONIK ;Integrated Security=True;"; // open connection try { conn.Open(); // command - insert SqlCommand cmd = new SqlCommand(); cmd.Connection = conn; cmd.CommandText = "INSERT INTO COSTOMERS (CODE, NAME, AMOUNT) " + "VALUES (@CODE, @NAME, @AMOUNT)"; cmd.Parameters.Add("@CODE", SqlDbType.VarChar, 10).Value = textBox1.Text; cmd.Parameters.Add("@NAME", SqlDbType.VarChar, 10).Value = textBox2.Text; cmd.Parameters.Add("@AMOUNT", SqlDbType.Decimal).Value = textBox3.Text; cmd.ExecuteNonQuery(); // run the command MessageBox.Show("FC- successful added!"); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally

{ conn.Close(); } In this example Parameters are used instead of real data or textboxes. Using parameters is the way of more secure data that will be added to database. How about the execution of a SELECT statement on a database or specifically reading data sequentially (read only)? This is generally done by the DataReader object. Typical example is (reading data and populating listbox): [Visual C#] SqlConnection con = new SqlConnection(); con.ConnectionString = @"Data Source=FARUK;Initial Catalog=FCELEKTRONIK;Integrated Security=True"; SqlCommand cmd = new SqlCommand(); cmd.Connection = con; con.Open(); cmd.CommandText = "Select * from CUSTOMERS"; SqlDataReader dr = default(SqlDataReader); dr = cmd.ExecuteReader(); while (dr.Read) { this.lstFCCustomers.Items.Add(dr.GetValue(1)); } dr.Close(); con.Close(); I hope this helps you to use ADO .NET objects. Faruk

Comment Request!
Thank you for reading this post. Please post your feedback, question, or comments about this post Here.
Loginto add your contents and source code to this article

Article Extensions
Contents added by ramanakanth k on Sep 20, 2010

For Connection Oriented you may have to use DataReader concept and For Connection Less You have to work on DataSet concept, Comparing to DataSet, Data Reader is More Faster But for dataset you may have to store bulk data. Here is Some example for Souce Code: Example for Connection Less: SqlConnection Cn=new SqlConnection("user id="abc";pwd="xyz";database="sample";data source="urservername"); cn.open(); SqlDataAdapter da=new SqlDataAdapter("Select * from employee",cn); DataSet ds=new DataSet(); da.fill(ds,employee); Gridview1.DataSource=ds;

Gridview1.DataBind(); Example for Connection Oriented: SqlConnection Cn=new SqlConnection("user id="abc";pwd="xyz";database="sample";data source="urservername"); cn.open(); SqlCommand cmd=new SqlCommand ("Select * from employee",cn); SqlDataReader dr=cmd.ExecuteReader(); if(dr.Read) { Gridview1.DataSource=ds.Tables[0].DefaultView; Gridview1.DataBind(); } else { Response.Write("Data Not Exist"); }

Designing and implementing a Data Warehouse: Part I


Introduction
Business Intelligence has become a buzzword in recent years as a support to decision making. Today we can find several database systems which include data warehousing, online analytical processing (OLAP), and data mining technologies. Data warehousing provides an efficient storage, maintenance, and retrieval of data. OLAP is a service that provides a way to create ad hoc queries against the data warehouse in order to answer important business questions. Data mining is a disciple comprising of several algorithms for discovering knowledge in a large bulk of data. In order to build a data warehouse solution, we need to model a consistent architecture where the operational data will fit well in an integrated and enterprise-wide view as well as to take into consideration a handful implementation strategies to provide a high quality application. The design and implementation of a data warehouse solution sometimes is a very complex challenge in theory and practice. In this article, I will cover the main principles and techniques to design and implement a data warehouse providing my own experience in such an overwhelming challenge. This is the first article of a series of articles that I want to write in order to share my knowledge and experience in this subject matter.

The design of a data warehouse


Although many of the principles and techniques to design and implement a relational data model for an operational system are adaptable to data warehouse modeling, they cannot be carried across in a natural way, thus data warehouse modeling is new discipline which is enhancing every day. Operational and decision support systems Most operational data is stored in relational database structures such as tables and their underlying relationships. They're highly normalized and optimized to support the business processes in the enterprise. This kind of schemas are excellent for operational systems with several users working concurrently and executing transactions (where the

most important criteria is the data consistency), although it's not adequate for reporting applications (where the common operation is data extraction and the most important criteria is the performance of the underlying query) using a huge amount of data by relatively very few users; because you have normally to join several tables in the execution of the query. Decision support systems deal with huge of historical data representing a time slice of the operational data. A data warehouse is the storage medium for the decision support systems and it requires periodic updates to load a new data from the operational data sources. Operations over data warehouse are characterized by read-only ad hoc queries (less predictable) over a high volume of data which might be integrated, aggregated, and summarized for decision support purposes. Table 1 summarizes the basic differences between operational (using relational database technologies) and decision support (using data warehouse technologies) systems.
Relational Database Systems Transaction oriented Thousands of users concurrently Generally small in size (Hundreds of MB up to GB) Current data Normalized data Continuous updates Simple to complex queries Data Warehouse Systems Business process oriented Few users Very large (Hundreds of GB up to several TB) Historical data De-normalized data Batch updates Very complex queries

Table 1 Dimensional modeling Dimensional modeling is a modeling technique to structure business dimensions and metrics which are analyzed along with dimensions in order to execute high performance queries. At a high level of interpretation, the data warehouse contains an integrated view of data which is derived from data in the operational systems supporting different business processes. In between the operational systems and the data warehouse, there is an important component known as the staging area. In this area, the operational data gets to be cleansed and transformed into a format suitable to be placed in the data warehouse storage. A data warehouse database is a highly de-normalized structure with two main components: the first one is a central table, also known as fact table, which contains transactional data and it is surrounded by the second type of components, known as the dimension tables which contain referential static data or master data. The conceptual relationship between these two main components is that the dimensions describe the facts. This specific data model of dimensions and facts tables is known as the dimensional model and it can be graphically described as a star schema (a single fact table surrounded by dimensions) which specifies a multidimensional database. A multidimensional database can be built using conventional relational DBMS (it is referred as ROLAP database) or specialized multidimensional DBMS optimized for such structures (referred as a multidimensional database composed by cubes). A data model of a data warehouse is practically made up of data marts or a sub-set of star schemas, where each data mart is a single fact table surrounded by dimension tables containing data for different departments of functional areas.

Transformation from the enterprise data model to the dimensional model The enterprise data model is the specification of the business entities as well as its underlying relationships, keys, attributes, subtypes and business rules using the entity relationship (ER) and normalization techniques. The enterprise data model is global view of the data model of the database systems to be integrated into the data warehouse. This important model corresponds to subject area supported by the underlying operational information systems. The degree of completion of the larger enterprise data model is of little concern to the development of the data warehouse. Once the enterprise data model is specified, you can make several transformations in order to build the dimensional model of the data warehouse such as: Removal of purely operational data Addition of appropriate derived data Transformation of relationships Creation of array of data

It's remarkable to say that these transformations are a guideline to the design of a data warehouse, but their use is mainly determined by the business requirements of the decision-support systems.

Removal of purely operational data


This transformation deals with examining the enterprise data model and removing all data that is purely operational. They are not removed from the enterprise data models; they are simply not useful in the dimensional model. For example, the definition of the entity Product (see Figure 1) contains a lot of operational attributes.

Figure 1 Now let's transform this definition into a new one that fits the dimensional model by removing the attributes: ProductNumber, MakeFlag, FinishedGoodsFlag, SafetyStockLevel, ReorderPoint, StandardCost, ListPrice, SizeUnitMeasureCode, WeightUnitMeasureCode, Weight, DaysToManufacture, ProductLine, Style, ProductSubcatogoryID, ProductModelID, SellStartDate, SellEndDate, DiscontinuedDate, rowguid and ModifiedDate. The final schema is shown in the Figure 2.

Figure 2

Addition of appropriate derived data


The next transformation is the addition of derived data (this is a de-normalization process) where it's mostly accessed and calculated in order to reduce the amount of processing required getting the data. Let's illustrate this transformation with an example of the Sales Order entity's data model (see Figure 3).

Figure 3 Now let's transforms this relational model in Figure 3 into a dimensional model (see Figure 4).

Figure 4 Another case is when we have physically designed the Product subject into two relational tables such as Product and ProductSubcategory tables in the AdventureWorks database (see Figure 5); and then we want to create a dimension for the Product subject. In this case, it's not descriptive to include the ProductSubcategoryID integer number; instead it's better to include the name of the product subcategory (see Figure 6).

Figure 5

Figure 6 Another interested case of this transformation is concerning the one-to-many relationship in the relation data model. Let's suppose that we have a non-identifying mandatory relationship between a Product and its Supplier. The underlying semantics dictates that a supplier may have many products, but a given product must have an associated supplier (see Figure 7).

Figure 7 In order to turn this data model into a dimensional model, we design an entity which represents the Supplier and Product entities and the associated relationship. We can also apply the Removal of purely operational data technique in order to design the most important attributes. This transformation is shown in the Figure 8.

Figure 8

Creation of Arrays of Data


As the enterprise data model is usually normalized, then the repeating groups are not shown as part of the model. But under some conditions, the data warehouse, as an analytical tool, needs to represent these repeating groups.

Let's suppose that our data model designs the Budget business entity. The budget occurs on a month-by-month basis. In order to normalize this structure, we have the Budget and BudgetItem entities associated by an indentifying relationship (see Figure 9).

Figure 9 Now when we apply the transformation technique, we get as a result the Figure 10.

Figure 10 It's remarkable to say that this transformation is not a general-purpose option. There are several scenarios where this strategy may be applied such as: When the number of occurrences of data are predictable. When the occurrence of data is relatively small. When the occurrences of data are frequently used together.

When the pattern of insertion and deletion is stable.

Conclusion
In this article, I've shown the principles of a data warehouse and the underlying modeling methodology.

Reading and Saving Images from/to a Database using C#

If you are new to database programming and ADO.NET, you may want to look at the ADO.NET section of C# Corner (http://www.c-sharpcorner.com). Plenty of source code samples and tutorials are available for free. You might want to check out my book for ADO.NET beginners: A Programmer's Guide to ADO.NET in C# (published by APress). First we need to create a database. We start by creating a new Access database called AppliedAdoNet.mdb and adding a table to the database called "Users." The database table schema should look like Figure 15.7 Microsoft Access stores binary large objects (BLOBs) using the OLE object data type. To make our application a little more interactive and user-friendly, let's create a Windows application and add a text box, three button controls, and a PictureBox control. The final form looks like Figure 15.8. As you can probably guess, the Browse Image button allows users to browse for bitmap files; the Save Image button saves the image to the database; and the Read Image button reads the first row of the database table, saves binary data as a bitmap, and displays the image in the picture box. Before we write code on button clicks, we need to define the following variables: //User-defined variable private Image curImage = null; private string curFileName = null; private string connectionString = "Provider=Microsoft.Jet.OLEDB.4.0; "+ "Data Source =F:\\AppliedAdoNet.mdb"; private string savedImageName = "F:\\ImageFromDb.BMP"; Do not forget to add references to the System.IO and System.Data.OleDb namespaces: using System.IO; using System.Data.OleDb;

Figure 15.7: Users table schema

Figure 15.8: Reading and writing images in a database form The stream-related classes are defined in the System.IO namespace. We will use the OLE DB data provider, which is defined in the System.Data.OleDb namespace, to work with our Access database. The Browse Image button click code is given in Listing 15.9, which simply browses bitmap files and saves the file name in CurFileName. We can set filter to access the file formats we want. Listing 15.9: the Browse button click event handler private void BrowseBtn_Click (object sender, system.EventArgs e) { OpenFileDialog openDlg = new OpenFileDialog(); openDlg.Filter = "All Bitmap files | *.bmp"; string filter = openDlg.Filter; openDlg.Title ="Open a Bitmap File"; if (openDlg.ShowDialog() == DialogResult.OK) { curFileName = openDlg.FileName; textBox1.Text = curFileName;

} } The Save Image button code given in Listing 15.10 creates a FileStream object from the bitmap file, opens a connection with the database, adds a new data row, set its values, and saves the row back to the database. Listing 15.10: The Save Image button click event handler private void SaveImageBtn_Click (object sender, System.EventArgs e) { //Read a bitmap's contents in a stream FileStream fs = new FileStream (curFileName, FileMode.OpenOrCreate, FileAccess.Read); byte[] rawData = new byte [fs.Length]; fs.Read (rawData, 0, System.Convert.ToInt32 (fs.Length)); fs.Close(); //Construct a SQL string and a connection object string sql = "SELECT * FROM Users"; OleDbConnection conn = new OleDbConnection(); conn.ConnectionString = connectionString; //Open the connection if (conn.State != ConnvetionState.Open) conn.Open(); //Create a data adapter and data set OleDbDataAdapter adapter = new PleDbDataAdapter (sql, conn); OleDbCommandBuilder cmdBuilder = new OleDbCommandBuilder (adapter); DataSet ds = new DataSet ("Users"); adapter.MissingSchemaAction =

MissingSchemaAction.AddWithKey; //Fill the data adapter adapter.Fill (ds, "Users"); string userDes = "Mahesh Chand is a founder of C# Corner"; userDes += "Author: 1. A Programmer's Guide to ADO.NET;"; userDea += ", 2. Applied ADO.NET."; //Create a new row DataRow row = ds.Tables ["Users"].NewRow(); row["UserName] ="Mahesh Chand"; row["UserEmail"]= mcb@mindcracker.com; row["UserDescription"] = userDes; row["UserPhoto"] = rawData; //Add the row to the collection ds.Tables ["Users"].Rows.Add (row); //Save changes to the database adapter.Update (ds, "Users"); //Clean up connection if(conn!=null) { if (con.State == ConnectionState.Open) conn.Close(); //Dispose of connection conn.Dispose(); } MessageBox.Show ("Image Saved");

} Once the data has been saved, the next step is to read data from the database table, save it as a bitmap again, and view the bitmap on the form. We can view an image using the Graphics.DrawImage method or using a picture box. Our example uses a picture box. The code for reading binary data is shown in Listing 15.11. We open a connection, create a data adapter, fill a data set, and get the first row of the Users table. If you want to read all the images, you may want to modify your application or loop through all the rows. Once a row has been read, we retrieve the data stored in the UserPhoto column in a stream and save it as a bitmap file. Later we view that bitmap file in a picture box by setting its Image property to the file name. Listing 15.11: Reading images from a database private void ReadImageBtn_Click(object sender, System.EventArgs e) { //Construct a SQL string and a connection object string sql = "SELECT * FROM Users"; OleDbConnection conn = new OleDbConnection(); conn.ConnectionString = connectionString; //Open the connection if (conn.State != ConnectionState.Open) conn.Open(); //Create a data adapter and data set OleDbDataAdapter adapter = new OleDbDataAdapter(sql, conn); OleDbCommandBuilder cmdBuilder = new OleDbCommandBuilder(adapter); DataSet ds = new DataSet("Users"); adapter.MissingSchemaAction = MissingSchemaAction.AddWithKey; //Fill the data adapter adapter.Fill(ds, "Users");

//Get the first row of the table DataRow row = ds.Tables["Users"].Rows[0]; //Read data in a stream byte[] rawData = new byte[0]; rawData = (byte[])row["UserPhoto"]; int len = new int(); len = rawData.GetUpperBound(0); //Save rawData as a bitmap FileStream fs = new FileStream (savedImageName, FileMode.OpenOrCreate, FileAccess.Write); fs.Write(rawData, 0, len); //Close the stream fs.Close(); //View the image in a pciture box curImage = Image.FromFile(savedImageName); pictureBox1.Image = curImage; //Clean up connection if (conn != null) { if (conn.State == ConnectionState.Open) conn.Close(); //Dispose of connection conn.Dispose(); } }

To see the program in action, we select the MyPhoto.bmp file by using the Browse Image button, and we click the Save Image button. When we open the database, we see that a new record has been added to the Users table. When we click on the Read Image button, a new ImageFromDb.bmp file is added to the current folder. The output is shown in figure 15.9.

Figure 15.9: Displaying a bitmap after reading data from a database

Connect to an SSIS package and consume its data from .Net application
In this article, I will show how to connect to a Data reader destination component within a given SQL Server Integration Services package. The client application in this context is a simple console application that I have built using C# 3.5. Requirements First of all, there are conditions and requirements to be fulfilled in order to proceed and follow the subsequent walkthrough steps. 1. First, you have to have SQL server 2005/2008 at least the standard edition as it supports BI tools, namely SQL server integration services, SQL server analysis services and SQL server reporting services. But for our case we will be interested only on SQL server integration services.

2. You have to install those BI tools if they aren't already installed. To install them
you have to lunch the SQL Installation Center

3. And then switch to the installation tab, then lunch the installation wizard through
the first link

4. Of Corse, you have to have the SQL Server installation CD in the drive. Then
follow the installation steps until you rich the bellow level

5. Of Corse, if you want to install a new named instance select the first alternative,
and if you want to enhance an already existed instance then select the second choice Remarque: The installation step details are beyond the scope of this article, to know how to install SQL Server in detail please refer to this guide for 2005 version: http://www.impromed.com/documents/SQL_Server_2005_09252006.pdf And for 2008 version : http://blog.sqlauthority.com/2008/06/12/sql-server-2008-step-by-stepinstallation-guide-with-images/

6. Now, we are concerned by the bellow installation step, the Integration services
must be checked

7. After the installation verify that the BI IDE which is Business Intelligence
Development Studio BIDS is installed

The Data Reader destination case The data reader destination component is a particular one among the rest of the other SSIS components as it is designed not to load data within a given data base or within a given file but it loads data in memory in order to be accessed by client applications like the .Net assemblies.

1. To starts let's first create a SSIS project

2. The create a new package by right clicking the packages folder within the solution explorer and then select create new package, then rename it by right clicking it and giving it a new name

3. Drag a data flow component within the scene

4. Double click that data flow in the scene then drag a OLEDB Source and a Data Reader destination

5. First begin by configuring the OLE DB source by double clicking it, then set the
connection manager by configuring its provider, data base and data source which could be a table, a view or a command. The last one is better for performance issues. In my case, I connect to the Adventure works data base and retrieve full name which is a derived column and the city one and the state one. To choose an SQL command, you can select it from the SQL command text drop down list; you will remark that the page look will change. Then you can use the Build Query option to compose you query if you're not strong enough in SQL ; )

6. Always with the OLE DB source configuration wizard, ensure that all the desired
columns within the view are selected by switching to the columns tab

7. Now, we step through to the data reader destination configuration, to do that,


double click on that component, and first, let's link it with the OLE DB source component.

Second, let's verify that all columns are correctly mapped by switching to the Input Columns tab.

8. We can verify the correctness of the package content by debugging it by hitting


F5, all the packages must turn to green color

9. Now, let's create a client application that consumes data from that package
For this case we can create a simple console application to consume that data flow. To do that, add a console application project to the solution. 10. Add a reference to the Microsoft.SqlServer.Dts.DtsClient.dll which is a managed assembly located in %ProgramFiles%\Microsoft SQL Server\100\DTS\Binn

11. Then add this code to the class Program of the client, Of Corse, in my case I'm
supposing to retrieve data from MyPackage.dtsx which is located in

C:\Users\Administrator\Documents\VisualStudio 2008\Projects\SSISProject001\SSISProject001\ folder. The name of the data reader destination component is DataReaderDest that could be found within the properties grid of that component, in deed, you can change that name to suit your needs. In my case, I suppose to retrieve the full name, the city and the state fields from that data reader destination. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data; using Microsoft.SqlServer.Dts.DtsClient; using System.Windows.Forms; namespace DataClient { class Program { static DtsConnection connection; static DtsCommand command; static IDataReader reader; static void Main(string[] args) { using(connection = new DtsConnection()) { connection.ConnectionString = @"/File "" C:\Users\Administrator\Documents\Visual Studio 2008\Projects\SSISProject001\SSISProject001\MyPackage.dtsx"""; try { connection.Open(); command = new DtsCommand(connection); command.CommandText = "DataReaderDest"; reader = command.ExecuteReader(CommandBehavior.Default); while(reader.Read()) { Console.WriteLine(string.Format("Full name: " + reader[0]+ " City" + reader[1] )); } } catch(ApplicationException caught) { Console.WriteLine(caught.Message + " ,something is wrong"); } finally { Console.Read(); } } } } } Very important issue: SSIS packages could be stored in the file system like our case, and then connection string is in that case as follow:

@"/File "" <The path>\<The package name>.dtsx""" They could also be stored within the SQL server instance and exactly within the msdb system data base. In this case, the connection should be modified to be: @"/SQL ""<The package name>""" Then, if the package is stored within SSIS storage, the SQL keyword must be replaced by DTS one. You can play around by importing the given package within SQL Server Management Studio and exactly the SQL Server Integration Services instance if you have right permissions to do that and then try those connection strings to retrieve data from the package.

12. Finally, to lunch and test the client let start by setting the integration service

project as a startup project and then lunch it by hitting F5, then you should wait until every component become green. Afterward, Start a new instance of the client

And the result will be as expected

It retrieves in memory data successfully.

How-to store FastReport.NET report templates in database


Some applications require the storing of report templates in a database. This simplifies template support - all reports are stored in one place, and allows to differentiate the access rights to different templates. I noted only one shortcoming of this technique slight complication of the code in the client application. For example, we need to create Access database (mdb) named "reports" and a table for storing our report templates. I named this table "reports_table". Three tables are enough in our data table: No. Field name Type Description 1 Id counter Auto-increment, index 2 ReportName text Name of report 3 ReportFile BLOB Binary data with template You can store templates in any other database similar to the one in our example. To do this: open the designer;

show custom form with a list of templates from our database instead of standard dialog when users open a file in the designer; load template in the designer after selecting it in the custom form; Save the template in a database where the user saves a file in the designer.

Despite the apparent complexity, the tasks above will be simple because FastReport.NET has special features. Create a new project in Visual Studio first. Then you need to drag-n-drop "Report" object from toolbox to the empty form. Also drag the " EnvironmentSettings" object (properties of reporting engine). You can setup many settings of the report and the designer in "environmentSettings1" object. You have to override the event handlers CustomOpenDialog, CustomOpenReport, CustomSaveDialog and CustomSaveReport. Event handler CustomOpenDialog allows releasing any algorithm of the load report template in the designer - load template from the database field and load it in the designer or set e.Cancel = true; when loading fails. The problem reduces to showing a dialogue with a list of files from which you want to select the report template from the database and load the template in the designer. Of course, if the user presses the Cancel button in this dialog, we set e.Cancel = true. The loading process is clear but saving code need some details. The user can choose two ways to save a file - simply by clicking "Save", in this case report should be rewritten to the old place, or the second option - "Save as...", the user is expected to select path of file. Storage location of report templates cannot be changed in our case. You need to save template in the old place (database field) in both ways capture the CustomSaveDialog event by empty function and save template in database in the CustomSaveReport event. Now you need to add a new data source to the project - reports.mdb.Drop the button on form for launching of the reports designer. Write in the Click event handler: private void button1_Click(object sender,EventArgs e) { report1.Design(); } Create an additional dialog form for template selection: Assign the buttons OK and Cancel corresponding to DialogResult. Do not forget to bind your data source to DataGrid - select the field name of the record and make the index field invisible. You need to save the selected index when you click on the 'OK' button: public int reportID; private void OKBtn_Click(object sender,EventArgs e) { // save id of report for use in future

reportID = (int)dataGridView1.CurrentRow.Cells[0].Value; } We return to our first form. It is time to handle the events of opening and saving a report. We make loading the first thing to do: // define variable for store of report ID private int reportID; // define array byte[] for store of template private byte[] blob; private void environmentSettings1_CustomOpenDialog(object sender, astReport.Design.OpenSaveDialogEventArgs e) { using (ReportListForm reportListForm =new ReportListForm()) { // show dialog for report selection if (reportListForm.ShowDialog() == DialogResult.OK) { // get report ID reportID = reportListForm.reportID; // load report in array from BLOB blob = (byte[])this.reports_tableTableAdapter.GetDataByID(reportID).Rows[0]["ReportFile"]; // read file name of report for designers title e.FileName = (string)this.reports_tableTableAdapter.GetDataByID(reportID).Rows[0]["ReportName"]; } else // cancel loading e.Cancel = true; } } Second handler CustomOpenReport for loading the template in designer should look like this: privatevoid environmentSettings1_CustomOpenReport(object sender, FastReport.Design.OpenSaveReportEventArgs e) { using (MemoryStream stream = new MemoryStream()) { // skip all garbage created by MS Access in begin of blob field - we seek the tag of XML int start = 0; for (int i = 0; i) } }

DataReader in C#
A Key Class in ADO.NET: DataReader The DataReader object is used for accessing data from the data store and is one of the two mechanisms that ADO.NET provides. As we will remember DataReader object provides a read only, forward only, high performance mechanism to retrieve data from a data store as a data stream, while staying connected with the data source. The

DataReader is restricted but highly optimized. The .NET framework provides data providers for SQL Server native OLE DB providers and native ODBC drivers: SqlDataReader OleDbDataReader OdbcDataReader

You can use the ADO.NET DataReader to retrieve a read-only, forward-only stream of data from a database. Using the DataReader can increase application performance and reduce system overhead because only one row at a time is ever in memory. After creating an instance of the Command object, you create a DataReader by calling Command.ExecuteReader to retrieve rows from a data source, as shown in the following example. SqlDataReader myReader = myCommand.ExecuteReader(); You use the Read method of the DataReader object to obtain a row from the results of the query. You can access each column of the returned row by passing the name or ordinal reference of the column to the DataReader. However, for best performance, the DataReader provides a series of methods that allow you to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). For a list of typed accessor methods, see the OleDbDataReader Class and the SqlDataReader Class. Using the typed accessor methods when the underlying data type is known will reduce the amount of type conversion required when retrieving the column value. The following code example iterates through a DataReader object, and returns two columns from each row. while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); myReader.Close(); The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory. You should always call the Close method when you have finished using the DataReader object. If your Command contains output parameters or return values, they will not be available until the DataReader is closed. Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. You will not be able to execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed. Multiple Result Sets If multiple result sets are returned, the DataReader provides the NextResult method to iterate through the result sets in order, as shown in the following code example. SqlCommand myCMD = new SqlCommand("SELECT CategoryID, CategoryName FROM

Categories;" + "SELECT EmployeeID, LastName FROM Employees", nwindConn); nwindConn.Open(); SqlDataReader myReader = myCMD.ExecuteReader(); do { Console.WriteLine("\t{0}\t{1}", myReader.GetName(0), myReader.GetName(1)); while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); } while (myReader.NextResult()); myReader.Close(); nwindConn.Close(); The DataReader implementation must provide two basic capabilities: forward-only access over one or more of the resultsets obtained by executing a Command, and access to the column values within each row. Data types from your data source will be stored in your .NET-based application as .NET Framework types. Your DataReader implementation will also provide strongly typed accessor methods for your DataReader that return column values as .NET Framework types. Examples of a strongly typed accessor would be GetInt32, GetString, and so on. If your .NET data provider has proprietary types that cannot adequately be exposed as .NET Framework types, you may extend the interfaces to support proprietary types, then add typed accessors for your DataReader that return proprietary types as well. For example, you can add GetMyStructure, GetMyTimeStamp, and so on. An example of this is the SQL Server .NET Data Provider, which exposes proprietary types using the System.Data.SqlTypes Namespace. The SqlDataReader then exposes those types as SqlTypes using strongly typed accessor methods. For example: GetSqlBinary, GetSqlDateTime, GetSqlDecimal, and so on. using System; using System.Data; using System.Globalization; namespace DotNetDataProviderTemplate { public class TemplateDataReader : IDataReader { // The DataReader must always be open when returned to the user. private bool dReaderOpen = true; // Keep track of the results and position // within the resultset (starts prior to first record). private TestDataBase.TestDataBaseResultSet testResultset; private static int testSTARTPOS = -1; private int testNPos = testSTARTPOS; private TemplateConnection testconnection = null; internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset) { testResultset = resultset; } internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset,

emplateConnection connection) { testResultset = resultset; testconnection = connection; } public int Depth { get { return 0; } } public bool IsClosed { get { return !dReaderOpen; } } public int RecordsAffected { get { return -1; } } public void Close() { dReaderOpen = false; } public bool NextResult() { return false; } public bool Read() { if (++testNPos >= testResultset.data.Length / testResultset.metaData.Length) return false; else return true; } public DataTable GetSchemaTable() { throw new NotSupportedException(); } public int FieldCount { get { return testResultset.metaData.Length; } } public String GetName(int i) { return testResultset.metaData[i].name; } public String GetDataTypeName(int i) { return testResultset.metaData[i].type.Name; } public Type GetFieldType(int i) {

return testResultset.metaData[i].type; } public Object GetValue(int i) { return testResultset.data[testNPos, i]; } public int GetValues(object[] values) { for (int i = 0; i < values.Length && i < testResultset.metaData.Length; i++) { values[i] = testResultset.data[testNPos, i]; } return i; } public int GetOrdinal(string name) { for (int i = 0; i < testResultset.metaData.Length; i++) { if (0 == _cultureAwareCompare(name, testResultset.metaData[i].name)) { return i; } } throw new IndexOutOfRangeException("Could not find specified column in results"); } public object this [ int i ] { get { return testResultset.data[testNPos, i]; } } public object this [ String name ] { get { return this[GetOrdinal(name)]; } } public bool GetBoolean(int i) { return (bool)testResultset.data[testNPos, i]; } public byte GetByte(int i) { return (byte)testResultset.data[testNPos, i]; } public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetBytes not supported."); } public char GetChar(int i) { return (char)testResultset.data[testNPos, i]; } public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)

{ throw new NotSupportedException("GetChars not supported."); } public Guid GetGuid(int i) { return (Guid)testResultset.data[testNPos, i]; } public Int16 GetInt16(int i) { return (Int16)testResultset.data[testNPos, i]; } public Int32 GetInt32(int i) { return (Int32)testResultset.data[testNPos, i]; } public Int64 GetInt64(int i) { return (Int64)testResultset.data[testNPos, i]; } public float GetFloat(int i) { return (float)testResultset.data[testNPos, i]; } public double GetDouble(int i) { return (double)testResultset.data[testNPos, i]; } public String GetString(int i) { return (String)testResultset.data[testNPos, i]; } public Decimal GetDecimal(int i) { return (Decimal)testResultset.data[testNPos, i]; } public DateTime GetDateTime(int i) { return (DateTime)testResultset.data[testNPos, i]; } public IDataReader GetData(int i) { throw new NotSupportedException("GetData not supported."); } public bool IsDBNull(int i) { return testResultset.data[testNPos, i] == DBNull.Value; } private int _cultureAwareCompare(string strA, string strB) { return

CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, ompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | ompareOptions.IgnoreCase); } } } * IgnoreKanaType Specifies that the string comparison must ignore the Kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds in the Japanese language. Summary In this article we had a discussion about the DataSet and its role in data-oriented applications. The DataSet is main one of the main components and it is important to understand to DataAdapter, DataTable, DataView, DataGrid and other objects in ADO.NET. Finally we create an example, which it has several functionality about DataSet and its relations with other ADO.NET classes. Next article we will discuss about multiple data tables and it will give us more idea on complex, advanced DataSets.

Data Binding in DataGrid Control using C#


Additional words to DataGrid A DataGrid control is a control that is displays ADO.NET data in a scrollable grid. The System.Windows.Forms.DataGrid (windows form) displays web-like links to child tables. You can click on a link to navigate to the child table. When a child table is displayed, a back button appears in the caption that can be clicked to navigate back to the parent table. The data from the parent rows is displayed below the caption and above the column headers. You can hide the parent row information by clicking the button to the right of the back button. To display a table in the System.Windows.Forms.DataGrid at run time, use the SetDataBinding method to set the DataSource and DataMember properties to a valid data source. The following data sources are valid: A DataTable A DataView A DataSet A DataViewManager A single dimension array Any component that implements the IListSource interface Any component that implements the IList interface

Data sources are further managed by BindingManagerBase objects. For each table in a data source, a BindingManagerBase can be returned from the form's BindingContext. For example, you can determine the number of rows contained by a data source by returning the associated BindingManagerBase object's Count Property. To validate data, use the underlying objects that represent data and their events. For example, if the data comes from a DataTable in a DataSet, use the ColumnChanging and RowChanging events. Note Because the number of columns can be customized (by

adding or deleting members of the GridColumnStylesCollection) and the rows may be sorted by column, the RowNumber and ColumnNumber property values cannot be guaranteed to correspond to DataRow and DataColumn indexes in a DataTable. Therefore you should avoid using those properties in the Validating event to validate data. To determine which cell is selected, use the CurrentCell property. Change the value of any cell by using the Item property, which can take both the row and column indexes of the cell, or a single DataGridCell. Monitor the CurrentCellChanged event to detect when the user selects another cell. To determine which part of the control the user clicked, use the HitTest method in the MouseDown event. The HitTest method returns a DataGrid.HitTestInfo object, which contains the row and column of a clicked area. To manage the appearance of the control at run time, several properties for setting the color and caption attributes are available, including the CaptionForeColor, CaptionBackColor, CaptionFont, and so on. The appearance of the displayed grid (or grids) can be further modified by creating DataGridTableStyle objects and adding them to the GridTableStylesCollection, which is accessed through the TableStyles property. For example, if the DataSource is set to a DataSet containing three DataTable objects, you can add three DataGridTableStyle objects to the collection, one for each table. To synchronize each DataGridTableStyle object with a DataTable, set the MappingName of the DataGridTableStyle to the TableName of the DataTable. To create a customized view of a table, create a collection of DataGridColumnStyle objects, and set each column's MappingName to the ColumnName of a column that you want to show in the grid. To hide a column, set its MappingName to something other than a valid ColumnName. For each DataGridTableStyle, you can set color and caption attributes that override the settings for the System.Windows.Forms.DataGrid control. However, if those properties are not set, the settings for the control are used by default. The following properties can be overridden by DataGridTableStyle properties: AllowSorting AlternatingBackColor BackColor ColumnHeadersVisible ForeColor GridLineColor GridLineStyle HeaderBackColor HeaderFont HeaderForeColor LinkColor PreferredColumnWidth PreferredRowHeight ReadOnly RowHeadersVisible RowHeaderWidth SelectionBackColor SelectionForeColor

To customize the appearance of individual columns, add DataGridColumnStyle objects to the GridColumnStylesCollection, which is accessed through the GridColumnStyles property of each DataGridTableStyle. To synchronize each DataGridColumnStyle with a DataColumn in the DataTable, set the MappingName to the ColumnName of a DataColumn. When constructing a DataGridColumnStyle, you can also set a formatting

string that specifies how the column displays data. For example, you can specify that the column use a short-date format to display dates contained in the table. Please pay attention to you need always create DataGridColumnStyle objects and add them to the GridColumnStylesCollection before adding DataGridTableStyle objects to the GridTableStylesCollection. When you add an empty DataGridTableStyle to the collection, DataGridColumnStyle objects are automatically generated for you. Consequently, an exception will be thrown if you try to add new DataGridColumnStyle objects with duplicate MappingName values to the GridColumnStylesCollection. The following example creates a Windows form, a DataSet containing two DataTable objects, and a DataRelation that relates the two tables. To display the data, a System.Windows.Forms.DataGrid control is then bound to the DataSet through the SetDataBinding method. A button on the form changes the appearance of the grid by creating two DataGridTableStyle objects and setting the MappingName of each object to a TableName of one of the DataTable objects. The example also contains code in the MouseUp event that uses the HitTest method to print the column, row, and part of the grid that has been clicked. using System; using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; public class Form1 : System.Windows.Forms.Form { private System.ComponentModel.Container components; private Button button1; private Button button2; private DataGrid myDataGrid; private DataSet myDataSet; private bool TablesAlreadyAdded; public Form1() { // Required for Windows Form Designer support. InitializeComponent(); // Call SetUp to bind the controls. SetUp(); } protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose();} } base.Dispose( disposing ); } private void InitializeComponent() {

// Create the form and its controls. this.components = new System.ComponentModel.Container(); this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.myDataGrid = new DataGrid(); this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.Text = "DataGrid Control Sample"; this.ClientSize = new System.Drawing.Size(450, 330); button1.Location = new Point(24, 16); button1.Size = new System.Drawing.Size(120, 24); button1.Text = "Change Appearance"; button1.Click+=new System.EventHandler(button1_Click); button2.Location = new Point(150, 16); button2.Size = new System.Drawing.Size(120, 24); button2.Text = "Get Binding Manager"; button2.Click+=new System.EventHandler(button2_Click); myDataGrid.Location = new Point(24, 50); myDataGrid.Size = new Size(300, 200); myDataGrid.CaptionText = "Microsoft DataGrid Control"; myDataGrid.MouseUp += new MouseEventHandler(Grid_MouseUp); this.Controls.Add(button1); this.Controls.Add(button2); this.Controls.Add(myDataGrid); } public static void Main() Application.Run(new Form1()); } private void SetUp() { // Create a DataSet with two tables and one relation. MakeDataSet(); /* Bind the DataGrid to the DataSet. The dataMember specifies that the Customers table should be displayed.*/ myDataGrid.SetDataBinding(myDataSet, "Customers"); } protected void button1_Click(object sender, System.EventArgs e) { if(TablesAlreadyAdded) return;AddCustomDataTableStyle(); } private void AddCustomDataTableStyle() { DataGridTableStyle ts1 = new DataGridTableStyle(); ts1.MappingName = "Customers"; // Set other properties. ts1.AlternatingBackColor = Color.LightGray; /* Add a GridColumnStyle and set its MappingName to the name of a DataColumn in the DataTable. Set the HeaderText and Width properties. */ DataGridColumnStyle boolCol = new DataGridBoolColumn(); boolCol.MappingName = "Current";

boolCol.HeaderText = "IsCurrent Customer"; boolCol.Width = 150; ts1.GridColumnStyles.Add(boolCol);// Add a second column style. DataGridColumnStyle TextCol = new DataGridTextBoxColumn(); TextCol.MappingName = "custName"; TextCol.HeaderText = "Customer Name"; TextCol.Width = 250;ts1.GridColumnStyles.Add(TextCol); // Create the second table style with columns. DataGridTableStyle ts2 = new DataGridTableStyle(); ts2.MappingName = "Orders"; // Set other properties. ts2.AlternatingBackColor = Color.LightBlue; // Create new ColumnStyle objects DataGridColumnStyle cOrderDate = new DataGridTextBoxColumn(); cOrderDate.MappingName = "OrderDate"; cOrderDate.HeaderText = "Order Date"; cOrderDate.Width = 100; ts2.GridColumnStyles.Add(cOrderDate); /* Use a PropertyDescriptor to create a formatted column. First get the PropertyDescriptorCollection for the data source and data member. */ PropertyDescriptorCollection pcol = this.BindingContext [myDataSet, "Customers.custToOrders"].GetItemProperties(); /* Create a formatted column using a PropertyDescriptor. The formatting character "c" specifies a currency format. */ DataGridColumnStyle csOrderAmount = new DataGridTextBoxColumn(pcol ["OrderAmount"], "c", true); csOrderAmount.MappingName = "OrderAmount"; csOrderAmount.HeaderText = "Total"; csOrderAmount.Width = 100; ts2.GridColumnStyles.Add(csOrderAmount); /* Add the DataGridTableStyle instances to the GridTableStylesCollection. */myDataGrid.TableStyles.Add(ts1); myDataGrid.TableStyles.Add(ts2); // Sets the TablesAlreadyAdded to true so this doesn't happen again. TablesAlreadyAdded=true; } protected void button2_Click(object sender, System.EventArgs e) { BindingManagerBase bmGrid; bmGrid = BindingContext[myDataSet, "Customers"]; MessageBox.Show("Current BindingManager Position: " + bmGrid.Position); } private void Grid_MouseUp(object sender, MouseEventArgs e) { // Create a HitTestInfo object using the HitTest method. // Get the DataGrid by casting sender. DataGrid myGrid = (DataGrid)sender;

DataGrid.HitTestInfo myHitInfo = myGrid.HitTest(e.X, e.Y); Console.WriteLine(myHitInfo); Console.WriteLine(myHitInfo.Type); Console.WriteLine(myHitInfo.Row); Console.WriteLine(myHitInfo.Column); } // Create a DataSet with two tables and populate it. private void MakeDataSet() { // Create a DataSet. myDataSet = new DataSet("myDataSet"); // Create two DataTables. DataTable tCust = new DataTable("Customers"); DataTable tOrders = new DataTable("Orders");// Create two columns, and add them to the first table. DataColumn cCustID = new DataColumn("CustID", typeof(int)); DataColumn cCustName = new DataColumn("CustName"); DataColumn cCurrent = new DataColumn("Current", typeof(bool)); tCust.Columns.Add(cCustID); tCust.Columns.Add(cCustName); tCust.Columns.Add(cCurrent);// Create three columns, and add them to the second table. DataColumn cID = new DataColumn("CustID", typeof(int)); DataColumn cOrderDate = new DataColumn("orderDate",typeof(DateTime)); DataColumn cOrderAmount = new DataColumn("OrderAmount", typeof(decimal)); tOrders.Columns.Add(cOrderAmount); tOrders.Columns.Add(cID); tOrders.Columns.Add(cOrderDate); // Add the tables to the DataSet. myDataSet.Tables.Add(tCust); myDataSet.Tables.Add(tOrders); // Create a DataRelation, and add it to the DataSet. DataRelation dr = new DataRelation ("custToOrders", cCustID , cID); myDataSet.Relations.Add(dr); /* Populates the tables. For each customer and order, creates two DataRow variables. */ DataRow newRow1; DataRow newRow2; // Create three customers in the Customers Table. for(int i = 1; i < 4; i++) { newRow1 = tCust.NewRow(); newRow1["custID"] = i; // Add the row to the Customers table. tCust.Rows.Add(newRow1); } // Give each customer a distinct name. tCust.Rows[0]["custName"] = "Alpha";

tCust.Rows[1]["custName"] = "Beta"; tCust.Rows[2]["custName"] = "Omega";// Give the Current column a value. tCust.Rows[0]["Current"] = true; tCust.Rows[1]["Current"] = true; tCust.Rows[2]["Current"] = false; // For each customer, create five rows in the Orders table. for(int i = 1; i < 4; i++) { for(int j = 1; j < 6; j++) { newRow2 = tOrders.NewRow(); newRow2["CustID"]= i; newRow2["orderDate"]= new DateTime(2001, i, j * 2); newRow2["OrderAmount"] = i * 10 + j * .1; // Add the row to the Orders table. tOrders.Rows.Add(newRow2); } } } } Editing with DataGridTextBox and DataGridTextColumn The DataGridTextBox and the DataGridTextBoxColumn work together to allow users to directly edit values in a DataGrid control column. The DataGridTextBoxColumn derives from DataGridColumnStyle, and is designed to host the DataGridTextBox, which derives from the TextBox control. In addition to the properties, events, and methods of the base control, you can call the KeyPress and KeyDown events with the OnKeyPress and OnMouseDown methods. private void GetDataGridTextBox() { // Gets the DataGridTextBoxColumn from the DataGrid control.DataGridTextBoxColumn myTextBoxColumn; // Assumes the CompanyName column is a DataGridTextBoxColumn. myTextBoxColumn = (DataGridTextBoxColumn)dataGrid1. TableStyles[0].GridColumnStyles["CompanyName"]; // Gets the DataGridTextBox for the column. DataGridTextBox myGridTextBox; myGridTextBox = (DataGridTextBox) myTextBoxColumn.TextBox; } The DataGridTextBoxColumn class derives from the abstract (MustInherit in Visual Basic) class DataGridColumnStyle. At run time, the DataGridTextBoxColumn hosts a DataGridTextBox control that allows users to edit text. Special properties added to the class include Format, and HideEditBox. These properties allow you to access the hosted DataGridTextBox control and its attributes, and set the format for displaying values.

If the data source is a DataTable containing DataColumn objects, the DataType property

of the DataColumn should be set to a data type that can logically be edited in a text box control. The following data types are automatically associated with a DataGridTextBoxColumn: Byte, DateTime, Decimal, Double, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, and String. private void AddColumn() { DataTable myTable= new DataTable(); // Add a new DataColumn to the DataTable. DataColumn myColumn = new DataColumn("myTextBoxColumn"); myColumn.DataType = System.Type.GetType("System.String"); myColumn.DefaultValue="default string"; myTable.Columns.Add(myColumn); // Get the CurrencyManager for the DataTable. CurrencyManager cm = (CurrencyManager)this.BindingContext[myTable]; // Use the CurrencyManager to get the PropertyDescriptor for the // new column. PropertyDescriptor pd = cm.GetItemProperties()["myTextBoxColumn"]; DataGridTextBoxColumn myColumnTextColumn; // Create the DataGridTextBoxColumn with the PropertyDescriptor. myColumnTextColumn = new DataGridTextBoxColumn(pd); // Add the new DataGridColumn to the GridColumnsCollection. dataGrid1.DataSource= myTable; dataGrid1.TableStyles.Add(new DataGridTableStyle()); dataGrid1.TableStyles[0].GridColumnStyles.Add(myColumnTextColumn); } A Key Class in ADO.NET: DataReader The DataReader object is used for accessing data from the data store and is one of the two mechanisms that ADO.NET provides. As we will remember DataReader object provides a read only, forward only, high performance mechanism to retrieve data from a data store as a data stream, while staying connected with the data source. The DataReader is restricted but highly optimized. The .NET framework provides data providers for SQL Server native OLE DB providers and native ODBC drivers: SqlDataReader OleDbDataReader OdbcDataReader

You can use the ADO.NET DataReader to retrieve a read-only, forward-only stream of data from a database. Using the DataReader can increase application performance and reduce system overhead because only one row at a time is ever in memory. After creating an instance of the Command object, you create a DataReader by calling Command.ExecuteReader to retrieve rows from a data source, as shown in the following example. SqlDataReader myReader = myCommand.ExecuteReader(); You use the Read method of the DataReader object to obtain a row from the results of

the query. You can access each column of the returned row by passing the name or ordinal reference of the column to the DataReader. However, for best performance, the DataReader provides a series of methods that allow you to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). For a list of typed accessor methods, see the OleDbDataReader Class and the SqlDataReader Class. Using the typed accessor methods when the underlying data type is known will reduce the amount of type conversion required when retrieving the column value. The following code example iterates through a DataReader object, and returns two columns from each row. while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); myReader.Close(); The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory. You should always call the Close method when you have finished using the DataReader object. If your Command contains output parameters or return values, they will not be available until the DataReader is closed. Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. You will not be able to execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed. Multiple Result Sets If multiple result sets are returned, the DataReader provides the NextResult method to iterate through the result sets in order, as shown in the following code example. SqlCommand myCMD = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories;" + "SELECT EmployeeID, LastName FROM Employees", nwindConn); nwindConn.Open(); SqlDataReader myReader = myCMD.ExecuteReader(); do { Console.WriteLine("\t{0}\t{1}", myReader.GetName(0), myReader.GetName(1)); while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); } while (myReader.NextResult()); myReader.Close(); nwindConn.Close(); The DataReader implementation must provide two basic capabilities: forward-only access over one or more of the resultsets obtained by executing a Command, and access to the column values within each row. Data types from your data source will be stored in your .NET-based application as .NET Framework types. Your DataReader implementation will also provide strongly typed accessor methods for your DataReader that return

column values as .NET Framework types. Examples of a strongly typed accessor would be GetInt32, GetString, and so on. If your .NET data provider has proprietary types that cannot adequately be exposed as .NET Framework types, you may extend the interfaces to support proprietary types, then add typed accessors for your DataReader that return proprietary types as well. For example, you can add GetMyStructure, GetMyTimeStamp, and so on. An example of this is the SQL Server .NET Data Provider, which exposes proprietary types using the System.Data.SqlTypes Namespace. The SqlDataReader then exposes those types as SqlTypes using strongly typed accessor methods. For example: GetSqlBinary, GetSqlDateTime, GetSqlDecimal, and so on. using System; using System.Data; using System.Globalization; namespace DotNetDataProviderTemplate { public class TemplateDataReader : IDataReader { // The DataReader must always be open when returned to the user. private bool dReaderOpen = true; // Keep track of the results and position // within the resultset (starts prior to first record). private TestDataBase.TestDataBaseResultSet testResultset; private static int testSTARTPOS = -1; private int testNPos = testSTARTPOS; private TemplateConnection testconnection = null; internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset) { testResultset = resultset; } internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset, emplateConnection connection) { testResultset = resultset; testconnection = connection; } public int Depth { get { return 0; } } public bool IsClosed { get { return !dReaderOpen; } } public int RecordsAffected { get { return -1; } } public void Close()

{ dReaderOpen = false; } public bool NextResult() { return false; } public bool Read() { if (++testNPos >= testResultset.data.Length / testResultset.metaData.Length) return false; else return true; } public DataTable GetSchemaTable() { throw new NotSupportedException(); } public int FieldCount { get { return testResultset.metaData.Length; } } public String GetName(int i) { return testResultset.metaData[i].name; } public String GetDataTypeName(int i) { return testResultset.metaData[i].type.Name; } public Type GetFieldType(int i) { return testResultset.metaData[i].type; } public Object GetValue(int i) { return testResultset.data[testNPos, i]; } public int GetValues(object[] values) { for (int i = 0; i < values.Length && i < testResultset.metaData.Length; i++) { values[i] = testResultset.data[testNPos, i]; } return i; } public int GetOrdinal(string name) { for (int i = 0; i < testResultset.metaData.Length; i++) {

if (0 == _cultureAwareCompare(name, testResultset.metaData[i].name)) { return i; } } throw new IndexOutOfRangeException("Could not find specified column in results"); } public object this [ int i ] { get { return testResultset.data[testNPos, i]; } } public object this [ String name ] { get { return this[GetOrdinal(name)]; } } public bool GetBoolean(int i) { return (bool)testResultset.data[testNPos, i]; } public byte GetByte(int i) { return (byte)testResultset.data[testNPos, i]; } public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetBytes not supported."); } public char GetChar(int i) { return (char)testResultset.data[testNPos, i]; } public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetChars not supported."); } public Guid GetGuid(int i) { return (Guid)testResultset.data[testNPos, i]; } public Int16 GetInt16(int i) { return (Int16)testResultset.data[testNPos, i]; } public Int32 GetInt32(int i) { return (Int32)testResultset.data[testNPos, i]; } public Int64 GetInt64(int i) { return (Int64)testResultset.data[testNPos, i];

} public float GetFloat(int i) { return (float)testResultset.data[testNPos, i]; } public double GetDouble(int i) { return (double)testResultset.data[testNPos, i]; } public String GetString(int i) { return (String)testResultset.data[testNPos, i]; } public Decimal GetDecimal(int i) { return (Decimal)testResultset.data[testNPos, i]; } public DateTime GetDateTime(int i) { return (DateTime)testResultset.data[testNPos, i]; } public IDataReader GetData(int i) { throw new NotSupportedException("GetData not supported."); } public bool IsDBNull(int i) { return testResultset.data[testNPos, i] == DBNull.Value; } private int _cultureAwareCompare(string strA, string strB) { return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, ompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | ompareOptions.IgnoreCase); } } } * IgnoreKanaType Specifies that the string comparison must ignore the Kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds in the Japanese language. Summary In this article we had a discussion about the DataSet and its role in data-oriented applications. The DataSet is main one of the main components and it is important to understand to DataAdapter, DataTable, DataView, DataGrid and other objects in ADO.NET. Finally we create an example, which it has several functionality about DataSet

and its relations with other ADO.NET classes. Next article we will discuss about multiple data tables and it will give us more idea on complex, advanced DataSets.

DataView in C#
ADO.NET DataView Control A major function of the DataView is to allow data binding on both Windows Forms and Web Forms. Additionally, a DataView can be customized to present a subset of data from the DataTable. This capability allows you to have two controls bound to the same DataTable, but showing different versions of the data. For example, one control may be bound to a DataView showing all of the rows in the table, while a second may be configured to display only the rows that have been deleted from the DataTable. The DataTable also has a DefaultView property which returns the default DataView for the table. For example, if you wish to create a custom view on the table, set the RowFilter on the DataView returned by the DefaultView. A DataView object serves a similar purpose to views in the SQL context. Both are ways to select a subset of the columns and rows in a table. In SQL Server, it is possible to create a view based on the result of almost any query, but a DataView in ADO.NET is limited to operation on one table only. However, unlike views in some versions of SQL Server, a DataView can be sorted into a given order. The DataViewManager and the DataViewSetting classes do allow multiple table views. A DataView enables you to create different views of the data stored in a DataTable, a capability that is often used in data-binding applications. Using a DataView, you can expose the data in a table with different sort orders, and you can filter the data by row state or based on a filter expression. A DataView provides a dynamic view of data whose content, ordering, and membership reflect changes to the underlying DataTable as they occur. This is different from the Select method of the DataTable, which returns a DataRow array from a table per a particular filter and/or sort order and whose content reflects changes to the underlying table, but whose membership and ordering remain static. The dynamic capabilities of the DataView make it ideal for data-binding applications. A DataView provides you with a dynamic view of a single set of data to which you can apply different sorting and filtering criteria, similar to the view provided by a database. However, a DataView differs significantly from a database view in that the DataView cannot be treated as a table and cannot provide a view of joined tables. You also cannot exclude columns that exist in the source table, nor can you append columns, such as computational columns, that do not exist in the source table. You use a DataViewManager to manage view settings for all the tables in a DataSet. The DataViewManager provides you with a convenient way to manage default view settings for each table. When binding a control to more than one table of a DataSet, binding to a DataViewManager is the ideal choice. To create a filtered and sorted view of data, set the RowFilter and Sort properties. Then use the Item property to return a single DataRowView. You can also add and delete from the set of rows using the AddNew and Delete methods. When you use those methods, the RowStateFilter property can set to specify that only deleted rows or new rows be displayed by the DataView. public class DataView : MarshalByValueComponent, IBindingList,IList, ICollection, IEnumerable, ITypedList, ISupportInitialize The following example creates a single DataTable with one column and five rows. Two DataView objects are created and the RowStateFilter is set on each to show different views of the table data. The values are then printed. private void DemonstrateDataView() { // Create one DataTable with one column.

DataTable myTable = new DataTable("myTable"); DataColumn colItem = new DataColumn("item",Type.GetType("System.String")); myTable.Columns.Add(colItem); // Add five items. DataRow NewRow; for(int i = 0; i <5; i++) { NewRow = myTable.NewRow(); NewRow["item"] = "Item " + i; myTable.Rows.Add(NewRow); } // Change the values in the table. myTable.Rows[0]["item"]="cat"; myTable.Rows[1]["item"] = "dog"; myTable.AcceptChanges(); // Create two DataView objects with the same table. DataView firstView = new DataView(myTable); DataView secondView = new DataView(myTable); // Print current table values. PrintTableOrView(myTable,"Current Values in Table"); // Set first DataView to show only modified versions of original rows. firstView.RowStateFilter=DataViewRowState.ModifiedOriginal ; // Print values. PrintTableOrView(firstView,"First DataView: ModifiedOriginal"); // Add one New row to the second view. DataRowView myDataRowView; myDataRowView=secondView.AddNew(); myDataRowView["item"] = "fish"; // Set second DataView to show modified versions of current rows, or New rows. secondView.RowStateFilter=DataViewRowState.ModifiedCurrent | DataViewRowState.Added; // Print modified and Added rows. PrintTableOrView(secondView, "Second DataView: ModifiedCurrent | Added"); } private void PrintTableOrView(DataTable t, string label) { // This function prints values in the table or DataView. Console.WriteLine("\n" + label); for(int i = 0; i<t.Rows.Count;i++) { Console.WriteLine("\t" + t.Rows[i]["item"]); } Console.WriteLine(); } private void PrintTableOrView(DataView dv, string label) { // This overload prints values in the table or DataView. Console.WriteLine("\n" + label); for(int i = 0; i<dv.Count;i++) { Console.WriteLine("\t" + dv[i]["item"]); } Console.WriteLine(); } How we can create a DataView? There are two ways to create a DataView. You can use the DataView constructor, or you

can create a reference to the DefaultView property of the DataTable. The DataView constructor can be empty, or will also take either a DataTable as a single argument, or a DataTable along with filter criteria, sort criteria, and a row state filter. For more information about the additional arguments available for use with the DataView, see Sorting and Filtering Data Using a DataView. Because the index for a DataView is built both when the DataView is created, and when any of the Sort, RowFilter, or RowStateFilter properties are modified, you will achieve best performance by supplying any initial sort order or filtering criteria as constructor arguments when you create the DataView. Creating a DataView without specifying sort or filter criteria and then setting the Sort, RowFilter, or RowStateFilter properties later results in the index being built at least twice: once when the DataView is created, and again when any of the sort or filter properties are modified. Note that if you create a DataView using the constructor that does not take any arguments, you will not be able to use the DataView until you have set the Table property. The following code example demonstrates how to create a DataView using the DataView constructor. A RowFilter, Sort column, and DataViewRowState are supplied along with the DataTable. DataView custDV = new DataView(customerDS.Tables["Customers"], "Country = 'USA'", "ContactName", DataViewRowState.CurrentRows); DataView custDV = customerDS.Tables["Customers"].DefaultView; Sorting and Filtering Data Using a DataView The DataView provides several capabilities for sorting and filtering data in a DataTable. Using the Sort property, you can specify single or multiple column sort orders and include ASC (ascending) and DESC (descending) parameters. You can use the ApplyDefaultSort property to automatically create a sort order, in ascending order, based on the primary key column or columns of the table. ApplyDefaultSort only applies when the Sort property is a null reference or an empty string, and when the table has a primary key defined. Using the RowFilter property, you can specify subsets of rows based on their column values. For details about valid expressions for the RowFilter property, see the reference information for the Expression property of the DataColumn class. If you want to return the results of a particular query on the data, as opposed to providing a dynamic view of a subset of the data, to achieve best performance use the Find or FindRows methods of the DataView rather than setting the RowFilter property. Setting the RowFilter property causes the index for the data to be rebuilt, adding overhead to your application, and decreasing performance. The RowFilter property is best used in a data-bound application where a bound control displays filtered results. The Find and FindRows methods leverage the current index without requiring the index to be rebuilt. Using the RowStateFilter property, you can specify which row versions to view. The DataView implicitly manages which row version to expose depending upon the RowState of the underlying row. For example, if the RowStateFilter is set to DataViewRowState.Deleted, the DataView will expose the Original row version of all Deleted rows because there is no Current row version. You can determine which row version of a row is being exposed using the RowVersion property of the DataRowView. The following table shows the options for DataViewRowState. DataViewRowState Description CurrentRows - The Current row version of all Unchanged, Added, and Modified rows. This is the default. Added - The Current row version of all Added rows. Deleted - The Original row version of all Deleted rows. ModifiedCurrent - The Current row version of all Modified rows. ModifiedOriginal - The Original row version of all Modified rows.

None - No rows. OriginalRows - The Original row version of all Unchanged, Modified, and Deleted rows. Unchanged - The Current row version of all Unchanged rows.

The following code example creates a view that shows all the products where the units in stock is less than or equal to the reorder level, sorted first by supplier ID and then by product name. DataView prodView = new DataView(prodDS.Tables["Products"], "UnitsInStock <= ReorderLevel", "SupplierID, ProductName", DataViewRowState.CurrentRows); Additional words to DataGrid A DataGrid control is a control that is displays ADO.NET data in a scrollable grid. The System.Windows.Forms.DataGrid (windows form) displays web-like links to child tables. You can click on a link to navigate to the child table. When a child table is displayed, a back button appears in the caption that can be clicked to navigate back to the parent table. The data from the parent rows is displayed below the caption and above the column headers. You can hide the parent row information by clicking the button to the right of the back button. To display a table in the System.Windows.Forms.DataGrid at run time, use the SetDataBinding method to set the DataSource and DataMember properties to a valid data source. The following data sources are valid: A DataTable A DataView A DataSet A DataViewManager A single dimension array Any component that implements the IListSource interface Any component that implements the IList interface

Data sources are further managed by BindingManagerBase objects. For each table in a data source, a BindingManagerBase can be returned from the form's BindingContext. For example, you can determine the number of rows contained by a data source by returning the associated BindingManagerBase object's Count Property. To validate data, use the underlying objects that represent data and their events. For example, if the data comes from a DataTable in a DataSet, use the ColumnChanging and RowChanging events. Note Because the number of columns can be customized (by adding or deleting members of the GridColumnStylesCollection) and the rows may be sorted by column, the RowNumber and ColumnNumber property values cannot be guaranteed to correspond to DataRow and DataColumn indexes in a DataTable. Therefore you should avoid using those properties in the Validating event to validate data. To determine which cell is selected, use the CurrentCell property. Change the value of any cell by using the Item property, which can take both the row and column indexes of the cell, or a single DataGridCell. Monitor the CurrentCellChanged event to detect when the user selects another cell. To determine which part of the control the user clicked, use

the HitTest method in the MouseDown event. The HitTest method returns a DataGrid.HitTestInfo object, which contains the row and column of a clicked area. To manage the appearance of the control at run time, several properties for setting the color and caption attributes are available, including the CaptionForeColor, CaptionBackColor, CaptionFont, and so on. The appearance of the displayed grid (or grids) can be further modified by creating DataGridTableStyle objects and adding them to the GridTableStylesCollection, which is accessed through the TableStyles property. For example, if the DataSource is set to a DataSet containing three DataTable objects, you can add three DataGridTableStyle objects to the collection, one for each table. To synchronize each DataGridTableStyle object with a DataTable, set the MappingName of the DataGridTableStyle to the TableName of the DataTable. To create a customized view of a table, create a collection of DataGridColumnStyle objects, and set each column's MappingName to the ColumnName of a column that you want to show in the grid. To hide a column, set its MappingName to something other than a valid ColumnName. For each DataGridTableStyle, you can set color and caption attributes that override the settings for the System.Windows.Forms.DataGrid control. However, if those properties are not set, the settings for the control are used by default. The following properties can be overridden by DataGridTableStyle properties: AllowSorting AlternatingBackColor BackColor ColumnHeadersVisible ForeColor GridLineColor GridLineStyle HeaderBackColor HeaderFont HeaderForeColor LinkColor PreferredColumnWidth PreferredRowHeight ReadOnly RowHeadersVisible RowHeaderWidth SelectionBackColor SelectionForeColor

To customize the appearance of individual columns, add DataGridColumnStyle objects to the GridColumnStylesCollection, which is accessed through the GridColumnStyles property of each DataGridTableStyle. To synchronize each DataGridColumnStyle with a DataColumn in the DataTable, set the MappingName to the ColumnName of a DataColumn. When constructing a DataGridColumnStyle, you can also set a formatting string that specifies how the column displays data. For example, you can specify that the column use a short-date format to display dates contained in the table. Please pay attention to you need always create DataGridColumnStyle objects and add them to the GridColumnStylesCollection before adding DataGridTableStyle objects to the GridTableStylesCollection. When you add an empty DataGridTableStyle to the collection, DataGridColumnStyle objects are automatically generated for you. Consequently, an exception will be thrown if you try to add new DataGridColumnStyle objects with

duplicate MappingName values to the GridColumnStylesCollection. The following example creates a Windows form, a DataSet containing two DataTable objects, and a DataRelation that relates the two tables. To display the data, a System.Windows.Forms.DataGrid control is then bound to the DataSet through the SetDataBinding method. A button on the form changes the appearance of the grid by creating two DataGridTableStyle objects and setting the MappingName of each object to a TableName of one of the DataTable objects. The example also contains code in the MouseUp event that uses the HitTest method to print the column, row, and part of the grid that has been clicked. using System; using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; public class Form1 : System.Windows.Forms.Form { private System.ComponentModel.Container components; private Button button1; private Button button2; private DataGrid myDataGrid; private DataSet myDataSet; private bool TablesAlreadyAdded; public Form1() { // Required for Windows Form Designer support. InitializeComponent(); // Call SetUp to bind the controls. SetUp(); } protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose();} } base.Dispose( disposing ); } private void InitializeComponent() { // Create the form and its controls. this.components = new System.ComponentModel.Container(); this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.myDataGrid = new DataGrid(); this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.Text = "DataGrid Control Sample"; this.ClientSize = new System.Drawing.Size(450, 330);

button1.Location = new Point(24, 16); button1.Size = new System.Drawing.Size(120, 24); button1.Text = "Change Appearance"; button1.Click+=new System.EventHandler(button1_Click); button2.Location = new Point(150, 16); button2.Size = new System.Drawing.Size(120, 24); button2.Text = "Get Binding Manager"; button2.Click+=new System.EventHandler(button2_Click); myDataGrid.Location = new Point(24, 50); myDataGrid.Size = new Size(300, 200); myDataGrid.CaptionText = "Microsoft DataGrid Control"; myDataGrid.MouseUp += new MouseEventHandler(Grid_MouseUp); this.Controls.Add(button1); this.Controls.Add(button2); this.Controls.Add(myDataGrid); } public static void Main() Application.Run(new Form1()); } private void SetUp() { // Create a DataSet with two tables and one relation. MakeDataSet(); /* Bind the DataGrid to the DataSet. The dataMember specifies that the Customers table should be displayed.*/ myDataGrid.SetDataBinding(myDataSet, "Customers"); } protected void button1_Click(object sender, System.EventArgs e) { if(TablesAlreadyAdded) return;AddCustomDataTableStyle(); } private void AddCustomDataTableStyle() { DataGridTableStyle ts1 = new DataGridTableStyle(); ts1.MappingName = "Customers"; // Set other properties. ts1.AlternatingBackColor = Color.LightGray; /* Add a GridColumnStyle and set its MappingName to the name of a DataColumn in the DataTable. Set the HeaderText and Width properties. */ DataGridColumnStyle boolCol = new DataGridBoolColumn(); boolCol.MappingName = "Current"; boolCol.HeaderText = "IsCurrent Customer"; boolCol.Width = 150; ts1.GridColumnStyles.Add(boolCol);// Add a second column style. DataGridColumnStyle TextCol = new DataGridTextBoxColumn(); TextCol.MappingName = "custName"; TextCol.HeaderText = "Customer Name"; TextCol.Width = 250;ts1.GridColumnStyles.Add(TextCol); // Create the second table style with columns.

DataGridTableStyle ts2 = new DataGridTableStyle(); ts2.MappingName = "Orders"; // Set other properties. ts2.AlternatingBackColor = Color.LightBlue; // Create new ColumnStyle objects DataGridColumnStyle cOrderDate = new DataGridTextBoxColumn(); cOrderDate.MappingName = "OrderDate"; cOrderDate.HeaderText = "Order Date"; cOrderDate.Width = 100; ts2.GridColumnStyles.Add(cOrderDate); /* Use a PropertyDescriptor to create a formatted column. First get the PropertyDescriptorCollection for the data source and data member. */ PropertyDescriptorCollection pcol = this.BindingContext [myDataSet, "Customers.custToOrders"].GetItemProperties(); /* Create a formatted column using a PropertyDescriptor. The formatting character "c" specifies a currency format. */ DataGridColumnStyle csOrderAmount = new DataGridTextBoxColumn(pcol ["OrderAmount"], "c", true); csOrderAmount.MappingName = "OrderAmount"; csOrderAmount.HeaderText = "Total"; csOrderAmount.Width = 100; ts2.GridColumnStyles.Add(csOrderAmount); /* Add the DataGridTableStyle instances to the GridTableStylesCollection. */myDataGrid.TableStyles.Add(ts1); myDataGrid.TableStyles.Add(ts2); // Sets the TablesAlreadyAdded to true so this doesn't happen again. TablesAlreadyAdded=true; } protected void button2_Click(object sender, System.EventArgs e) { BindingManagerBase bmGrid; bmGrid = BindingContext[myDataSet, "Customers"]; MessageBox.Show("Current BindingManager Position: " + bmGrid.Position); } private void Grid_MouseUp(object sender, MouseEventArgs e) { // Create a HitTestInfo object using the HitTest method. // Get the DataGrid by casting sender. DataGrid myGrid = (DataGrid)sender; DataGrid.HitTestInfo myHitInfo = myGrid.HitTest(e.X, e.Y); Console.WriteLine(myHitInfo); Console.WriteLine(myHitInfo.Type); Console.WriteLine(myHitInfo.Row); Console.WriteLine(myHitInfo.Column); } // Create a DataSet with two tables and populate it. private void MakeDataSet()

{ // Create a DataSet. myDataSet = new DataSet("myDataSet"); // Create two DataTables. DataTable tCust = new DataTable("Customers"); DataTable tOrders = new DataTable("Orders");// Create two columns, and add them to the first table. DataColumn cCustID = new DataColumn("CustID", typeof(int)); DataColumn cCustName = new DataColumn("CustName"); DataColumn cCurrent = new DataColumn("Current", typeof(bool)); tCust.Columns.Add(cCustID); tCust.Columns.Add(cCustName); tCust.Columns.Add(cCurrent);// Create three columns, and add them to the second table. DataColumn cID = new DataColumn("CustID", typeof(int)); DataColumn cOrderDate = new DataColumn("orderDate",typeof(DateTime)); DataColumn cOrderAmount = new DataColumn("OrderAmount", typeof(decimal)); tOrders.Columns.Add(cOrderAmount); tOrders.Columns.Add(cID); tOrders.Columns.Add(cOrderDate); // Add the tables to the DataSet. myDataSet.Tables.Add(tCust); myDataSet.Tables.Add(tOrders); // Create a DataRelation, and add it to the DataSet. DataRelation dr = new DataRelation ("custToOrders", cCustID , cID); myDataSet.Relations.Add(dr); /* Populates the tables. For each customer and order, creates two DataRow variables. */ DataRow newRow1; DataRow newRow2; // Create three customers in the Customers Table. for(int i = 1; i < 4; i++) { newRow1 = tCust.NewRow(); newRow1["custID"] = i; // Add the row to the Customers table. tCust.Rows.Add(newRow1); } // Give each customer a distinct name. tCust.Rows[0]["custName"] = "Alpha"; tCust.Rows[1]["custName"] = "Beta"; tCust.Rows[2]["custName"] = "Omega";// Give the Current column a value. tCust.Rows[0]["Current"] = true; tCust.Rows[1]["Current"] = true; tCust.Rows[2]["Current"] = false; // For each customer, create five rows in the Orders table. for(int i = 1; i < 4; i++) {

for(int j = 1; j < 6; j++) { newRow2 = tOrders.NewRow(); newRow2["CustID"]= i; newRow2["orderDate"]= new DateTime(2001, i, j * 2); newRow2["OrderAmount"] = i * 10 + j * .1; // Add the row to the Orders table. tOrders.Rows.Add(newRow2); } } } } Editing with DataGridTextBox and DataGridTextColumn The DataGridTextBox and the DataGridTextBoxColumn work together to allow users to directly edit values in a DataGrid control column. The DataGridTextBoxColumn derives from DataGridColumnStyle, and is designed to host the DataGridTextBox, which derives from the TextBox control. In addition to the properties, events, and methods of the base control, you can call the KeyPress and KeyDown events with the OnKeyPress and OnMouseDown methods. private void GetDataGridTextBox() { // Gets the DataGridTextBoxColumn from the DataGrid control.DataGridTextBoxColumn myTextBoxColumn; // Assumes the CompanyName column is a DataGridTextBoxColumn. myTextBoxColumn = (DataGridTextBoxColumn)dataGrid1. TableStyles[0].GridColumnStyles["CompanyName"]; // Gets the DataGridTextBox for the column. DataGridTextBox myGridTextBox; myGridTextBox = (DataGridTextBox) myTextBoxColumn.TextBox; } The DataGridTextBoxColumn class derives from the abstract (MustInherit in Visual Basic) class DataGridColumnStyle. At run time, the DataGridTextBoxColumn hosts a DataGridTextBox control that allows users to edit text. Special properties added to the class include Format, and HideEditBox. These properties allow you to access the hosted DataGridTextBox control and its attributes, and set the format for displaying values.

If the data source is a DataTable containing DataColumn objects, the DataType property of the DataColumn should be set to a data type that can logically be edited in a text box control. The following data types are automatically associated with a DataGridTextBoxColumn: Byte, DateTime, Decimal, Double, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, and String. private void AddColumn() { DataTable myTable= new DataTable();

// Add a new DataColumn to the DataTable. DataColumn myColumn = new DataColumn("myTextBoxColumn"); myColumn.DataType = System.Type.GetType("System.String"); myColumn.DefaultValue="default string"; myTable.Columns.Add(myColumn); // Get the CurrencyManager for the DataTable. CurrencyManager cm = (CurrencyManager)this.BindingContext[myTable]; // Use the CurrencyManager to get the PropertyDescriptor for the // new column. PropertyDescriptor pd = cm.GetItemProperties()["myTextBoxColumn"]; DataGridTextBoxColumn myColumnTextColumn; // Create the DataGridTextBoxColumn with the PropertyDescriptor. myColumnTextColumn = new DataGridTextBoxColumn(pd); // Add the new DataGridColumn to the GridColumnsCollection. dataGrid1.DataSource= myTable; dataGrid1.TableStyles.Add(new DataGridTableStyle()); dataGrid1.TableStyles[0].GridColumnStyles.Add(myColumnTextColumn); } A Key Class in ADO.NET: DataReader The DataReader object is used for accessing data from the data store and is one of the two mechanisms that ADO.NET provides. As we will remember DataReader object provides a read only, forward only, high performance mechanism to retrieve data from a data store as a data stream, while staying connected with the data source. The DataReader is restricted but highly optimized. The .NET framework provides data providers for SQL Server native OLE DB providers and native ODBC drivers: SqlDataReader OleDbDataReader OdbcDataReader

You can use the ADO.NET DataReader to retrieve a read-only, forward-only stream of data from a database. Using the DataReader can increase application performance and reduce system overhead because only one row at a time is ever in memory. After creating an instance of the Command object, you create a DataReader by calling Command.ExecuteReader to retrieve rows from a data source, as shown in the following example. SqlDataReader myReader = myCommand.ExecuteReader(); You use the Read method of the DataReader object to obtain a row from the results of the query. You can access each column of the returned row by passing the name or ordinal reference of the column to the DataReader. However, for best performance, the DataReader provides a series of methods that allow you to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). For a list of typed accessor methods, see the OleDbDataReader Class and the SqlDataReader Class. Using the typed accessor methods when the underlying data type is known will reduce the amount of type conversion required when retrieving the column value.

The following code example iterates through a DataReader object, and returns two columns from each row. while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); myReader.Close(); The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory. You should always call the Close method when you have finished using the DataReader object. If your Command contains output parameters or return values, they will not be available until the DataReader is closed. Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. You will not be able to execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed. Multiple Result Sets If multiple result sets are returned, the DataReader provides the NextResult method to iterate through the result sets in order, as shown in the following code example. SqlCommand myCMD = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories;" + "SELECT EmployeeID, LastName FROM Employees", nwindConn); nwindConn.Open(); SqlDataReader myReader = myCMD.ExecuteReader(); do { Console.WriteLine("\t{0}\t{1}", myReader.GetName(0), myReader.GetName(1)); while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); } while (myReader.NextResult()); myReader.Close(); nwindConn.Close(); The DataReader implementation must provide two basic capabilities: forward-only access over one or more of the resultsets obtained by executing a Command, and access to the column values within each row. Data types from your data source will be stored in your .NET-based application as .NET Framework types. Your DataReader implementation will also provide strongly typed accessor methods for your DataReader that return column values as .NET Framework types. Examples of a strongly typed accessor would be GetInt32, GetString, and so on. If your .NET data provider has proprietary types that cannot adequately be exposed as .NET Framework types, you may extend the interfaces to support proprietary types, then add typed accessors for your DataReader that return proprietary types as well. For example, you can add GetMyStructure, GetMyTimeStamp, and so on. An example of this is the SQL Server .NET Data Provider, which exposes proprietary types using the

System.Data.SqlTypes Namespace. The SqlDataReader then exposes those types as SqlTypes using strongly typed accessor methods. For example: GetSqlBinary, GetSqlDateTime, GetSqlDecimal, and so on. using System; using System.Data; using System.Globalization; namespace DotNetDataProviderTemplate { public class TemplateDataReader : IDataReader { // The DataReader must always be open when returned to the user. private bool dReaderOpen = true; // Keep track of the results and position // within the resultset (starts prior to first record). private TestDataBase.TestDataBaseResultSet testResultset; private static int testSTARTPOS = -1; private int testNPos = testSTARTPOS; private TemplateConnection testconnection = null; internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset) { testResultset = resultset; } internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset, emplateConnection connection) { testResultset = resultset; testconnection = connection; } public int Depth { get { return 0; } } public bool IsClosed { get { return !dReaderOpen; } } public int RecordsAffected { get { return -1; } } public void Close() { dReaderOpen = false; } public bool NextResult() { return false; } public bool Read()

{ if (++testNPos >= testResultset.data.Length / testResultset.metaData.Length) return false; else return true; } public DataTable GetSchemaTable() { throw new NotSupportedException(); } public int FieldCount { get { return testResultset.metaData.Length; } } public String GetName(int i) { return testResultset.metaData[i].name; } public String GetDataTypeName(int i) { return testResultset.metaData[i].type.Name; } public Type GetFieldType(int i) { return testResultset.metaData[i].type; } public Object GetValue(int i) { return testResultset.data[testNPos, i]; } public int GetValues(object[] values) { for (int i = 0; i < values.Length && i < testResultset.metaData.Length; i++) { values[i] = testResultset.data[testNPos, i]; } return i; } public int GetOrdinal(string name) { for (int i = 0; i < testResultset.metaData.Length; i++) { if (0 == _cultureAwareCompare(name, testResultset.metaData[i].name)) { return i; } } throw new IndexOutOfRangeException("Could not find specified column in results"); } public object this [ int i ]

{ get { return testResultset.data[testNPos, i]; } } public object this [ String name ] { get { return this[GetOrdinal(name)]; } } public bool GetBoolean(int i) { return (bool)testResultset.data[testNPos, i]; } public byte GetByte(int i) { return (byte)testResultset.data[testNPos, i]; } public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetBytes not supported."); } public char GetChar(int i) { return (char)testResultset.data[testNPos, i]; } public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetChars not supported."); } public Guid GetGuid(int i) { return (Guid)testResultset.data[testNPos, i]; } public Int16 GetInt16(int i) { return (Int16)testResultset.data[testNPos, i]; } public Int32 GetInt32(int i) { return (Int32)testResultset.data[testNPos, i]; } public Int64 GetInt64(int i) { return (Int64)testResultset.data[testNPos, i]; } public float GetFloat(int i) { return (float)testResultset.data[testNPos, i]; } public double GetDouble(int i) { return (double)testResultset.data[testNPos, i];

} public String GetString(int i) { return (String)testResultset.data[testNPos, i]; } public Decimal GetDecimal(int i) { return (Decimal)testResultset.data[testNPos, i]; } public DateTime GetDateTime(int i) { return (DateTime)testResultset.data[testNPos, i]; } public IDataReader GetData(int i) { throw new NotSupportedException("GetData not supported."); } public bool IsDBNull(int i) { return testResultset.data[testNPos, i] == DBNull.Value; } private int _cultureAwareCompare(string strA, string strB) { return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, ompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | ompareOptions.IgnoreCase); } } } * IgnoreKanaType Specifies that the string comparison must ignore the Kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds in the Japanese language. Summary In this article we had a discussion about the DataSet and its role in data-oriented applications. The DataSet is main one of the main components and it is important to understand to DataAdapter, DataTable, DataView, DataGrid and other objects in ADO.NET. Finally we create an example, which it has several functionality about DataSet and its relations with other ADO.NET classes. Next article we will discuss about multiple data tables and it will give us more idea on complex, advanced DataSets.

DataAdapter in C#
Name of the Revolution in ADO.NET: DataAdapter How is ADO.NET like ADO? Like ADO, ADO.NET has a Connection object that we use to

manage our connection to our data source. Like ADO, ADO.NET also has a Command object. The Command object is used to submit SQL statements or to execute stored procedures. Like the ADO Command object, the ADO.NET Command object accepts parameters and supports re-executing compiled commands. Things start to get different when we look at the ADO.NET DataSet object. In many ways, the DataSet object looks like a weird amalgam of all of the old DAO objects holding tables, relations, and columns. The ADO Recordset object held a collection of records that we could scroll through. The ADO.NET DataSet can do the same but can hold several sets of records and the relationships between them. The ADO.NET DataSet is like a portable database containing tables and views along with the data description information that defines them. We can consider an ADO.NET DataSet to be an in-memory database that we hold in our application's memory space (see the sidebar, "The DataReader," for the one exception to ADO.NET's separation of client and server). Theoretical overview to DataAdapter The completely new object in the ADO.NET world is the DataAdapter. The purpose of the DataAdapter is embedded in its name: It performs the activities necessary to get the data from the data source on the server into the database that's held in the DataSet. To do that, the DataAdapter lets us specify the commands that should be carried out to retrieve and update data. In ADO, if we used a client-side Recordset, our data was disconnected from the data source. This had lots of advantages, not the least of which was that we could close our application's connection to the data source and still work with the data. This would free up the connection so that it could be used by other applications, improving our application's scalability. Disconnected Recordsets also made applications more scalable in other ways. In addition to reducing the load on the data server by reducing the number of active connections, the data server's load was also reduced because activities performed on disconnected data had no impact on the server. In order to transmit changes back to the data source, we used ADO's UpdateBatch method. The process was straightforward: We created a disconnected Recordset; we made changes to the data; we called the UpdateBatch method; and enchantment happened. If we had carefully crafted SQL statements or stored procedures, it didn't matter. UpdateBatch performed our updates any way that it saw fit. Some of Microsoft's documentation suggests that our original Recordset was recreated on the server, and the records scrolled through, reconciling the changes between the Recordset from the client and its half-sibling on the server, a very inefficient process.

The DataAdapter improves on this process. The object provides four properties that allow us to control how updates are made to the server: SelectCommand, UpdateCommand, InsertCommand, and DeleteCommand. The four properties are set to Command objects that are used when data is manipulated. For instance, when we call the DataAdapter's Fill method to retrieve data from a data source and pour it into a DataSet, the Command object in the SelectCommand property

is used. The DataAdapter is the gatekeeper that sits between our DataSet and the data source. Instead of using Command objects directly with a Connection, the DataAdapter manages our Command objects as they interact with the data source. DataAdapter.Fill Method Adds or refreshes rows in the DataSet to match those in the data source using the DataSet name, and creates a DataTable named "Table". public abstract int Fill ( DataSet dataSet; ) The Fill method retrieves rows from the data source using the SELECT statement specified by an associated SelectCommand property. The connection object associated with the SELECT statement must be valid, but it does not need to be open. If the connection is closed before Fill is called, it is opened to retrieve data, and then closed. If the connection is open before Fill is called, it remains open. The Fill operation then adds the rows to destination DataTable objects in the DataSet, creating the DataTable objects if they do not already exist. When creating DataTable objects, the Fill operation normally creates only column name metadata. However, if the MissingSchemaAction property is set to AddWithKey, appropriate primary keys, and constraints are also created. If the data adapter encounters duplicate columns while populating a DataTable, it generates names for the subsequent columns, using the pattern "columnname1", "columnname2", "columnname3", and so on. If the incoming data contains unnamed columns, they are placed in the DataSet according to the pattern "Column1", "Column2", and so on. When multiple result sets are added to the DataSet each result set is placed in a separate table. Additional result sets are named by appending integral values to the specified table name (for example, "Table", "Table1", "Table2", and so on.). Applications should use caution when using column and table names to ensure that conflicts with these naming patterns does not occur. When the SELECT statement used to populate the DataSet returns multiple results, such as a batch SQL statements, if one of the results contains an error, all subsequent results are skipped and not added to the DataSet. We can use the Fill method multiple times on the same DataTable. If a primary key exists, incoming rows are merged with matching rows that already exist. If no primary key exists, incoming rows are appended to the DataTable. Note When handling batch SQL statements that return multiple results, the implementation of FillSchema for the OLE DB .NET Data Provider retrieves schema information for only the first result. To retrieve schema information for multiple results, use Fill with the MissingSchemaAction set to AddWithKey. Populating a DataSet using DataAdapter The ADO.NET DataSet is a memory-resident representation of data that provides a

consistent relational programming model independent of the data source. The DataSet represents a complete set of data including tables, constraints, and relationships among the tables. Because the DataSet is independent of the data source, a DataSet can include data local to the application, as well as data from multiple data sources. Interaction with existing data sources is controlled through the DataAdapter. Each .NET data provider included with the .NET Framework has a DataAdapter object: the OLE DB .NET Data Provider includes an OleDbDataAdapter object and the SQL Server .NET Data Provider includes a SqlDataAdapter object. A DataAdapter is used to retrieve data from a data source and populate tables within a DataSet. The DataAdapter also resolves changes made to the DataSet back to the data source. The DataAdapter uses the Connection object of the .NET data provider to connect to a data source, and Command objects to retrieve data from and resolve changes to the data source. The SelectCommand property of the DataAdapter is a Command object that retrieves data from the data source. The InsertCommand, UpdateCommand, and DeleteCommand properties of the DataAdapter are Command objects that manage updates to the data in the data source according to modifications made to the data in the DataSet. The Fill method of the DataAdapter is used to populate a DataSet with the results of the SelectCommand of the DataAdapter. Fill takes as its arguments a DataSet to be populated, and a DataTable object, or the name of the DataTable to be filled with the rows returned from the SelectCommand. The Fill method uses the DataReader object implicitly to return the column names and types used to create the tables in the DataSet, as well as the data to populate the rows of the tables in the DataSet. Tables and columns are only created if they do not already exist; otherwise Fill uses the existing DataSet schema. Column types are created as .NET Framework types according to the tables in Mapping .Net Data Provider Data Types to .NET Framework Data Types. Primary keys are not created unless they exist in the data source and DataAdapter.MissingSchemaAction is set to MissingSchemaAction.AddWithKey. If Fill finds that a primary key exists for a table, it will overwrite data in the DataSet with data from the data source for rows where the primary key column values match those of the row returned from the data source. If no primary key is found, the data is appended to the tables in the DataSet. Fill uses any TableMappings that may exist when populating the DataSet. The following code example creates an instance of a DataAdapter that uses a Connection to the Microsoft SQL Server Northwind database and populates a DataTable in a DataSet with the list of customers. The SQL statement and Connection arguments passed to the DataAdapter constructor are used to create the SelectCommand property of the DataAdapter. SqlClient example: SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"); SqlCommand selectCMD = new SqlCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn); selectCMD.CommandTimeout = 30; SqlDataAdapter customerDA = new SqlDataAdapter();

customerDA.SelectCommand = selectCMD; nwindConn.Open(); DataSet customerDS = new DataSet(); customerDA.Fill(customerDS, "Customers"); nwindConn.Close(); OleDb Example OleDbConnection nwindConn = new OleDbConnection("Provider=SQLOLEDB;Data Source=localhost;" + "Integrated Security=SSPI;Initial Catalog=northwind"); OleDbCommand selectCMD = new OleDbCommand("SELECT CustomerID, CompanyName FROM Customers", nwindConn); selectCMD.CommandTimeout = 30; OleDbDataAdapter customerDA = new OleDbDataAdapter(); customerDA.SelectCommand = selectCMD; DataSet customerDS = new DataSet(); customerDA.Fill(customerDS, "Customers"); Note that the code does not explicitly open and close the Connection. The Fill method implicitly opens the Connection that the DataAdapter is using if it finds that the connection is not already open. If Fill opened the connection, it will also close the connection when Fill is finished. This can simplify our code when dealing with a single operation such as a Fill or an Update. However, if we are performing multiple operations that require an open connection, we can improve the performance of our application by explicitly calling the Open method of the Connection, performing the operations against the data source, then calling the Close method of the Connection. We should strive to keep connections to the data source open for a minimal amount of time to free up the resource to be used by other client applications. Multiple Result Sets If the DataAdapter encounters multiple result sets, it will create multiple tables in the DataSet. The tables will be given an incremental default name of TableN, starting with "Table" for Table0. If a table name is passed as an argument to the Fill method, the tables will be given an incremental default name of TableNameN, starting with "TableName" for TableName0. Populating a DataSet from Multiple DataAdapters Any number of DataAdapters can be used in conjunction with a DataSet. Each DataAdapter can be used to fill one or more DataTable objects and resolve updates back to the relevant data source. DataRelation and Constraint objects can be added to the DataSet locally, enabling we to relate data from multiple dissimilar data sources. For example, a DataSet can contain data from a Microsoft SQL Server database, an IBM DB2 database exposed via OLE DB, and a data source that streams XML. One or more DataAdapter objects can handle communication to each data source. The following code example populates a list of customers from the Northwind database on Microsoft SQL Server 2000, and a list of orders from the Northwind database stored

in Microsoft Access 2000. The filled tables are related with a DataRelation, and the list of customers is then displayed with the orders for that customer. SqlConnection custConn = new SqlConnection("Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind;"); SqlDataAdapter customerDA = new SqlDataAdapter("SELECT * FROM Customers", ustConn); OleDbConnection orderConn = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" + "Data Source=c:\\Program Files\\Microsoft Office\\Office\\Samples\\northwind.mdb;"); OleDbDataAdapter orderDA = new OleDbDataAdapter("SELECT * FROM Orders", orderConn); custConn.Open(); orderConn.Open(); DataSet customerDS = new DataSet(); customerDA.Fill(customerDS, "Customers"); orderDA.Fill(customerDS, "Orders"); custConn.Close(); orderConn.Close(); DataRelation custOrderRel = customerDS.Relations.Add("CustOrders", customerDS.Tables["Customers"].Columns["CustomerID"], customerDS.Tables["Orders"].Columns["CustomerID"]); foreach (DataRow pRow in customerDS.Tables["Customers"].Rows) { Console.WriteLine(pRow["CustomerID"]); foreach (DataRow cRow in pRow.GetChildRows(custOrderRel)) Console.WriteLine("\t" + cRow["OrderID"]); } SQL Server Decimal Type The DataSet stores data using .NET Framework data types. For most applications, these provide a convenient representation of data source information. However, this representation may cause a problem when the data type in the data source is a SQL Server decimal. The .NET Framework decimal data type allows a maximum of 28 significant digits, while the SQL Server decimal data type allows 38 significant digits. If the SqlDataAdapter determines, during a Fill operation, that the precision of a SQL Server decimal field is greater than 28 characters, the current row will not be added to the DataTable. Instead the FillError event will occur, which enables you to determine if a loss of precision will occur, and respond appropriately. For more information about the FillError event, see Working with DataAdapter Events. To get the SQL Server decimal value, you can also use a SqlDataReader object and call the GetSqlDecimal method. OLE DB Chapters Hierarchical rowsets, or chapters (OLE DB type DBTYPE_HCHAPTER, ADO type adChapter) can be used to fill the contents of a DataSet. When the DataAdapter encounters a chaptered column during a Fill operation, a DataTable is created for the chaptered column, and that table is filled with the columns and rows from the chapter. The table created for the chaptered column is named using both the parent table name

and the chaptered column name in the form "ParentTableNameChapteredColumnName". If a table already exists in the DataSet that matches the name of the chaptered column, the current table is filled with the chapter data. If there is no column in an existing table that matches a column found in the chapter, a new column is added. Before the tables in the DataSet are filled with the data in the chaptered columns, a relation is created between the parent and child tables of the hierarchical rowset by adding an integer column to both the parent and child table, setting the parent column to auto-increment and creating a DataRelation using the added columns from both tables. The added relation is named using the parent and child column names in the form "ParentColumnName_ChildColumnName". Note that the related column only exists in the DataSet. Subsequent fills from the data source will result in new rows being added to the tables rather than changes being merged into existing rows. Remember also that, if you use the DataAdapter.Fill overload that takes a DataTable, only that table will be filled. An auto-incrementing integer column will still be added to the table, but no child table will be created or filled, and no relation will be created. The following example uses the MSDataShape Provider to generate a chapter column of orders for each customer in a list of customers. A DataSet is then filled with the data. OleDbConnection nwindConn = new OleDbConnection("Provider=MSDataShape;Data Provider=SQLOLEDB;" + "Data Source=localhost;Integrated Security=SSPI;Initial Catalog=northwind"); OleDbDataAdapter customerDA = new OleDbDataAdapter("SHAPE {SELECT CustomerID, CompanyName FROM Customers} " + " APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " + " RELATE CustomerID TO CustomerID)", nwindConn); DataSet customerDS = new DataSet(); customerDA.Fill(customerDS, "Customers"); Updating the Database using DataAdapter and the DataSet The Update method of the DataAdapter is called to resolve changes from a DataSet back to the data source. The Update method, like the Fill method, takes as arguments an instance of a DataSet, and an optional DataTable object or DataTable name. The DataSet instance is the DataSet that contains the changes that have been made, and the DataTable identifies the table from which to retrieve the changes. When you call the Update method, the DataAdapter analyzes the changes that have been made and executes the appropriate command (INSERT, UPDATE, or DELETE). When the DataAdapter encounters a change to a DataRow, it uses the InsertCommand, UpdateCommand, or DeleteCommand to process the change. This allows you to maximize the performance of your ADO.NET application by specifying command syntax at design-time and, where possible, through the use of stored procedures. You must explicitly set the commands before calling Update. If Update will call and the appropriate command does not exist for a particular update, than an exception will be thrown (for example, no DeleteCommand for deleted rows). Command parameters can be used to specify input and output values for an SQL statement or stored procedure for each modified row in a DataSet. For more information,

see Using Parameters with a DataAdapter. If your DataTable maps to or is generated from a single database table, you can take advantage of the CommandBuilder object to automatically generate the DeleteCommand, InsertCommand, and UpdateCommand of the DataAdapter. For more information, see Automatically Generated Commands. The Update method will resolve your changes back to the data source, however other clients may have modified data at the data source since the last time you filled the DataSet. To refresh your DataSet with current data, use the DataAdapter and Fill the DataSet again. New rows will be added to the table, and updated information will be incorporated into existing rows. To handle exceptions that may occur during an Update, you can use the RowUpdated event to respond to row update errors when they occur or you can set DataAdapter.ContinueUpdateOnError to true before calling Update, and respond to the error information stored in the RowError property of a particular row when the Update is completed. Calling AcceptChanges on the DataSet, DataTable, or DataRow will cause all Original values for a DataRow to be overwritten with the Current values for the DataRow. If the field values have been modified that identify the row as unique, after calling AcceptChanges the Original values will no longer match the values in the data source. The following examples demonstrate how to perform updates to modified rows by explicitly setting the UpdateCommand of the DataAdapter. Notice that the parameter specified in the WHERE clause of the UPDATE statement is set to use the Original value of the SourceColumn. This is important, because the Current value may have been modified and may not match the value in the data source. The Original value is the value that was used to populate the DataTable from the data source. SqlDataAdapter catDA = new SqlDataAdapter("SELECT CategoryID, CategoryName FROM Categories", nwindConn); catDA.UpdateCommand = new SqlCommand("UPDATE Categories SET CategoryName = @CategoryName " + "WHERE CategoryID = @CategoryID" , nwindConn); catDA.UpdateCommand.Parameters.Add("@CategoryName", SqlDbType.NVarChar, 15, "CategoryName"); SqlParameter workParm = catDA.UpdateCommand.Parameters.Add("@CategoryID", qlDbType.Int); workParm.SourceColumn = "CategoryID"; workParm.SourceVersion = DataRowVersion.Original; DataSet catDS = new DataSet(); catDA.Fill(catDS, "Categories"); DataRow cRow = catDS.Tables["Categories"].Rows[0]; cRow["CategoryName"] = "New Category"; catDA.Update(catDS); ADO.NET DataView Control A major function of the DataView is to allow data binding on both Windows Forms and Web Forms. Additionally, a DataView can be customized to present a subset of data from the DataTable. This capability allows you to have two controls bound to the same DataTable, but showing different versions of the data. For example, one control may be bound to a DataView showing all of the rows in the table, while a second may be configured to display only the rows that have been deleted from the DataTable. The

DataTable also has a DefaultView property which returns the default DataView for the table. For example, if you wish to create a custom view on the table, set the RowFilter on the DataView returned by the DefaultView. A DataView object serves a similar purpose to views in the SQL context. Both are ways to select a subset of the columns and rows in a table. In SQL Server, it is possible to create a view based on the result of almost any query, but a DataView in ADO.NET is limited to operation on one table only. However, unlike views in some versions of SQL Server, a DataView can be sorted into a given order. The DataViewManager and the DataViewSetting classes do allow multiple table views. A DataView enables you to create different views of the data stored in a DataTable, a capability that is often used in data-binding applications. Using a DataView, you can expose the data in a table with different sort orders, and you can filter the data by row state or based on a filter expression. A DataView provides a dynamic view of data whose content, ordering, and membership reflect changes to the underlying DataTable as they occur. This is different from the Select method of the DataTable, which returns a DataRow array from a table per a particular filter and/or sort order and whose content reflects changes to the underlying table, but whose membership and ordering remain static. The dynamic capabilities of the DataView make it ideal for data-binding applications. A DataView provides you with a dynamic view of a single set of data to which you can apply different sorting and filtering criteria, similar to the view provided by a database. However, a DataView differs significantly from a database view in that the DataView cannot be treated as a table and cannot provide a view of joined tables. You also cannot exclude columns that exist in the source table, nor can you append columns, such as computational columns, that do not exist in the source table. You use a DataViewManager to manage view settings for all the tables in a DataSet. The DataViewManager provides you with a convenient way to manage default view settings for each table. When binding a control to more than one table of a DataSet, binding to a DataViewManager is the ideal choice. To create a filtered and sorted view of data, set the RowFilter and Sort properties. Then use the Item property to return a single DataRowView. You can also add and delete from the set of rows using the AddNew and Delete methods. When you use those methods, the RowStateFilter property can set to specify that only deleted rows or new rows be displayed by the DataView. public class DataView : MarshalByValueComponent, IBindingList,IList, ICollection, IEnumerable, ITypedList, ISupportInitialize The following example creates a single DataTable with one column and five rows. Two DataView objects are created and the RowStateFilter is set on each to show different views of the table data. The values are then printed. private void DemonstrateDataView() { // Create one DataTable with one column. DataTable myTable = new DataTable("myTable"); DataColumn colItem = new DataColumn("item",Type.GetType("System.String")); myTable.Columns.Add(colItem); // Add five items. DataRow NewRow; for(int i = 0; i <5; i++) { NewRow = myTable.NewRow(); NewRow["item"] = "Item " + i; myTable.Rows.Add(NewRow); } // Change the values in the table. myTable.Rows[0]["item"]="cat"; myTable.Rows[1]["item"] = "dog";

myTable.AcceptChanges(); // Create two DataView objects with the same table. DataView firstView = new DataView(myTable); DataView secondView = new DataView(myTable); // Print current table values. PrintTableOrView(myTable,"Current Values in Table"); // Set first DataView to show only modified versions of original rows. firstView.RowStateFilter=DataViewRowState.ModifiedOriginal ; // Print values. PrintTableOrView(firstView,"First DataView: ModifiedOriginal"); // Add one New row to the second view. DataRowView myDataRowView; myDataRowView=secondView.AddNew(); myDataRowView["item"] = "fish"; // Set second DataView to show modified versions of current rows, or New rows. secondView.RowStateFilter=DataViewRowState.ModifiedCurrent | DataViewRowState.Added; // Print modified and Added rows. PrintTableOrView(secondView, "Second DataView: ModifiedCurrent | Added"); } private void PrintTableOrView(DataTable t, string label) { // This function prints values in the table or DataView. Console.WriteLine("\n" + label); for(int i = 0; i<t.Rows.Count;i++) { Console.WriteLine("\t" + t.Rows[i]["item"]); } Console.WriteLine(); } private void PrintTableOrView(DataView dv, string label) { // This overload prints values in the table or DataView. Console.WriteLine("\n" + label); for(int i = 0; i<dv.Count;i++) { Console.WriteLine("\t" + dv[i]["item"]); } Console.WriteLine(); } How we can create a DataView? There are two ways to create a DataView. You can use the DataView constructor, or you can create a reference to the DefaultView property of the DataTable. The DataView constructor can be empty, or will also take either a DataTable as a single argument, or a DataTable along with filter criteria, sort criteria, and a row state filter. For more information about the additional arguments available for use with the DataView, see Sorting and Filtering Data Using a DataView. Because the index for a DataView is built both when the DataView is created, and when any of the Sort, RowFilter, or RowStateFilter properties are modified, you will achieve best performance by supplying any initial sort order or filtering criteria as constructor arguments when you create the DataView. Creating a DataView without specifying sort or filter criteria and then setting the Sort, RowFilter, or RowStateFilter properties later results in the index being built at least twice: once when the DataView is created, and again when any of the sort or filter properties are modified. Note that if you create a DataView using the constructor that does not take any arguments, you will not be able to use the DataView until you have set the Table

property. The following code example demonstrates how to create a DataView using the DataView constructor. A RowFilter, Sort column, and DataViewRowState are supplied along with the DataTable. DataView custDV = new DataView(customerDS.Tables["Customers"], "Country = 'USA'", "ContactName", DataViewRowState.CurrentRows); DataView custDV = customerDS.Tables["Customers"].DefaultView; Sorting and Filtering Data Using a DataView The DataView provides several capabilities for sorting and filtering data in a DataTable. Using the Sort property, you can specify single or multiple column sort orders and include ASC (ascending) and DESC (descending) parameters. You can use the ApplyDefaultSort property to automatically create a sort order, in ascending order, based on the primary key column or columns of the table. ApplyDefaultSort only applies when the Sort property is a null reference or an empty string, and when the table has a primary key defined. Using the RowFilter property, you can specify subsets of rows based on their column values. For details about valid expressions for the RowFilter property, see the reference information for the Expression property of the DataColumn class. If you want to return the results of a particular query on the data, as opposed to providing a dynamic view of a subset of the data, to achieve best performance use the Find or FindRows methods of the DataView rather than setting the RowFilter property. Setting the RowFilter property causes the index for the data to be rebuilt, adding overhead to your application, and decreasing performance. The RowFilter property is best used in a data-bound application where a bound control displays filtered results. The Find and FindRows methods leverage the current index without requiring the index to be rebuilt. Using the RowStateFilter property, you can specify which row versions to view. The DataView implicitly manages which row version to expose depending upon the RowState of the underlying row. For example, if the RowStateFilter is set to DataViewRowState.Deleted, the DataView will expose the Original row version of all Deleted rows because there is no Current row version. You can determine which row version of a row is being exposed using the RowVersion property of the DataRowView. The following table shows the options for DataViewRowState. DataViewRowState Description CurrentRows - The Current row version of all Unchanged, Added, and Modified rows. This is the default. Added - The Current row version of all Added rows. Deleted - The Original row version of all Deleted rows. ModifiedCurrent - The Current row version of all Modified rows. ModifiedOriginal - The Original row version of all Modified rows. None - No rows. OriginalRows - The Original row version of all Unchanged, Modified, and Deleted rows. Unchanged - The Current row version of all Unchanged rows.

The following code example creates a view that shows all the products where the units in stock is less than or equal to the reorder level, sorted first by supplier ID and then by product name. DataView prodView = new DataView(prodDS.Tables["Products"], "UnitsInStock <= ReorderLevel",

"SupplierID, ProductName", DataViewRowState.CurrentRows); Additional words to DataGrid A DataGrid control is a control that is displays ADO.NET data in a scrollable grid. The System.Windows.Forms.DataGrid (windows form) displays web-like links to child tables. You can click on a link to navigate to the child table. When a child table is displayed, a back button appears in the caption that can be clicked to navigate back to the parent table. The data from the parent rows is displayed below the caption and above the column headers. You can hide the parent row information by clicking the button to the right of the back button. To display a table in the System.Windows.Forms.DataGrid at run time, use the SetDataBinding method to set the DataSource and DataMember properties to a valid data source. The following data sources are valid: A DataTable A DataView A DataSet A DataViewManager A single dimension array Any component that implements the IListSource interface Any component that implements the IList interface

Data sources are further managed by BindingManagerBase objects. For each table in a data source, a BindingManagerBase can be returned from the form's BindingContext. For example, you can determine the number of rows contained by a data source by returning the associated BindingManagerBase object's Count Property. To validate data, use the underlying objects that represent data and their events. For example, if the data comes from a DataTable in a DataSet, use the ColumnChanging and RowChanging events. Note Because the number of columns can be customized (by adding or deleting members of the GridColumnStylesCollection) and the rows may be sorted by column, the RowNumber and ColumnNumber property values cannot be guaranteed to correspond to DataRow and DataColumn indexes in a DataTable. Therefore you should avoid using those properties in the Validating event to validate data. To determine which cell is selected, use the CurrentCell property. Change the value of any cell by using the Item property, which can take both the row and column indexes of the cell, or a single DataGridCell. Monitor the CurrentCellChanged event to detect when the user selects another cell. To determine which part of the control the user clicked, use the HitTest method in the MouseDown event. The HitTest method returns a DataGrid.HitTestInfo object, which contains the row and column of a clicked area. To manage the appearance of the control at run time, several properties for setting the color and caption attributes are available, including the CaptionForeColor, CaptionBackColor, CaptionFont, and so on. The appearance of the displayed grid (or grids) can be further modified by creating DataGridTableStyle objects and adding them to the GridTableStylesCollection, which is accessed through the TableStyles property. For example, if the DataSource is set to a DataSet containing three DataTable objects, you can add three DataGridTableStyle objects to the collection, one for each table. To synchronize each DataGridTableStyle object with a DataTable, set the MappingName of the DataGridTableStyle to the TableName of the DataTable.

To create a customized view of a table, create a collection of DataGridColumnStyle objects, and set each column's MappingName to the ColumnName of a column that you want to show in the grid. To hide a column, set its MappingName to something other than a valid ColumnName. For each DataGridTableStyle, you can set color and caption attributes that override the settings for the System.Windows.Forms.DataGrid control. However, if those properties are not set, the settings for the control are used by default. The following properties can be overridden by DataGridTableStyle properties: AllowSorting AlternatingBackColor BackColor ColumnHeadersVisible ForeColor GridLineColor GridLineStyle HeaderBackColor HeaderFont HeaderForeColor LinkColor PreferredColumnWidth PreferredRowHeight ReadOnly RowHeadersVisible RowHeaderWidth SelectionBackColor SelectionForeColor

To customize the appearance of individual columns, add DataGridColumnStyle objects to the GridColumnStylesCollection, which is accessed through the GridColumnStyles property of each DataGridTableStyle. To synchronize each DataGridColumnStyle with a DataColumn in the DataTable, set the MappingName to the ColumnName of a DataColumn. When constructing a DataGridColumnStyle, you can also set a formatting string that specifies how the column displays data. For example, you can specify that the column use a short-date format to display dates contained in the table. Please pay attention to you need always create DataGridColumnStyle objects and add them to the GridColumnStylesCollection before adding DataGridTableStyle objects to the GridTableStylesCollection. When you add an empty DataGridTableStyle to the collection, DataGridColumnStyle objects are automatically generated for you. Consequently, an exception will be thrown if you try to add new DataGridColumnStyle objects with duplicate MappingName values to the GridColumnStylesCollection. The following example creates a Windows form, a DataSet containing two DataTable objects, and a DataRelation that relates the two tables. To display the data, a System.Windows.Forms.DataGrid control is then bound to the DataSet through the SetDataBinding method. A button on the form changes the appearance of the grid by creating two DataGridTableStyle objects and setting the MappingName of each object to a TableName of one of the DataTable objects. The example also contains code in the MouseUp event that uses the HitTest method to print the column, row, and part of the grid that has been clicked. using System;

using System.ComponentModel; using System.Data; using System.Drawing; using System.Windows.Forms; public class Form1 : System.Windows.Forms.Form { private System.ComponentModel.Container components; private Button button1; private Button button2; private DataGrid myDataGrid; private DataSet myDataSet; private bool TablesAlreadyAdded; public Form1() { // Required for Windows Form Designer support. InitializeComponent(); // Call SetUp to bind the controls. SetUp(); } protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose();} } base.Dispose( disposing ); } private void InitializeComponent() { // Create the form and its controls. this.components = new System.ComponentModel.Container(); this.button1 = new System.Windows.Forms.Button(); this.button2 = new System.Windows.Forms.Button(); this.myDataGrid = new DataGrid(); this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.Text = "DataGrid Control Sample"; this.ClientSize = new System.Drawing.Size(450, 330); button1.Location = new Point(24, 16); button1.Size = new System.Drawing.Size(120, 24); button1.Text = "Change Appearance"; button1.Click+=new System.EventHandler(button1_Click); button2.Location = new Point(150, 16); button2.Size = new System.Drawing.Size(120, 24); button2.Text = "Get Binding Manager"; button2.Click+=new System.EventHandler(button2_Click); myDataGrid.Location = new Point(24, 50); myDataGrid.Size = new Size(300, 200); myDataGrid.CaptionText = "Microsoft DataGrid Control";

myDataGrid.MouseUp += new MouseEventHandler(Grid_MouseUp); this.Controls.Add(button1); this.Controls.Add(button2); this.Controls.Add(myDataGrid); } public static void Main() Application.Run(new Form1()); } private void SetUp() { // Create a DataSet with two tables and one relation. MakeDataSet(); /* Bind the DataGrid to the DataSet. The dataMember specifies that the Customers table should be displayed.*/ myDataGrid.SetDataBinding(myDataSet, "Customers"); } protected void button1_Click(object sender, System.EventArgs e) { if(TablesAlreadyAdded) return;AddCustomDataTableStyle(); } private void AddCustomDataTableStyle() { DataGridTableStyle ts1 = new DataGridTableStyle(); ts1.MappingName = "Customers"; // Set other properties. ts1.AlternatingBackColor = Color.LightGray; /* Add a GridColumnStyle and set its MappingName to the name of a DataColumn in the DataTable. Set the HeaderText and Width properties. */ DataGridColumnStyle boolCol = new DataGridBoolColumn(); boolCol.MappingName = "Current"; boolCol.HeaderText = "IsCurrent Customer"; boolCol.Width = 150; ts1.GridColumnStyles.Add(boolCol);// Add a second column style. DataGridColumnStyle TextCol = new DataGridTextBoxColumn(); TextCol.MappingName = "custName"; TextCol.HeaderText = "Customer Name"; TextCol.Width = 250;ts1.GridColumnStyles.Add(TextCol); // Create the second table style with columns. DataGridTableStyle ts2 = new DataGridTableStyle(); ts2.MappingName = "Orders"; // Set other properties. ts2.AlternatingBackColor = Color.LightBlue; // Create new ColumnStyle objects DataGridColumnStyle cOrderDate = new DataGridTextBoxColumn(); cOrderDate.MappingName = "OrderDate"; cOrderDate.HeaderText = "Order Date"; cOrderDate.Width = 100; ts2.GridColumnStyles.Add(cOrderDate);

/* Use a PropertyDescriptor to create a formatted column. First get the PropertyDescriptorCollection for the data source and data member. */ PropertyDescriptorCollection pcol = this.BindingContext [myDataSet, "Customers.custToOrders"].GetItemProperties(); /* Create a formatted column using a PropertyDescriptor. The formatting character "c" specifies a currency format. */ DataGridColumnStyle csOrderAmount = new DataGridTextBoxColumn(pcol ["OrderAmount"], "c", true); csOrderAmount.MappingName = "OrderAmount"; csOrderAmount.HeaderText = "Total"; csOrderAmount.Width = 100; ts2.GridColumnStyles.Add(csOrderAmount); /* Add the DataGridTableStyle instances to the GridTableStylesCollection. */myDataGrid.TableStyles.Add(ts1); myDataGrid.TableStyles.Add(ts2); // Sets the TablesAlreadyAdded to true so this doesn't happen again. TablesAlreadyAdded=true; } protected void button2_Click(object sender, System.EventArgs e) { BindingManagerBase bmGrid; bmGrid = BindingContext[myDataSet, "Customers"]; MessageBox.Show("Current BindingManager Position: " + bmGrid.Position); } private void Grid_MouseUp(object sender, MouseEventArgs e) { // Create a HitTestInfo object using the HitTest method. // Get the DataGrid by casting sender. DataGrid myGrid = (DataGrid)sender; DataGrid.HitTestInfo myHitInfo = myGrid.HitTest(e.X, e.Y); Console.WriteLine(myHitInfo); Console.WriteLine(myHitInfo.Type); Console.WriteLine(myHitInfo.Row); Console.WriteLine(myHitInfo.Column); } // Create a DataSet with two tables and populate it. private void MakeDataSet() { // Create a DataSet. myDataSet = new DataSet("myDataSet"); // Create two DataTables. DataTable tCust = new DataTable("Customers"); DataTable tOrders = new DataTable("Orders");// Create two columns, and add them to the first table. DataColumn cCustID = new DataColumn("CustID", typeof(int)); DataColumn cCustName = new DataColumn("CustName"); DataColumn cCurrent = new DataColumn("Current", typeof(bool));

tCust.Columns.Add(cCustID); tCust.Columns.Add(cCustName); tCust.Columns.Add(cCurrent);// Create three columns, and add them to the second table. DataColumn cID = new DataColumn("CustID", typeof(int)); DataColumn cOrderDate = new DataColumn("orderDate",typeof(DateTime)); DataColumn cOrderAmount = new DataColumn("OrderAmount", typeof(decimal)); tOrders.Columns.Add(cOrderAmount); tOrders.Columns.Add(cID); tOrders.Columns.Add(cOrderDate); // Add the tables to the DataSet. myDataSet.Tables.Add(tCust); myDataSet.Tables.Add(tOrders); // Create a DataRelation, and add it to the DataSet. DataRelation dr = new DataRelation ("custToOrders", cCustID , cID); myDataSet.Relations.Add(dr); /* Populates the tables. For each customer and order, creates two DataRow variables. */ DataRow newRow1; DataRow newRow2; // Create three customers in the Customers Table. for(int i = 1; i < 4; i++) { newRow1 = tCust.NewRow(); newRow1["custID"] = i; // Add the row to the Customers table. tCust.Rows.Add(newRow1); } // Give each customer a distinct name. tCust.Rows[0]["custName"] = "Alpha"; tCust.Rows[1]["custName"] = "Beta"; tCust.Rows[2]["custName"] = "Omega";// Give the Current column a value. tCust.Rows[0]["Current"] = true; tCust.Rows[1]["Current"] = true; tCust.Rows[2]["Current"] = false; // For each customer, create five rows in the Orders table. for(int i = 1; i < 4; i++) { for(int j = 1; j < 6; j++) { newRow2 = tOrders.NewRow(); newRow2["CustID"]= i; newRow2["orderDate"]= new DateTime(2001, i, j * 2); newRow2["OrderAmount"] = i * 10 + j * .1; // Add the row to the Orders table. tOrders.Rows.Add(newRow2); } } }

} Editing with DataGridTextBox and DataGridTextColumn The DataGridTextBox and the DataGridTextBoxColumn work together to allow users to directly edit values in a DataGrid control column. The DataGridTextBoxColumn derives from DataGridColumnStyle, and is designed to host the DataGridTextBox, which derives from the TextBox control. In addition to the properties, events, and methods of the base control, you can call the KeyPress and KeyDown events with the OnKeyPress and OnMouseDown methods. private void GetDataGridTextBox() { // Gets the DataGridTextBoxColumn from the DataGrid control.DataGridTextBoxColumn myTextBoxColumn; // Assumes the CompanyName column is a DataGridTextBoxColumn. myTextBoxColumn = (DataGridTextBoxColumn)dataGrid1. TableStyles[0].GridColumnStyles["CompanyName"]; // Gets the DataGridTextBox for the column. DataGridTextBox myGridTextBox; myGridTextBox = (DataGridTextBox) myTextBoxColumn.TextBox; } The DataGridTextBoxColumn class derives from the abstract (MustInherit in Visual Basic) class DataGridColumnStyle. At run time, the DataGridTextBoxColumn hosts a DataGridTextBox control that allows users to edit text. Special properties added to the class include Format, and HideEditBox. These properties allow you to access the hosted DataGridTextBox control and its attributes, and set the format for displaying values.

If the data source is a DataTable containing DataColumn objects, the DataType property of the DataColumn should be set to a data type that can logically be edited in a text box control. The following data types are automatically associated with a DataGridTextBoxColumn: Byte, DateTime, Decimal, Double, Int16, Int32, Int64, UInt16, UInt32, UInt64, Single, and String. private void AddColumn() { DataTable myTable= new DataTable(); // Add a new DataColumn to the DataTable. DataColumn myColumn = new DataColumn("myTextBoxColumn"); myColumn.DataType = System.Type.GetType("System.String"); myColumn.DefaultValue="default string"; myTable.Columns.Add(myColumn); // Get the CurrencyManager for the DataTable. CurrencyManager cm = (CurrencyManager)this.BindingContext[myTable]; // Use the CurrencyManager to get the PropertyDescriptor for the // new column. PropertyDescriptor pd = cm.GetItemProperties()["myTextBoxColumn"]; DataGridTextBoxColumn myColumnTextColumn;

// Create the DataGridTextBoxColumn with the PropertyDescriptor. myColumnTextColumn = new DataGridTextBoxColumn(pd); // Add the new DataGridColumn to the GridColumnsCollection. dataGrid1.DataSource= myTable; dataGrid1.TableStyles.Add(new DataGridTableStyle()); dataGrid1.TableStyles[0].GridColumnStyles.Add(myColumnTextColumn); } A Key Class in ADO.NET: DataReader The DataReader object is used for accessing data from the data store and is one of the two mechanisms that ADO.NET provides. As we will remember DataReader object provides a read only, forward only, high performance mechanism to retrieve data from a data store as a data stream, while staying connected with the data source. The DataReader is restricted but highly optimized. The .NET framework provides data providers for SQL Server native OLE DB providers and native ODBC drivers: SqlDataReader OleDbDataReader OdbcDataReader

You can use the ADO.NET DataReader to retrieve a read-only, forward-only stream of data from a database. Using the DataReader can increase application performance and reduce system overhead because only one row at a time is ever in memory. After creating an instance of the Command object, you create a DataReader by calling Command.ExecuteReader to retrieve rows from a data source, as shown in the following example. SqlDataReader myReader = myCommand.ExecuteReader(); You use the Read method of the DataReader object to obtain a row from the results of the query. You can access each column of the returned row by passing the name or ordinal reference of the column to the DataReader. However, for best performance, the DataReader provides a series of methods that allow you to access column values in their native data types (GetDateTime, GetDouble, GetGuid, GetInt32, and so on). For a list of typed accessor methods, see the OleDbDataReader Class and the SqlDataReader Class. Using the typed accessor methods when the underlying data type is known will reduce the amount of type conversion required when retrieving the column value. The following code example iterates through a DataReader object, and returns two columns from each row. while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); myReader.Close(); The DataReader provides an unbuffered stream of data that allows procedural logic to efficiently process results from a data source sequentially. The DataReader is a good choice when retrieving large amounts of data because the data is not cached in memory. You should always call the Close method when you have finished using the DataReader

object. If your Command contains output parameters or return values, they will not be available until the DataReader is closed. Note that while a DataReader is open, the Connection is in use exclusively by that DataReader. You will not be able to execute any commands for the Connection, including creating another DataReader, until the original DataReader is closed. Multiple Result Sets If multiple result sets are returned, the DataReader provides the NextResult method to iterate through the result sets in order, as shown in the following code example. SqlCommand myCMD = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories;" + "SELECT EmployeeID, LastName FROM Employees", nwindConn); nwindConn.Open(); SqlDataReader myReader = myCMD.ExecuteReader(); do { Console.WriteLine("\t{0}\t{1}", myReader.GetName(0), myReader.GetName(1)); while (myReader.Read()) Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1)); } while (myReader.NextResult()); myReader.Close(); nwindConn.Close(); The DataReader implementation must provide two basic capabilities: forward-only access over one or more of the resultsets obtained by executing a Command, and access to the column values within each row. Data types from your data source will be stored in your .NET-based application as .NET Framework types. Your DataReader implementation will also provide strongly typed accessor methods for your DataReader that return column values as .NET Framework types. Examples of a strongly typed accessor would be GetInt32, GetString, and so on. If your .NET data provider has proprietary types that cannot adequately be exposed as .NET Framework types, you may extend the interfaces to support proprietary types, then add typed accessors for your DataReader that return proprietary types as well. For example, you can add GetMyStructure, GetMyTimeStamp, and so on. An example of this is the SQL Server .NET Data Provider, which exposes proprietary types using the System.Data.SqlTypes Namespace. The SqlDataReader then exposes those types as SqlTypes using strongly typed accessor methods. For example: GetSqlBinary, GetSqlDateTime, GetSqlDecimal, and so on. using System; using System.Data; using System.Globalization; namespace DotNetDataProviderTemplate { public class TemplateDataReader : IDataReader {

// The DataReader must always be open when returned to the user. private bool dReaderOpen = true; // Keep track of the results and position // within the resultset (starts prior to first record). private TestDataBase.TestDataBaseResultSet testResultset; private static int testSTARTPOS = -1; private int testNPos = testSTARTPOS; private TemplateConnection testconnection = null; internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset) { testResultset = resultset; } internal TemplateDataReader(TestDataBase.TestDataBaseResultSet resultset, emplateConnection connection) { testResultset = resultset; testconnection = connection; } public int Depth { get { return 0; } } public bool IsClosed { get { return !dReaderOpen; } } public int RecordsAffected { get { return -1; } } public void Close() { dReaderOpen = false; } public bool NextResult() { return false; } public bool Read() { if (++testNPos >= testResultset.data.Length / testResultset.metaData.Length) return false; else return true; } public DataTable GetSchemaTable() { throw new NotSupportedException(); } public int FieldCount

{ get { return testResultset.metaData.Length; } } public String GetName(int i) { return testResultset.metaData[i].name; } public String GetDataTypeName(int i) { return testResultset.metaData[i].type.Name; } public Type GetFieldType(int i) { return testResultset.metaData[i].type; } public Object GetValue(int i) { return testResultset.data[testNPos, i]; } public int GetValues(object[] values) { for (int i = 0; i < values.Length && i < testResultset.metaData.Length; i++) { values[i] = testResultset.data[testNPos, i]; } return i; } public int GetOrdinal(string name) { for (int i = 0; i < testResultset.metaData.Length; i++) { if (0 == _cultureAwareCompare(name, testResultset.metaData[i].name)) { return i; } } throw new IndexOutOfRangeException("Could not find specified column in results"); } public object this [ int i ] { get { return testResultset.data[testNPos, i]; } } public object this [ String name ] { get { return this[GetOrdinal(name)]; } } public bool GetBoolean(int i) { return (bool)testResultset.data[testNPos, i]; }

public byte GetByte(int i) { return (byte)testResultset.data[testNPos, i]; } public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetBytes not supported."); } public char GetChar(int i) { return (char)testResultset.data[testNPos, i]; } public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length) { throw new NotSupportedException("GetChars not supported."); } public Guid GetGuid(int i) { return (Guid)testResultset.data[testNPos, i]; } public Int16 GetInt16(int i) { return (Int16)testResultset.data[testNPos, i]; } public Int32 GetInt32(int i) { return (Int32)testResultset.data[testNPos, i]; } public Int64 GetInt64(int i) { return (Int64)testResultset.data[testNPos, i]; } public float GetFloat(int i) { return (float)testResultset.data[testNPos, i]; } public double GetDouble(int i) { return (double)testResultset.data[testNPos, i]; } public String GetString(int i) { return (String)testResultset.data[testNPos, i]; } public Decimal GetDecimal(int i) { return (Decimal)testResultset.data[testNPos, i]; } public DateTime GetDateTime(int i) {

return (DateTime)testResultset.data[testNPos, i]; } public IDataReader GetData(int i) { throw new NotSupportedException("GetData not supported."); } public bool IsDBNull(int i) { return testResultset.data[testNPos, i] == DBNull.Value; } private int _cultureAwareCompare(string strA, string strB) { return CultureInfo.CurrentCulture.CompareInfo.Compare(strA, strB, ompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | ompareOptions.IgnoreCase); } } } * IgnoreKanaType Specifies that the string comparison must ignore the Kana type. Kana type refers to Japanese hiragana and katakana characters, which represent phonetic sounds in the Japanese language. Summary In this article we had a discussion about the DataSet and its role in data-oriented applications. The DataSet is main one of the main components and it is important to understand to DataAdapter, DataTable, DataView, DataGrid and other objects in ADO.NET. Finally we create an example, which it has several functionality about DataSet and its relations with other ADO.NET classes. Next article we will discuss about multiple data tables and it will give us more idea on complex, advanced DataSets.

Code Only Design using ADO.NET Entity Framework 4.0


This article will cover the code-only approach, which provides developers the ability to use the Entity Framework using POCO entities and without an EDMX file. This approach lets developers view code as their model. This includes topics such as 1. 2. 3. 4. Deferred or lazy loading. Complex types. Change tracking. Foreign key association support.

The EntityClient Apart from using LINQ to Entities and Entity SQL, there is one more way we can query the EDM by using EntityClient. The EntityClient provider can be used by the Entity Framework to access data. This provider uses.NET Framework data provider to access data sources, such as SQL Server. Like, the SqlClient provider for SQL Server is used by the EntityClient provider to access the SQL Server database. The key to using this provider is found in the System.Data.EntityClient namespace. Although this provider operation that are performed on conceptual model, entities are

translated into operations performed on physical sources, and returned results are translated from physical data sources into conceptual Entities back again. The EntityClient uses Entity SQL language to execute commands against an entity model. As such, the Entity Framework facilitates the communication and translation of Entity SQL into storage specific queries. Since the Entity SQL language doesn't have specific language to query database, Entity SQL works great for the EntityClient provider. Using the EntityClient is extremely similar to using other .NET data access technologies such as the SqlClient. It has got classes similar to SqlClient; EntityConnection, EntityCommand, EntityReader etc. We will see all of these classes in action. Note: Please download the database scripts as well to run the sample code. Create POCO Class (Data Project) A. Create solution called CodeOnlyDesign.sln. I am using VSTS 2010 Ultimate trail version. Add a new class library project to the solution and name it as CodeOnlyData. As of now our primary focus is on creating POCO class.

B. Make sure EF4FeatureCTP3.exe is installed on the machine. C. Once the project is created, create class call Person.cs and Add the following code to the Person class. using System; using System.Data; using System.Collections.Generic; using System.Linq; using System.Text; namespace CodeOnlyData { public class Person { public Person() { } public int PersonID { get; set; } public string FirstName { get; set; } public string MiddleName { get; set; } public string LastName { get; set; } public string Title { get; set; } public DateTime BirthDate { get; set; } public string MaritalStatus { get; set; } public string Gender { get; set; }

public string Suffix { get; set; } public string EmailAddress { get; set; } public string Phone { get; set; } public DateTime ModifiedDate { get; set; } } } Create UI Project A. We need a UI project that will consume our data project, so let's add that. From the file menu, select Add New Project. When the Add New Project dialog opens, select ASP.NET web application template, Name this project CodeOnlyUI and click OK.

B. Add the reference of System.Data.Entity.dll and Microsoft.Data.Entity.Ctp.dll to the UI project and CodeOnlyData project. Now we have to create the context and connections or any configuration. So create two classes namely, PersonContext.cs and PersonConfiguration.cs. C. Finally our solution looks like as follows

D. Coding for Context class. Open the PersonContext.cs. Add the following code. This class is our context and extends the ObjectContext. It represents the shape of our model and is the entry and tunnel to the database. We added a single constructor, which accepts an EntityConnection. This is simply a wrapper around the true database connection and the EF metadata. This connection information is passed to the constructor when a new instance of the PersonContext is instantiated. We also declare two typed entities using the IObjectSet interface, which allow us to perform create, read, update, and delete operations. Since the ObjectSet class derives from ObjectQuery, it can also work as a query object. using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Objects; using System.Data.EntityClient; using CodeOnlyData; namespace CodeOnlyUI { public class PersonContext: ObjectContext { public PersonContext(EntityConnection connection): base(connection) { DefaultContainerName = "PersonContext"; } public IObjectSet<Person> Contact { get { return base.CreateObjectSet<Person>(); } } } } E. Create the Person configuration class. This class holds the entire configuration for the Person class. In this class we define the property that is the primary key by using the IsIdentity() property. We also specify other

property facets such as MaxLength and IsRequired. Notice that this example also illustrates that you can combine the properties on a single line instead of two separate statements. This class is derived from EntityConfiguration which allows us to configure the entity properties like max length, Identity, required or optional. using System; using System.Data; using System.Collections.Generic; using System.Linq; using System.Web; using System.Data.Objects; using System.Data.EntityClient; using Microsoft.Data.Objects; using CodeOnlyData; namespace CodeOnlyUI { public class PersonConfiguration : EntityConfiguration<Person> { public PersonConfiguration() { Property(c => c.PersonID).IsIdentity(); Property(c => c.FirstName).HasMaxLength(50); Property(c => c.FirstName).IsRequired(); Property(c => c.MiddleName).HasMaxLength(50); Property(c => c.LastName).HasMaxLength(50); Property(c => c.LastName).IsRequired(); Property(c => c.Title).HasMaxLength(8); Property(c => c.Gender).IsRequired(); Property(c => c.Suffix).HasMaxLength(10); Property(c => c.EmailAddress).HasMaxLength(50); Property(c => c.Phone).HasMaxLength(25); } } } F. Now it is time to query the database using code only approach. Go to the UI project, on the default.aspx file, and add GridView and a button on the screen. Names I am leaving upto you. In my case they are going to be gvPersons and getPersons respectively. G. Add the following code in getPersons event. protected void getPersons_Click(object sender, EventArgs e) { try { SqlConnection conn = new SqlConnection(@"Data Source=BLRLXP-SCHINNA\SQLEXPRESS;Initial Catalog=CodeOnlyDataBase;Integrated Security=SSPI"); var builder = new ContextBuilder<PersonContext>(); builder.Configurations.Add(new PersonConfiguration()); var context = builder.Create(conn); gvPersons.DataSource = context.Person; gvPersons.DataBind(); } catch (Exception ex) { Response.Write(ex.Message); } }

Model-First Design using ADO.NET Entity Framework 4.0


In this article we are going to see the second most impartment part of the ADO.NET entity framework 4.0. As the first part is traditional way of developing applications like, create Database schema and then creation of entity class follows. In this approach any changes to the schema after developing the conceptual entity classes needs to modified, even though it is quite simple to update the entity class from the schema, in case of big modifications, due to business change, it is time consuming process to synchronize the UX code and the entity class code. In Model first approach, we will be creating the EDM, conceptual model, first with respect to the business, and keep evolute the EDM till it fits for the business and then generate the database schema based on the EDM. At least it makes easier to limit the huge changes. We will see the what limitations we have in this approach, everything comes with limitation. We will be learning following 1. 2. 3. 4. 5. 6. Create Empty Model. EDM Designer. Creating Entities. Creating Associations and Relationships between Entities. Generating Schema SQL and Creating Database Schema. Performing CRUD Operations on Bands Entity

Create Empty Model 1. Create a solution called ModelFirstDesign.sln. I am using ASP.NET Web application template for this sample, VSTS 2010 Ultimate trail version.

2. Add a new class library project to the solution and name it as ProjectTeam. As of now our primary focus is on creating entity class and the database for the same. 3. Add an ADO.NET Entity model item and name it as ProjectTeam.edm

4. In the wizard select the Empty model and click on finish.

EDM Designer 5. We will examine the empty mode and its tool box that helps us in creating the EDM entities, entity associations and Inheritance. Entity: Allows you to design and create an Entity. Association: Lets you create an association (or relationship) between two entities.

Inheritance: Lets you create an Inheritance relationship between two entities.

Creating Entities 6. Now we will create the entities in the model. a. Following are the entities we will be creating in the EDM.

ServiceLine: This is contains the service line details that a resource can belong to. o ProjectTeam: This entity will contain the individual team types. Like Dev, Test, DB and Support teams o ResourceDetails: This entity will contains the individual member details and which ServiceLine he/she belongs to and ProjectTeam o Brand: This entity tracks the resource brand. b. Creating individual entities. Drag an entity instance from the tool box. By default each entity should have an identity column to identity uniquely in the object cache. Try to learn about the ObjectStateManager, ObjectStateEntity and EntityState which is currently out of scope here. o

c. By selecting the Entity1 properties change the name of the Entity to ServiceLine

d. By selecting the Id property change the name to ServiceLineID. Since this id we need as primary key make sure that the following properties set

e. By right clicking on the Entity add the following scalar properties. Also repeat the
same steps for all the Entities in the table given bellow. Make sure you are not creating the for now.

ServiceLine Entity Column Name ServiceLineID Data Type Description Int32 Unique identifier The Service line name

SeviceLineName String

Band Entity Column Name BrandID BrandName Data Type Int32 String Description Unique identifier The brand name of the member

ProjectTeam Entity Column Name TeamID TeamName Data Type Int32 String Description Unique identifier Name project team

ResourceDetail Entity Column Name Data Type Description ResourceID FirstName LastName MiddleName Experience Int32 String String String Int32 Unique identifier Resource First Name Resource Last Name Resource Middle Name The resource experience

So for your model should look like bellow

Creating Associations and Relationships between Entities

f. To create the relationship with between the table. Click on the Association in the
tool box. Drag the ServiceLineID from ServiceLine to ResourceDetail entity and repeat the same for all of them.

Generating Schema SQL and Creating Database Schema Before actually we create a Database Script from the model. We will need to create an empty database where we need to create our schema. Create a database called ProjectResource in the SQL Server 2008 (which I am using is EXPRESS edition)

g. Right click on the designer and choose 'Generate Database form Model'.

h. Create a connection to the project that we created, and click next.

i.

In the next step the wizard created the DDL for the schema. Click on the finish button which will create a ProjectTeam.edmx.sql file to the project.

j.

Open the ProjectTeam.edmx.sql file examine. The file will have the following sections o Create all tables o Creating all primary key constraints o Creating all FOREIGN KEY constraints -- --------------------------------------------------- Entity Designer DDL Script for SQL Server 2005, 2008, and Azure -- --------------------------------------------------- Date Created: 07/16/2010 16:25:10 -- Generated from EDMX file: D:\3. Research\EF4\ModelFirstDesign\ProjectTeam\ProjectTeam\ProjectT eam.edmx -- -------------------------------------------------SETQUOTED_IDENTIFIER OFF; GO USE[ProjectResource]; GO IFSCHEMA_ID(N'dbo')IS NULLEXECUTE(N'CREATE SCHEMA [dbo]'); GO -- --------------------------------------------------- Dropping existing FOREIGN KEY constraints -- --------------------------------------------------- --------------------------------------------------- Dropping existing tables -- --------------------------------------------------- --------------------------------------------------- Creating all tables -- --------------------------------------------------- Creating table 'ServiceLines' CREATETABLE [dbo].[ServiceLines]( [ServiceLineId] intIDENTITY(1,1)NOT NULL, [ServiceLineName] nvarchar(max) NOT NULL ); GO -- Creating table 'ResourceDetails' CREATETABLE [dbo].[ResourceDetails]( [ResourceId] intIDENTITY(1,1)NOT NULL, [FirestName] nvarchar(max) NOT NULL, [LasteName] nvarchar(max) NOT NULL, [Experience] int NOT NULL, [MiddleName] nvarchar(max) NOT NULL, [ServiceLine_ServiceLineId]int NOT NULL, [ProjectTeam_TeamId] int NOT NULL, [Band_BandId] int NOT NULL ); GO -- Creating table 'ProjectTeams' CREATETABLE [dbo].[ProjectTeams]( [TeamId] intIDENTITY(1,1)NOT NULL, [TeamName] nvarchar(max) NOT NULL ); GO -- Creating table 'Bands' CREATETABLE [dbo].[Bands]( [BandId] intIDENTITY(1,1)NOT NULL,

[BandName] nvarchar(max) NOT NULL ); GO -- --------------------------------------------------- Creating all PRIMARY KEY constraints -- --------------------------------------------------- Creating primary key on [ServiceLineId] in table 'ServiceLines' ALTERTABLE [dbo].[ServiceLines] ADDCONSTRAINT [PK_ServiceLines] PRIMARY KEYCLUSTERED ([ServiceLineId]ASC); GO -- Creating primary key on [ResourceId] in table 'ResourceDetails' ALTERTABLE [dbo].[ResourceDetails] ADDCONSTRAINT [PK_ResourceDetails] PRIMARY KEYCLUSTERED ([ResourceId]ASC); GO -- Creating primary key on [TeamId] in table 'ProjectTeams' ALTERTABLE [dbo].[ProjectTeams] ADDCONSTRAINT [PK_ProjectTeams] PRIMARY KEYCLUSTERED ([TeamId]ASC); GO -- Creating primary key on [BandId] in table 'Bands' ALTERTABLE [dbo].[Bands] ADDCONSTRAINT [PK_Bands] PRIMARY KEYCLUSTERED ([BandId]ASC); GO -- --------------------------------------------------- Creating all FOREIGN KEY constraints -- --------------------------------------------------- Creating foreign key on [ServiceLine_ServiceLineId] in table 'ResourceDetails' ALTERTABLE [dbo].[ResourceDetails] ADDCONSTRAINT [FK_ServiceLineResourceDetail] FOREIGN KEY ([ServiceLine_ServiceLineId]) REFERENCES [dbo].[ServiceLines] ([ServiceLineId]) ON DELETENO ACTIONON UPDATENO ACTION; -- Creating non-clustered index for FOREIGN KEY 'FK_ServiceLineResourceDetail' CREATEINDEX [IX_FK_ServiceLineResourceDetail] ON[dbo].[ResourceDetails] ([ServiceLine_ServiceLineId]); GO -- Creating foreign key on [ProjectTeam_TeamId] in table 'ResourceDetails' ALTERTABLE [dbo].[ResourceDetails] ADDCONSTRAINT [FK_ProjectTeamResourceDetail] FOREIGN KEY ([ProjectTeam_TeamId]) REFERENCES [dbo].[ProjectTeams] ([TeamId]) ON DELETENO ACTIONON UPDATENO ACTION; -- Creating non-clustered index for FOREIGN KEY 'FK_ProjectTeamResourceDetail' CREATEINDEX [IX_FK_ProjectTeamResourceDetail] ON[dbo].[ResourceDetails] ([ProjectTeam_TeamId]); GO

-- Creating foreign key on [Band_BandId] in table 'ResourceDetails' ALTERTABLE [dbo].[ResourceDetails] ADDCONSTRAINT [FK_BandResourceDetail] FOREIGN KEY ([Band_BandId]) REFERENCES [dbo].[Bands] ([BandId]) ON DELETENO ACTIONON UPDATENO ACTION; -- Creating non-clustered index for FOREIGN KEY 'FK_BandResourceDetail' CREATEINDEX [IX_FK_BandResourceDetail] ON[dbo].[ResourceDetails] ([Band_BandId]); GO k. Open the file and right click on the file and click on the Connection -> Connect, which will open the SQL Server "Connect to Database Engine "window and select the server instance and click on connect.

l.

Here we need to perform two steps. First verify the syntax and execute SQL o Right click on the opened file and select Validate SQL Syntax. Make sure that syntax validation successful.

Now click on the Execute SQL.

Go back to your SQL Server database and verify the all tables are created.

One more thing that we have to confirm is that the relationships. Create a new database diagram and add all the tables to verify the same.

m. By default EDM provides only Create Operation. Select Band entity, right click and
select 'Table Mapping'notice that what is default.

Performing CRUD Operations on Bands Entity a. Create CreateBands, SelectBands, UpdateBands and DeleteBands Procedures in the Prject Resources DataBase. o CreateBands CREATE PROCEDURE CreateBands @BandName nvarchar(max) AS BEGIN BEGIN TRY BEGIN TRANSACTION; INSERT INTO ProjectResource.dbo.Bands (( [BandName] )) VALUES ( @BandName ))))) COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT > 0 BEGIN ROLLBACK TRANSACTION; END END CATCH; END GO o SelectBands CREATEPROCEDURE [dbo].[SelectBand] AS BEGIN SELECT Bands.BandId, Bands.BandName

FROM Bands END Go o UpdateBands CREATEPROCEDURE [dbo].[UpdateBands] @BandIdint, @BandNamenvarchar(max) AS BEGIN SETNOCOUNT ON; BEGIN TRY BEGIN TRANSACTION; UPDATE ProjectResource.dbo.BandsSET [BandName] = @BandName WHERE [BandId] = @BandId COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT> 0 BEGIN ROLLBACK TRANSACTION; END END CATCH; END GO o DeleteBands CREATEPROCEDURE DeleteBands @BandIDint AS BEGIN BEGINTRY BEGIN TRANSACTION; DELETE FROM ProjectResource.dbo.Bands WHERE [BandId] = @BandId COMMIT TRANSACTION; END TRY BEGIN CATCH IF @@TRANCOUNT> 0 BEGIN ROLLBACK TRANSACTION; END END CATCH; END GO b. Go back to EDM and right click on the EDM and select Update Model from Database.

c. Select the newly added stored procedures and click on finish. Go to Model bowers and expand the stored procedure node. You can see the procedures added there. Do you know? Adding SP to the EDM will not change anything to our Entities until we map them to the EDM functions!!

d. Select the Band Entity in the EDM; select the Stored Procedure Mapping by right clicking on the Bands entity. Expand the <Select Insert Function> you can notice that the SP's are available for mapping.

e. Now map the respective procedures to the Sp's. Make sure that DeleteBands BandId mapped to BandId under Property column.

f.

Notice that we don't have provision for mapping SelectBands procedure. For the same we need to create Import function. So that the SelectBands function will be

available through a method for querying. To do the same, right click on the SelectBands procedure and click on Add Import Function.

g. In the Add Import Function window set the values as follows and click on Ok. Notice that SelectBands function added under Import Function.

h. Compile the Solution.

i.

Now we will query the EDM for Bands. I have inserted some sample data from the backend.

j.

Add the following code to query the EDM. You can download the source code. Since we have created our EDM with name ProjectTeam, EDM created a class ProjectTeamContainer that derives for ObjectContext. So our context becomes ProjectTeamContainer. The Import function that we have add to our solution, SelectBands, is called from the context. privatevoid LoadBands() { var context =new ProjectTeamContainer(); var bands = context.SelectBands(); gvBandDetails.DataSource = bands; gvBandDetails.DataBind(); }

k. Add the following code to insert new Band. var context = new ProjectTeamContainer(); context.AddToBands( new Band() { BandName = "Some Band" } ); context.SaveChanges(); l. Add the following code to delete the Band. var context = new ProjectTeamContainer(); var band = (from mybands in context.SelectBands() where mybands.BandId == selectedBandId select mybands).First(); context.Bands.DeleteObject(band); context.SaveChanges(); m. Add the following code to update the bands. var context = new ProjectTeamContainer(); var band = (from mybands in context.SelectBands() where mybands.BandId == selectedBandId select mybands).First(); band.BandName = txtBandName.Text; context.SaveChanges(); Now you can try with the other entities. Thanks,

How to: Select distinct values from Dataset


Dataset is a most powerful and easy-to-use component of ADO.Net. In this section you will see how to get the distinct values from the Dataset. CODE: #region DATASET HELPER private bool ColumnEqual(object A, object B) { // Compares two values to see if they are equal. Also compares DBNULL.Value. if (A == DBNull.Value&& B == DBNull.Value) // both are DBNull.Value return true; if (A == DBNull.Value || B == DBNull.Value)// only one is BNull.Value return false; return(A.Equals(B)); // value type standard comparison } public DataTable SelectDistinct(DataTable SourceTable, stringFieldName) { // Create a Datatable datatype same as FieldName DataTable dt = new DataTable(SourceTable.TableName); dt.Columns.Add(FieldName, SourceTable.Columns[FieldName].DataType); // Loop each row & compare each value with one another // Add it to datatable if the values are mismatch objectLastValue = null; foreach (DataRowdr in SourceTable.Select("", FieldName)) { if(LastValue == null || !(ColumnEqual(LastValue,dr[FieldName]))) { LastValue = dr[FieldName]; dt.Rows.Add(new object[] { LastValue }); } } return dt; } #endregion Example: Consider the following Dataset dsOrders,

Get distinct Product from this Dataset, DataTable distinctDT = SelectDistinct(dsOrders.Tables[0], "Product"); For CashMode,

DataTable distinctDT = SelectDistinct(dsOrders.Tables[0], "CashMode"); Output:

Working with DataTable Events in ADO.NET


This article has been excerpted from book "A Programmer's Guide to ADO.NET in C#".

A DataTable represents a table of a dataset. DataTable provides many events that an application can track down (see Table 9-5).

Table 9-5. The DataTable Events EVENT ColumnChanged ColumnChanging RowChanged RowChanging RowDeleted RowDeleting DESCRIPTION This event occurs when a value of a column has been changed. This event occurs when a new value is being added to a column. This event occurs when a value of a row in the table has been changed. This event occurs when a row in a table has been changed. This event occurs when a row in a table has been deleted. This event occurs when a row is being deleted.

ColumnChangedEventHandler handles the ColumnChanged event; it's as follows:

public delegatevoid DataColumnChangeEventHandler(object sender, DataColumnChangeEventArgs e);

Where sender is the source of the event and e is DataColumnChangedEventArgs, which contains the event data.

ColumnChangingEventHandler handles the ColumnChanging Event; it's as follows:

public delegatevoid DataColumnChangeEventHandler(object sender,DataColumnChangeEventArgs e);

Where Sender is the source of the event and e is DataColumnChangingEventArgs, which contains the event data.

Similarly, to these two handlers, RowChangedEventHandler, RowChangingEventHandler, RowDeletingEventHandler, and RowDeletedEventHandler handle the RowChanged, RowChanging, RowDeleting, and RowDeleted events, respectively. Definitions of these event handlers are similar to DataColumnChangingEventHandler and DataColumnChangedEventHandler.

To test these I'll create a data table, add data rows to the table, and then update and delete rows from the table.

Listing 9-8 creates a data table, adds three columns (id, name, and address), adds data to the table, and changes the columns of the table. It also calls the ColumnChanged and ColumnChanging event handlers. You write the code for the ColumnChanged and ColumnChanging event handlers in the Column_Changed and Column_Changing methods. Specifically, you can write this code on a button-click event handler.

Listing 9-8. Writing the Column and ColumnChanged event handlers

private void ColumnChange_Click(object sender, System.EventArgs e) { DataTable custTable =new DataTable("Customers");

// add columns custTable.Columns.Add("id",typeof(int)); custTable.Columns.Add("name",typeof(string)); custTable.Columns.Add("address",typeof(string));

// Add ColumnChanging and ColumnChanged event handlers

custTable.ColumnChanging += new DataColumnChangeEventHandler(Column_Changing); custTable.ColumnChanged +=new DataColumnChangeEventHandler(Column_Changed);

// add Two rows custTable.Rows.Add(new object[] { 1, "name1", "address1" }); custTable.Rows.Add(new object[] { 2, "name2", "address2" }); custTable.AcceptChanges();

// Change the name column in all the rows foreach (DataRow row in custTable.Rows) { row["name"] = "new name"; } }

private staticvoid Column_Changed(object sender, DataColumnChangeEventArgs e) { MessageBox.Show("Column_changed Event: " + " , " + e.Row["name"] + " ," + e.Column.ColumnName +", " + e.Row["name",DataRowVersion.Original]); }

private staticvoid Column_Changing(object sender, DataColumnChangeEventArgs e) { MessageBox.Show("Column_changing Event: " + " , " + e.Row["name"] + " ," + e.Column.ColumnName +", " + e.Row["name",DataRowVersion.Original]); }

Listing 9-9 creates a data table, adds three columns (id, name, and address), adds data to the table, and changes the columns of the table. It also calls the RowChanging and RowChanged event handlers.

Listing 9-9. Writing the RowChanging and RowChanged event handlers

private void UpdateRow_Click(object sender, System.EventArgs e) { DataTable custTable =new DataTable("Customers");

// add columns custTable.Columns.Add(); custTable.Columns.Add("id",typeof(int)); custTable.Columns.Add("name",typeof(string)); custTable.Columns.Add("address",typeof(string));

// add Two rows custTable.Rows.Add(new object[] { 1, "name1","address1" }); custTable.Rows.Add( newobject[] { 2, "name2", "address2" }); custTable.AcceptChanges();

foreach (DataRow row in custTable.Rows) { row["name"] = "new name";

// Adding RowChanged and RowChanging event handlers custTable.RowChanged +=new DataRowChangeEventHandler(Row_Changed); custTable.RowChanging += new DataRowChangeEventHandler(Row_Changing); } }

private staticvoid Row_Changed (object sender, DataRowChangeEventArgs e) { MessageBox.Show("Row_Changed Event:" + e.Row["name",DataRowVersion.Original].ToString() + e.Action.ToString()); }

private staticvoid Row_Changing(object sender, DataRowChangeEventArgs e) { MessageBox.Show("Row_Changing Event:" + e.Row["name",DataRowVersion.Original].ToString() + e.Action.ToString()); }

Listing 9-10 creates a data table, adds three columns (id, name, and address), adds data to the table, and changes the columns of the table. It also calls the RowDeleting and RowDeleted event handlers.

Listing 9-10. Writing the RowDeleting and RowDeleted event handlers

privatevoid DeleteRow_Click(object sender, System.EventArgs e) { DataTable custTable =new DataTable("Customers");

// add columns custTable.Columns.Add(); custTable.Columns.Add("id",typeof(int)); custTable.Columns.Add("name",typeof(string)); custTable.Columns.Add("address",typeof(string));

// Add RowDeleting and RowDeleted events custTable.RowDeleting +=new DataRowChangeEventHandler(Row_Deleting); custTable.RowDeleted +=new DataRowChangeEventHandler(Row_Deleted);

// add Two rows custTable.Rows.Add(new object[] { 1, "name1", "address1" }); custTable.Rows.Add(newobject[] { 2, "name2", "address2" }); custTable.AcceptChanges();

//Delete all the rows foreach (DataRow row in custTable.Rows) row.Delete(); }

private staticvoid Row_Deleting(object sender, DataRowChangeEventArgs e) { MessageBox.Show("Row_ Deleting Event:" +e.Row["name",DataRowVersion.Original].ToString() +e.Action.ToString()); }

private staticvoid Row_Deleted (object sender, DataRowChangeEventArgs e) { MessageBox.Show("Row_Deleted Event:" + e.Row["name",DataRowVersion.Original].ToString() + e.Action.ToString()); }

Conclusion

Hope this article would have helped you in understanding working with DataTable Events in ADO.NET.See other articles on the website also for further reference.

Test-driven development approach for database applications


Introduction This is the fourth article of series of articles related to Test-driven development (TDD) approach in Microsoft.NET. My intention is to illustrate this approach with several realworld examples. In this article, I will show how programmers can use the test-driven development approach to test enterprise solutions and its underlying data layer which should also support transactions in order to manage persistent data and leave the database systems in correct states. The data access layer components are implemented using ADO.NET technologies. Getting started with the solution It's remarkable to say that we have to face several challenging when testing applications with a data access layer. In the first place, it takes longer to run tests associated with persistent data in a database than it does to run tests on in-memory data. Secondly, database systems ensure that persistent data is consistent with the schema definition. This consistency checking is an issue when writing tests when we want to test each business entity without having to create all the supporting entities and finally we have to create all the supporting entities just to test the individual entity. Thirdly, you should not rely on existing data on the database (it might be manipulated by other developers). Thus, for each test, you should insert into the database whatever is needed for the test, run the test, and then remove anything that was inserted before. And finally, you should not run your test in the production database. You should take a snapshot of the production database and run the test against it. As an illustrative example, we're going to develop the data access layer as a Class Library project and the underlying data access components using ADO.NET and strongly typed data set object model (see Figure 1).

Figure 1 You're going to use a very simple database schema for testing purposes. The database schema is made up of the dept and emp tables and an optional non-identifying relationship between these tables. These tables store the state of the department and employee business entities as shown in the Figure 2.

Figure 2 Now we're going to add a DataSet item to represent the underlying business entities and the logic to access the data in the database systems (see Figure 3).

Figure 3 The first step in the test-driven development approach is, of course as its name implies, the formulation of a list of tests. One important thing to keep in mind is that the list of tests is dynamic in order to add or remove tests for testing in different environments. In this case, the list test case is as follows: 1. To connect to the database. 2. To test CRUD operations for the tables. 3. To test the relationship between them. In order to implement these test cases, we have to define the strongly typed data set for the employee and department business entities (see Figure 4).

Figure 4 Now let's add test project as Class Library project (see Figure 5).

Figure 5 Then, you have to add a reference to the NUnit framework (see Figure 6) and a fixture class (see Figure 7).

Figure 6

Figure 7 Then you must also add a reference to the TDD_DataAccessLayerPkg assembly (see Figure 8).

Figure 8 If you don't want to hard code the connection string in order to be used the test library

in several environments, you have to add a configuration file with the following configuration (see Listing 1). <?xmlversion="1.0"encoding="utf-8" ?> <configuration> <configSections> </configSections> <connectionStrings> <addname="TDD_DataAccessLayerPkg.Properties.Settings.TestDBConnectionString" connectionString="Data Source=localhost;Initial Catalog=TestDB;Integrated Security=True" providerName="System.Data.SqlClient" /> </connectionStrings> </configuration> Listing 1 Once you have the configuration, and one way is to pass this external information to the application using the ConfigurationSettings class. In order to not duplicate the retrieval of the connection string from the configuration file, we need to write the underlying code to a method annotated with the SetUp Attribute which ensures that this code is called prior to each test. In order to test each persistent business entity, we need to firstly add an entity into the database, retrieve it (check that's the same entity) and then delete it after we are finished. To retrieve a particular entity from the database, we need to add a new method to the table adapter with the necessary SQL code. The SQL code for the dept table is shown in the Figure 9.

Figure 9 The SQL code for the emp table is shown in the Figure 10.

Figure 10 Now it's time to write code for the test cases (to test the CRUD operations) using the test methods TestEmployee and TestDepartment annotated with Test attribute. We also need to add helper methods which are invoked from the test cases (see Listing 2). using using using using using using using using using System; System.Collections.Generic; System.Text; System.Configuration; System.Data; System.Data.SqlClient; NUnit.Framework; TDD_DataAccessLayerPkg; TDD_DataAccessLayerPkg.DS_TestTableAdapters;

namespace TDD_DataAccessLayer_TestPkg { [TestFixture] public classDS_TestFixture { private string m_strConnString = null; [SetUp] public void GetConnectionString() { this.m_strConnString =ConfigurationManager.ConnectionStrings["TDD_DataAccessLayerPkg.Properties.Setting

s.TestDBConnectionString"].ConnectionString; } [Test] public void ConnectionIsOpen() { SqlConnection objConn =new SqlConnection(this.m_strConnString); objConn.Open(); Assert.AreEqual(ConnectionState.Open,objConn.State); objConn.Close(); } publicstatic void TestInsertEmployee(int nEmpNo,string strName, decimal dSalary, SqlConnection objConn) { DS_Test dsInstance =new DS_Test(); DS_Test.empRow objEmp = dsInstance.emp.NewempRow(); objEmp.empno = nEmpNo; objEmp.ename = strName; objEmp.salary = dSalary; dsInstance.emp.AddempRow(objEmp); empTableAdapter taEmp = newempTableAdapter(); taEmp.Connection = objConn; taEmp.Update(dsInstance); } public staticvoid TestSelectEmployee(int nEmpNo, string strName, decimal dSalary, SqlConnection objConn) { DS_Test dsInstance =new DS_Test(); empTableAdapter taEmp =new empTableAdapter(); taEmp.Connection = objConn; taEmp.FillBy(dsInstance.emp, nEmpNo); DS_Test.empRow objEmp = dsInstance.emp[0]; Assert.AreEqual(nEmpNo, objEmp.empno); Assert.AreEqual(strName, objEmp.ename); Assert.AreEqual(dSalary, objEmp.salary); } public staticvoid TestDeleteEmployee(int nEmpNo, SqlConnection objConn) { DS_Test dsInstance =new DS_Test(); empTableAdapter taEmp =new empTableAdapter(); taEmp.Connection = objConn; taEmp.FillBy(dsInstance.emp, nEmpNo); DS_Test.empRow objEmp = dsInstance.emp[0]; Assert.AreEqual(nEmpNo, objEmp.empno); objEmp.Delete(); taEmp.Update(dsInstance); } publicstatic void TestInsertDepartment(int nDeptNo,string strName, string strLocation, SqlConnection objConn) {

DS_Test dsInstance =new DS_Test(); DS_Test.deptRow objDept = dsInstance.dept.NewdeptRow(); objDept.deptno = nDeptNo; objDept.dname = strName; objDept.loc = strLocation; dsInstance.dept.AdddeptRow(objDept); deptTableAdapter taDept = newdeptTableAdapter(); taDept.Connection = objConn; taDept.Update(dsInstance); } public staticvoid TestSelectDepartment(int nDeptNo, string strName,string strLocation, SqlConnection objConn) { DS_Test dsInstance =new DS_Test(); deptTableAdapter taDept =new deptTableAdapter(); taDept.Connection = objConn; taDept.FillBy(dsInstance.dept, nDeptNo); DS_Test.deptRow objDept = dsInstance.dept[0]; Assert.AreEqual(nDeptNo, objDept.deptno); Assert.AreEqual(strName, objDept.dname); Assert.AreEqual(strLocation, objDept.loc); } public staticvoid TestDeleteDepartment(int nDeptNo, SqlConnection objConn) { DS_Test dsInstance =new DS_Test(); deptTableAdapter taDept =new deptTableAdapter(); taDept.Connection = objConn; taDept.FillBy(dsInstance.dept, nDeptNo); DS_Test.deptRow objDept = dsInstance.dept[0]; Assert.AreEqual(nDeptNo, objDept.deptno); objDept.Delete(); taDept.Update(dsInstance); } [Test] public void TestEmployee() { SqlConnection objConn =new SqlConnection(this.m_strConnString); objConn.Open(); TestInsertEmployee(7380,"John Charles",100, objConn); TestSelectEmployee(7380, "John Charles", 100, objConn); TestDeleteEmployee(7380, objConn); objConn.Close(); } [Test] public void TestDepartment() { SqlConnection objConn =new SqlConnection(this.m_strConnString); objConn.Open();

TestInsertDepartment(50,"IT", "Baltimore", objConn); TestSelectDepartment(50, "IT","Baltimore", objConn); TestDeleteDepartment(50, objConn); objConn.Close(); } } } Listing 2 Now let's test the cases using the GUI NUnit test runner. Right-click on the project and select Properties from the context menu. In the Debug tab, set GUI NUnit test runner (see Figure 11).

Figure 11 Now let's build the solution and run the test. When the GUI NUnit test runner is run for the first time, we need to load the test project (see Figure 7).

Figure 12 In the GUI NUnit test runner window, click on the Run button to start the test, and finally you can see that all the test cases has passed (see Figure 13).

Figure 13 Conclusion In this article, I've illustrated how programmers can use the test-driven development approach to implement and test database applications. Now you can apply this approach to your own business solutions.

Distributed database technologies to share data between database systems


Introduction This article is intended to illustrate the main concepts of distributed database technologies supporting the replication principles in order to share data among different database systems. Companies have multiple copies of data distributed across various autonomous sites, and we need to access to this distributed data in a particular moment as we were connected to a single database. A distributed database is a loosely-coupled connected databases spread across multiple servers. There are two methods to distribute data: distributed transactions and replication. Replication is a set of technologies that allows moving data and database objects from one database system to another one across different geographic and platforms. This

allows a user to work with a local copy of data, and then transfer the changes to one or more remote sites. This consistency is maintained by the synchronization process. There are other reasons to use replication. Availability. Replication provides another alternative to access data when one server is down. Performance. Replication provides fast, local access to shared data. Users access to the server closest geographically to them. Disconnected computing. We have a snapshot or partial copy (replica) of the data. It allows user to work with a subset of the data while they are disconnected from the central server. Later, when the connection is established, the underlying data is synchronized. You want to copy distributed data to different sites on scheduled basis. Business scenario where multiple users are executing transactions and you need to merge the data modifications and resolve potential conflicts.

SQL Server implements three type of asynchronous replication: snapshot, transactional, and merge replication. Snapshot replication makes a copy of the data to propagate the changes for the whole data set rather than individual transactions. Transaction replication allows incremental changes of data to be transferred either continuously or at specific intervals. This type of transaction is used where there is a high volume of inserts, updates and deletes intended to server-to-server (peer-to-peer) environment. Merge replication allows subscribing servers to make changes and then it propagates those changes to the publishing servers, which in turn propagates their changes to the subscribers. In order to implement the replication in SQL Server, the developers of SQL Server follows the Publisher-Subscriber model based on a metaphor from the publishing industry. In this architecture, the publisher creates the publications which comprises of several articles (in this case, database objects such as tables, views, stored procedures) and then the publications are sent to the distributor. The distributor distributes the publications through several agents whose job is to deliver the publications and the underlying articles to the subscribers. The data is synchronized initially, and then the changes are propagated from the publishers to the subscribers. Now, I'm going to explain the main components. The distributor is the main component which links the publisher and the subscriber managing the data flow. In a snapshot and transactional replication, it stores the replica as well as the metadata and job history. In a case of push subscription, the distributor runs the replication agents. In a merge replication, the distributor stores the metadata and the history of the synchronization. It runs the Snapshot agent and the Merge agent. The publisher provides data to the distributor to be replicated (the replicas). It can also manage the data changes. The subscriber stores the replicas and receives updates from the publisher. It may act as publish and republish the replicas.

Let's talk about subscriptions. There are two methods for receiving the publications. Anonymous subscription and named subscription. Anonymous subscription doesn't enable store information about the subscriber on the publisher, thus subscriber needs to keep track of changes. In named subscription, the subscriber is explicitly enabled by the publisher. There are two type of named subscription: push and pull. In push subscription, the publisher propagates the changes to the subscribers without any request of them. Changes are pushed on demand, continuously or on a scheduled basis. In pull subscription, the subscriber requests for data changes made at the publisher. Changes are pulled on demand or on a scheduled basis. In this replication architecture, we have four types of agents: Snapshot, Log Reader, Queue Reader, Distribution and Merge. The Snapshot agent is used in all the replications, specifically at the beginning of synchronizations making copies of data and schema to be published, storing the replica in the snapshot file and recording all the data about synchronization in the distribution database. It usually resides on the distributor. The Log Reader agent monitors the transaction logs of the database involved in a transaction replication (thus used by transactional replication). Then the agent copies the data changes from the publisher to the distribution database on the distributor. Then the distributor sends the data to the subscribers. The Distribution agent is used by snapshot and transactional replication is responsible to move snapshots and transactions held in the distribution database on the distributor to the subscribers. In push subscriptions, it resides on the publisher while on pull subscription this agent resides on the subscriber. The Merge agent is used for merge replication. It applies initial snapshots and then monitors for changes to be merge on the subscribers resolving update conflicts. Each database, part of a merge replication, has one Merge agent. In transactional replication you can either immediately update the messages or store them in a queue. In this case, you send the changes when the connection is available. The Queue Reader agent reads the changes from the queue and applies to the distribution database on the distributor. Configuring a Snapshot Replication using GUI In order to configure the Snapshot Replication, we need to know how it really works. First, the Snapshot agent establishes a connection between the Distributor and the Publisher (locking the tables to be published). Then, the agent generates the schema of tables and writes them to a file with the extension .sch in the snapshot folder on the Distributor. It also generates the script files for other database objects such as stored procedure, indexes, views, functions to be replicated. The Snapshot agent sends copies of data from the publication database on the Publisher to the snapshot folder on the Distributor (the lock on the publication database are released). The Distribution agent will read later the location of these files from the MSrepl_commands system table in the distribution database and send the replicate data to the subscribers.

Now let's begin to configure the Snapshot Replication using Microsoft SQL Server Management Studio. Right-click on the Local Publications node under the Replication folder and select New Publication. The New Publication Wizard appears (see Figure 1).

Figure 1. Click Next, and choose the database that contains the objects to be published, and Click Next. The next page lists several types of publications, then select the Snapshot publication (Figure 2).

Figure 2. Click Next, the next page displays a list of objects to be published (see Figure 3).

Figure 3. Click Next, the next page asks whether you want to filter the rows horizontally. Click Next, and you'll see the Snapshot Agent page. You can specified when to run this agent. In my case, I select to create a snapshot immediately, and also it should run at scheduled times (see Figure 4).

Figure 4. Click Next, and you'll see the Agent Security page and you must specify the account under which the Snapshot Agent will run. It's recommended to configure the connection to the Distributor using a domain account, such as the SQL Server agent service account (see Figure 5).

Figure 5. Finally set a name for the publication and create it. Now that we have a publication, it's time to create a subscription to this publication. Go to the SQL Server instance that wants to receive the replica data. Right-click on the Local Subscription node under the Replication tree, and select New Subscriptions option. Then the New Subscription Wizard appears (see Figure 6).

Figure 6. Click Next, and in the publication page, browse to the publisher and select the publication that you want to. Click Next, the wizard asks you for the location of the distribution agent. You can run this agent either at the Distributor (push subscription) or the Subscriber (pull subscription). I have selected the option to run the Distributor agent at the Subscriber (pull subscription) (Figure 7).

Figure 7. Click Next, and the page allows you to select the Subscriber and the underlying database. Click Next, and the Distribution Agent Security page (see Figure 8).

Figure 8. Click Next, and in the Synchronization Schedule page, you can specify the schedule of your subscription (see Figure 9).

Figure 9. Click Next, in the Initialize Subscription page, you can specify when you want to initialize the subscription. You have two options: immediately or at the first synchronization. I have selected "at the first synchronization" option. Click Next, and the publication is created. You have a replication configuration which can be customized to your own situation. Conclusion In this article, I covered the key principles and techniques to distribute data between relational database systems. After you read this article, you have a deep insight of the Microsoft technologies supporting the replication concepts. After that, you can apply these techniques to your own business scenario and achieve a strong replication configuration.

Database Table Update in a DataGridView without Writing Code


This article was written based upon Visual Studio 2008. Some of the features are new for Visual Studio 2008 and might be different in Visual Studio 2010.

This article will describe creation of a DataGridView bound to a table. The table is a Data Source. When a table is bound to a control, code is generated for you automatically by Visual Studio that uses the .Net classes to manage the data going into and coming out of the control. There is abundant opportunity to customize this, but most of the basics are done for us. First decide what database table you want to do this for. If the database is not in the list of databases in the Server Explorer, then create a connection to the database in the Server Explorer. Use "View | Server Explorer" to use the Server Explorer. You will need to use a database; either a SQL Server or an Access database will work. You can install SQL Server Express or SQL Server Compact Edition for free if you don't have SQL Server installed. Create a table if you don't already have one you want to use. Then create a C# Windows Forms application. Show the Data Sources window if it is not showing; use "Data | Show Data Sources" to show the Data Sources window. There will be a link in the Data Sources window for "Add New Data Source"; click it (or click on the "Add New Data Source" icon), and a "Data Source Configuration Wizard" will open. Select Database and then click on Next. The next page "Choose Your Data Connection" will allow you to specify the database and will create a connection string for it. A connection string provides the information that a database system needs to connect to a database. If the database already appears in the Combo Box that lists databases, then you can use that and you need not do more on this page. If the database is not yet there, then click on the New Connection button and create a connection. When the connection has been created, click Next. A dialog box might then be shown that asks if you want to copy the database to your project; the dialog box looks like:

If you have a database you want to use for development purposes, but you don't want to modify the database, you can click Yes and Visual Studio will copy the database to your project, so the original is not modified. I don't; I click No so my project uses the database in it's current location. It depends on what you are doing whether you answer Yes or No. The next dialog box will ask if you want to save the connection string to the application

configuration file; just use the defaults on that page. Click Next and a page will be shown for selecting the table to use and selecting the fields in the table to use. Select (check the checkbox for) the table you want to use; you can instead choose just specific fields, and then (by default) only those fields will show in the DataGridView. Click Next. The Data Sources window will show a TreeView with the database as the root, the table under that and the fields from the table under that. With the project's form showing in Design view, drag the table node from the Data Sources window and drop on the form. This action will create many things, including a DataSet, a DataGridView, a BindingNavigator, a BindingSource, a TableAdapter and a TableAdapterManager (see below for a description of them). Note that the table node and the field nodes in the table node, in the Data Sources window have drop-down boxes that allows customization of what is bound to the form. We will use the defaults for now, but there are significant customizations that can easily be done using the drop-down box. Build the project. If all goes well, the project will build successfully. Then execute the application. You can edit, insert and delete records; all without writing any code, except read the next section about saving the data. Saving Data When editing the table, the data is not automatically saved. You can save the data by clicking the Save icon in the navigation toolbar, but the data won't be saved automatically. You can add a little bit of code that, if the data has been changed, will prompt to save the data. First create a method to save the data. I will call the method DoSave() but you can use whatever name you want to. Then move the code from the BindingNavigator's SaveItem button click handler (probably called tableBindingNavigatorSaveItem_Click, where table is the name of the table) to the DoSave() method and replace the code in the click event handler with a call to DoSave(). So the same code will be executed when the SaveItem button is clicked as before, except the code is now in the DoSave() method. Note that the code you put in the DoSave() is exactly the same code that is in the generated code. The code you use can be exactly as it exists in the generated code; it can be moved asis. There is just three lines in the generated code that is to be moved to the DoSave(). Then add an event handler for the form's FormClosing event and add code to the event handler as indicated below. If you don't know how to add event handlers for a form, then look at the Properties for the form. Along the top is a lightning bolt icon; click it. You can view, edit, insert and delete event handlers there. private void ViewForm_FormClosing(object sender, FormClosingEventArgs e) { if (!tableDataSet.HasChanges()) return; DialogResult dr = MessageBox.Show("Wanna save?", " DatabaseUpdateWithoutCode

Sample", MessageBoxButtons.YesNo); if (dr == System.Windows.Forms.DialogResult.Yes) DoSave(); } Generated Components When the data source is created, the connection string is saved in the project property settings. You can view the property settings by going to the Solution Explorer, expanding the Properties node if it is not yet expanded, then double-clicking on "Settings.Settings". The connection string is used by the database system to determine what database to use and how to use it. The code needed to connect to the database is generated, including code to automatically connect when needed. The following six components are generated for the form. They are listed under the form in Design View. BindingSource The BindingSource object binds the data source table to the control (the DataGridView) and the BindingNavigator. The DataGridView.DataSource property is set to the BindingSource generated for the data source. The BindingSource object has many members for manipulating the table bound to the control. The BindingSource object also manages updates to the database table from the control. DataGridView The DataGridView shows a database table in rows and columns, similar to a spreadsheet and similar to the rows and columns that Microsoft Access uses. For the purposes of this article, the columns are automatically generated based on the fields selected for the data source. The rows are created from the table rows. By default, an empty row exists at the bottom that allows adding new rows to the database table. BindingNavigator The BindingNavigator control manages navigation of the data source for the control (the DataGridView). The BindingNavigator control is a toolbar that is usually at the top of the form that allows the user to easily move around in the data. DataSet The DataSet class provides an in-memory copy of the database. It does not contain the entire database; it contains DataTable members for each database table used in the program as determined by the data source and the DataTable objects contain only the fields that the program uses as determined by the data source. TableAdapter The TableAdapter and TableAdapterManager (see below) classes are not .Net classes; they exist in generated code only. The generated TableAdapter connects to the database

when needed, then either fills a DataTable or creates a DataTable with the data. The DataTable is actually an object derived from DataTable that is generated with methods and properties specific to the data source. The generated DataTable-derived object has properties for each field in the data source. TableAdapterManager The TableAdapterManager contains the TableAdapters. It is most useful in programs that have multiple TableAdapters.

Working with Oracle Databases using ADO.NET


This article has been excerpted from book "A Programmer's Guide to ADO.NET in C#".
As discussed earlier, working with Oracle databases is no different from working with SQL Server or other databases. The only difference is the connection string. You can use the OleDb or ODBC data provider to connect to an Oracle database. On this section, I'll show you both ways (OleDb and ODBC) to access Oracle 8i and 9i databases. Accessing an Oracle 8i Database Using the ODBC Data Provider To use an ODBC data provider, the first thing you need to do is add a reference to the ODBC data provider and include the using statement in your application to add the Microsoft.Data.Odbc namespace as follows: using Microsoft.Data.Odbc; After that you follow same familiar steps: creating a connection string, adding data from database to a data adapter, and filling a dataset. To test this sample application, I created a Windows application, added a DataGrid control to the form, and added the code in listing 11-5 to the Form_Load event. Listing 11-5: Accessing an Oracle database using the ODBC data adapter private void Form1_Load(object sender, System.EventArgs e) { string connString ="Driver={Oracle ODBC Driver};" + "Server=localhost;UID=system;PWD=manager;"; OdbcConnection conn = new OdbcConnection(connString); if (conn.State !=ConnectionState.Open) conn.Open(); OdbcDataAdapter da = new OdbcDataAdapter("SELECT * FROM STDTABLE", conn); DataSet ds =new DataSet("STDTABLE"); da.Fill(ds, "STDTABLE"); dataGrid1.DataSource = ds.DefaultViewManager; // Close connection if (conn.State ==ConnectionState.Open) conn.Close(); }

As you can see from listing 11-5, I created a connection with the Oracle ODBC driver with the server as localhost, the user ID as System, and the password as manager. You may want to change the user ID and password if you're using something different from those used in listing 11-5. After that I created a data adapter by selecting data from STDTABLE, created a dataset, and filled the dataset by calling the Fill method of OdbcDataAdapter. The last step was to bind the dataset to a data grid. The output of listing 11-5 looks like figure 11-37.

Figure 11-37: Data view in a data grid from an Oracle database Accessing an Oracle 8i Database Using the OleDb Data Provider If you don't have an ODBC driver for the Oracle database, OLEDB is another way to access the database. You use the Oracle provider MSDAORA (see listing 11-6). The DSN name is oracle, the user ID is system, and the password is manager. You may want to change the user ID and password if you're not using the default. I also created an instance of OleDbConnection in listing 11-6. You can add these variables either publicity or privately in your class. Listing 11-6: The connection string from the Oracle OleDb data provider string connString = "Provider=MSDAORA;DSN=oracle;" + "User ID=system;Password=manager"; OleDbConnection conn = new OleDbConnection(); Once you have the connection string, you use this string to open a connection. You work with the connection in the same way as before: creating a data adapter or command, executing commands, filling datasets, and so on. As you can see from Listing 11-7, I simple set the connection string and opened the connection. After that I used connection as I've been doing with all the other databases.

It's the same steps as creating an OleDbDataAdapter: creating a dataset, filling data from a database table STDTABLE, and binding the dataset to data grid to display the data. Listing 11-7: Viewing data from an Oracle database table private void ViewDataBtn_Click(object sender, System.EventArgs e) { // Open connection if not already open conn.ConnectionString = connString; if (conn.State !=ConnectionState.Open) conn.Open(); OleDbDataAdapter da = new OleDbDataAdapter("SELECT * FROM STDTABLE", conn); DataSet ds =new DataSet("STDTABLE"); da.Fill(ds, "STDTABLE"); dataGrid1.DataSource = ds.DefaultViewManager; // Close connection if (conn.State ==ConnectionState.Open) conn.Close(); } As you've been doing in the other samples, you can create a SQL statement and execute it against an Oracle database. As you can see from listing 1-8, I created an INSERT statement to insert data into STDTABLE with three columns (MyId, myName, and myAddress) with values and then called the OleDbCommand.ExecuteNonQuery method to execute the command. Listing 11-8: Executing an INSERT statement string sql =" "; sql = "INSERT INTO STDTABLE(MyId, myName, myAddress) " + "VALUES(1001, 'new name', 'new address')"; try { // Create Command object and Execute SQL statement OleDbCommand cmd = new OleDbCommand(sql, conn); cmd.ExecuteNonQuery(); } catch (OleDbException ae) { string strMessage =""; for (int i = 0; i < ae.Errors.Count; i++) { strMessage += ae.Errors[i].Message +" - " + ae.Errors[i].SQLState + "\n"; } MessageBox.Show(strMessage); } // Close connection if (conn.State ==ConnectionState.Open) conn.Close();

Similar to listing 11-8, you can create UDATE and DELETE commands to update and delete data from the database. Working with an Oracle 9i Database In the previous section, you saw a sample of the Oracle 8i database. In this section, I will show you how to work with Oracle 9i databases using ODBC data providers. The Oracle 9i connection string looks like this: string connString ="Driver={Oracle in OraHome90};" + "Server=localhost;UID=system;PWD=mahesh;"; Where Oracle in OraHome90 is the Oracle ODBC driver. I've used the user ID system and the password mahesh. You need to change these to your user ID and password. If you're using the default user ID and password, you can use the system.manager or scott/tiger pairs as the user ID and password. In this sample application, I'll create a database table called mytable with four columns (Id, Name, Address, and Zip) of type integer, string, string and integer, respectively. The Id column is the primary key column. To test this application, I created a Windows application and added a DataGrid control and three buttons to the form by dragging the controls from the toolbox to the form and changing the name of the buttons to Create table, Fill data, and Delete table. The Create Table button creates myTable and adds data to the table. The Fill Data button reds the table and views the data in the DataGrid control, and the Delete Table button remove the table from the database. First, I added a reference to the Microsoft.Data.Odbc namespace and then added the following variables in the beginning of my form class: //connection string for Oracle 9i string connString ="Driver={Oracle in OraHome90};" + "Server=localhost;UID=system;PWD=mahesh;"; string sql =" SELECT * FROM OraTable"; // Create a connection OdbcConnection conn = null; // Create a command OdbcCommand cmd = null; OdbcDataAdapter da = null; Now I create connection and command objects on the form load, as shown here: private void Form1_Load(object sender, System.EventArgs e) { // Create a connection and command conn = new OdbcConnection(connString); cmd = new OdbcCommand(sql, conn); } The Create table button handler creates a new table. The code of this button handler looks like listing 11-9. Listing 11-9 also creates myTable and adds data to the table.

Listing 11-9: Creating a new database table and adding data to it private void button1_Click(object sender, System.EventArgs e) { try { if (conn.State !=ConnectionState.Open) conn.Open(); string sql ="CREATE TABLE myTable" + "(Id INTEGER CONSTRAINT PkeyMyId PRIMARY KEY," + "Name CHAR(50), Address CHAR(255), Zip INTEGER)"; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); // Adding records the table sql = "INSERT INTO myTable(ID, Name, Address, Zip) "VALUES (1001, 'Mr. Galler Hall', " + " '23 Church Street, Pace City, NY', 32432 ) "; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); sql = "INSERT INTO myTable(ID, Name, Address, Zip) "VALUES (1002, 'Dr. Dex Leech', " + " '3rd Aven, President Road, NJ', 743623) "; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); sql = "INSERT INTO myTable(ID, Name, Address, Zip) "VALUES (1003, 'Lambert Mart', " + " '45 Petersburgh Ave, Jacksonville, GA', 53492) "; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); sql = "INSERT INTO myTable(ID, Name, Address, Zip) "VALUES (1004, 'Moann Texur', " + " '4th Street, Lane 3, Packville, PA', 23433) "; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); // close connection if (conn.State ==ConnectionState.Open) conn.Close(); } catch (OdbcException ae) { MessageBox.Show(ae.Message.ToString()); } } The view data button handler reads data from myTable and views it in a DataGrid control. Listing 11-10, which should look familiar, shows the View Data button-click handler. I created a data adapter, filled a DataSet using the OdbcDataAdapter's Fill method, and bound the DataSet to the DataGrid control using DataGrid.DefaultViewManager. Listing 11-10: Viewing myTable data in a DataGrid private void button2_Click(object sender, System.EventArgs e) { try "+

"+

"+

"+

{ if (conn.State !=ConnectionState.Open) conn.Open(); da = new OdbcDataAdapter("SELECT * FROM myTable", conn); DataSet ds =new DataSet("ds"); da.Fill(ds, "myTable"); dataGrid1.DataSource = ds.DefaultViewManager; // Close connection if (conn.State ==ConnectionState.Open) conn.Close(); } catch (OdbcException ae) { MessageBox.Show(ae.Message.ToString()); } } The Delete table button handler removes myTable from the database. As you can see from listing 11-11, I simply constructed a DROP TABLE SQL statement and executing it using the OdbcCommand.Execute method. Listing 11-11: Execution a DROP TABLE SQL statement using OdbcCommand private void button3_Click(object sender, System.EventArgs e) { try { if (conn.State !=ConnectionState.Open) conn.Open(); // Construct DROP TABLE query and execute it string sql ="DROP TABLE myTable"; cmd = new OdbcCommand(sql, conn); cmd.ExecuteNonQuery(); // Close connection if (conn.State ==ConnectionState.Open) conn.Close(); } catch (OdbcException ae) { MessageBox.Show(ae.Message.ToString()); } } Conclusion Hope this article would have helped you in understanding working with Oracle Databases using ADO.NET. See my other articles on the website on ADO.NET.

Using transactions in ADO.NET

Introduction Information is critical in today's information age, but we need to keep the information as consistent with the reality as possible. Database systems holds data and ADO.NET enables to access this data in the backend system, and in order to keep the data consistent while we access the data using ADO.NET, we need to use transactions. A transaction is a set of operations (enabling data interchange between the business entities) where all of them must be successful or fail to ensure consistency on the behavior of the system. A transaction is said to perform a "unit of work" because it does all the work required to update the database to reflect the real-world changes. In this article, I will cover the main principles and techniques concerning transactions using ADO.NET as the data access technology and SQL Server as the Database system in order to build robust enterprise information systems. ACID Properties of Transactions Transactions are characterized by four properties called ACID properties. To pass this ACID test, a transaction must be Atomic, Consistent, Isolated, and Durable. Atomic. All steps in the transaction should succeed or fail together. If a transaction successfully completes and the system agrees to preserve its effects, we say that the transaction has committed, otherwise the transaction has aborted, and the underlying changes made to the database are undone, or rolled back. Consistency. The transaction takes the database from a stable state into a new stable state. The database must satisfy the business rules of the real-world enterprise it models, thus the execution of a transaction must maintain all these consistency constraints. Isolated. Every transaction is an independent entity. The execution of one transaction does not affect the execution of other transactions running at the same time. Durability. The results of committed transactions are permanent.

Transactions in enterprise systems Modern relational database management systems support transactions such as Oracle database and Microsoft SQL Server. Data access API such as ODBC, JDBC. OleDB and ADO.NET enable developer use transactions in their applications. If the developer is executing transactions against several distributed data sources, then the Microsoft Distributed Transaction Coordinator (MSDTC) is used. MSDTC along with COM+ are middleware which enables the execution of distributed transactions. There are a lot of software packages to assist developers to write and execute distributed transactions ensuring the ACID properties across all the underlying data sources, using mechanisms such as two-phase commit and rollback. Transactions in ADO.NET ADO.NET supports single-database transactions as well as distributed transactions. Single-database transaction model is implemented using the underlying .NET managed providers for Transaction and Connection classes from the System.Data namespace. Distributed transaction model is implemented using classes in the namespace System.Transactions. The following code snippet illustrates how to implement single-database transaction in ADO.NET (see Listing 1). using System;

using using using using

System.Data; System.Data.SqlClient; System.Collections.Generic; System.Text;

namespace TransactionExampleCons { class Program { static void Main(string[] args) { string strConnString = "myconnectionstring"; SqlTransaction objTrans = null; using (SqlConnection objConn = new SqlConnection(strConnString)) { objConn.Open(); objTrans = objConn.BeginTransaction(); SqlCommand objCmd1 = new SqlCommand("insert into tbExample values(1)", objConn); SqlCommand objCmd2 = new SqlCommand("insert into tbExample values(2)", objConn); try { objCmd1.ExecuteNonQuery(); objCmd2.ExecuteNonQuery(); objTrans.Commit(); } catch (Exception) { objTrans.Rollback(); } finally { objConn.Close(); } } } } } Listing 1 You can also use transactions along with DataSet and DataAdapter objects. The main idea is to set the created transactions to every command of the DataAdapter (see Listing 2). using using using using using using using System; System.Data; System.Data.Common; System.Data.SqlClient; System.Collections.Generic; System.Text; System.Reflection;

namespace OLA.Framework.Data.SqlClient.Transactions { public class SQLDataAdapter_TransactionalManagement { public SqlTransaction BeginTransaction(object objTableAdapter) { return this.BeginTransaction(objTableAdapter, IsolationLevel.ReadCommitted); } public SqlTransaction BeginTransaction(object objTableAdapter, IsolationLevel isLevel) { Type taType = objTableAdapter.GetType(); SqlConnection objConn = this.prvGetConnection(objTableAdapter); if (objConn.State == ConnectionState.Closed) { objConn.Open(); } SqlTransaction stTrans = objConn.BeginTransaction(isLevel); this.prvSetTransaction(objTableAdapter, stTrans); return stTrans; } public void EnlistInTransaction(object objTableAdapter, SqlTransaction stTrans) { this.prvSetTransaction(objTableAdapter, stTrans); } private SqlConnection prvGetConnection(object objTableAdapter) { SqlConnection scResult = null; Type taType = objTableAdapter.GetType(); PropertyInfo prtConnection = taType.GetProperty("Connection",BindingFlags.NonPublic | BindingFlags.Instance); scResult = (SqlConnection)prtConnection.GetValue(objTableAdapter,null); return scResult; } private void prvSetConnection(object objTableAdapter, SqlConnection objConn) { Type taType = objTableAdapter.GetType(); PropertyInfo prtConnection = taType.GetProperty("Connection", BindingFlags.NonPublic | BindingFlags.Instance); prtConnection.SetValue(objTableAdapter, objConn, null); } private void prvSetTransaction(object objTableAdapter, SqlTransaction stTrans) { Type taType = objTableAdapter.GetType();

PropertyInfo adapterProperty = taType.GetProperty("Adapter", BindingFlags.NonPublic | BindingFlags.Instance); SqlDataAdapter sdaAdapter = (SqlDataAdapter)adapterProperty.GetValue(objTableAdapter, null); sdaAdapter.UpdateCommand.Transaction = stTrans; sdaAdapter.InsertCommand.Transaction = stTrans; sdaAdapter.DeleteCommand.Transaction = stTrans; sdaAdapter.AcceptChangesDuringUpdate = false; PropertyInfo prtCommandCollection = taType.GetProperty("CommandCollection", BindingFlags.NonPublic | BindingFlags.Instance); SqlCommand[] arrCommands = (SqlCommand[])prtCommandCollection.GetValue(objTableAdapter, null); foreach (SqlCommand objCmd in arrCommands) { objCmd.Transaction = stTrans; } this.prvSetConnection(objTableAdapter, stTrans.Connection); } } } Listing 2 The AcceptChangesDuringUpdate property on the DataAdapter object when it's set to false, it specifies that the DataAdapter object should not change the state of data rows as long as it's executing the commands on several rows, thus the developer have to explicitly call the AcceptChanges method on the underlying DataSet object at the end of the transaction. If you set the AcceptChangesDuringUpdate property to true, and one row of all the rows to be updated (let's suppose this row is the last one) is not consistent with the rules of the database; when the transaction is executed and then it's rolled back, all the rows but the last one (the row with invalid values) has their state changed to UnModified. In .NET 1.1, a partial solution to this new problem is to extract the rows to be updated into a smaller DataSet using the GetChanges method of DataSet class. If the transaction commits, you could refresh the data and merge the new and fresh data from the database into the DataSet. One drawback with this approach is that the GetChanges and Merge methods are very expensive. Let's see how to use the class in the Listing 2 in a real-world example (see Listing 3). SqlTransaction stTrans = null; try { this.Validate(); this.m_bsEmployee.EndEdit();//Accept changes through this BindingSource //instance SQLDataAdapter_TransactionalManagement sdatmInstance = new SQLDataAdapter_TransactionalManagement(); stTrans = sdatmInstance.BeginTransaction(this.m_taEmployee); //Set //transaction for the table adapter in order to update the Employee table. //You can extend this transaction scope to several table adapters this.m_taEmployee.Update(this.m_hR_DataSet.Employee); //Update the //changes in the this.m_hr_DataSet.Employee object into the Employee table //through the table adapter stTrans.Commit();//Commit changes to the database system, if everything //is OK this.m_hR_DataSet.Employee.AcceptChanges();//Commit the changes to the //dataset

object } catch (SqlException ex) { stTrans.Rollback();//Cancel the changes to the database system, if an //error occurs System.Windows.Forms.MessageBox.Show(ex.Message, "SQL Exception", MessageBoxButtons.OK, MessageBoxIcon.Information); //Show the error message } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message, "Error Message", MessageBoxButtons.OK, MessageBoxIcon.Information); } finally { stTrans.Dispose();//Release the resources associated to the transaction //object

}
Listing 3 Distributed Transactions Developers can also deal with database systems in which a transaction can access a heterogeneous set of transaction processing systems at multiple sites (perhaps scattered throughout the world) also known as resource managers. This sort of transactions is known as distributed transactions. These systems process some operations within the current transactions (a subtransaction) and then report a success or a failure. In addition to resource managers, we need a middleware package that listens to and coordinates the final result between resource managers. This middleware is known as transaction manager. The transaction manager that ships with Windows is the Microsoft Distributed Transaction Coordinator (MSDTC). You can consume the services provided by MSDTC by using MTS/COM+, System.EnterpriseServices and the new System.Transactions namespace in .NET 2.0. In order to implement an atomic commit, we need a protocol for the communication of resource managers and transaction managers. A lot of atomic commit protocols have been proposed, but the one that is in common use is called two-phase commit protocol. This protocol is initiated by the transaction manager or coordinator when the underlying transaction requests to commit. To perform correctly this protocol, the coordinator needs to know the identities of all the resource managers involved in the transaction. Thus, each time a resource manager joins the transaction; its identification is sent to the coordinator. The two-phase commit protocol comprises two phases. The first phase involves preparing the changes required for the commit. The purpose is to determine whether resource managers are willing and ready to commit, but not actually committed yet. Once all the other resource managers notify to the transaction manager or coordinator to agree to commit, then the coordinator lets the resource managers to go ahead and commit their changes. In a distributed transaction, anything, which has the capability to enlist itself in an MSDTC transaction, can participate as resource managers. In .NET 1.1, you need to create a component hosted within a class library. This library must be in the GAC, thus you need to strongly name it using the sn.exe tool. This component can be implemented by inheriting from the class ServicedComponent in the

System.EnterpriseServices namespace which provides the programming interface to access MSDTC functionality. You need to specify the TransactionAttribute on top of the component class and declare the transactional behavior using the TransactionOption enumeration (see Table 1). Finally, this component will be able to enlist itself in an MSDTC transaction. Enumeration Description Disable This component does not participate in a transaction. This is the default value.

NotSupported This component runs outside the context of a transaction. Supported This component participates in a transaction if this exists. But it does not require a transaction or create a new one. This component must have a transaction. If a transaction does not exist, then it creates a new one. If a transaction exists, then it participates in this one.

Required

RequiresNew This component must have a transaction, and always creates a new transaction. Table 1 The implementation of the component is shown in Listing 4. using using using using using using using System; System.EnterpriseServices; System.Data; System.Data.SqlClient; System.Data.OracleClient; System.Collections.Generic; System.Text;

namespace TransactionExampleCons { [Transaction(TransactionOption.RequiresNew)] public class COMPlusDistributedTransaction : ServicedComponent { public static void FinancialAccount(int nDebitAccount, float fDebitAmount, int nCreditAccount, float fCreditAmount) { OracleConnection objOracleConn = null; SqlConnection objSqlConn = null; OracleCommand cmdDebit = null; SqlCommand cmdCredit = null; try { objOracleConn = new OracleConnection("oracleconnstring"); objSqlConn = new SqlConnection("oracleconnstring"); string strDebitCmd = String.Format("UPDATE tbAccount SET amount={0} WHERE accountid={1}", fDebitAmount, nDebitAccount); string strCreditCmd = String.Format("UPDATE tbAccount SET amount={0} WHERE accountid={1}", fCreditAmount, nCreditAccount);

cmdDebit = new OracleCommand(strDebitCmd, objOracleConn); cmdCredit = new SqlCommand(strCreditCmd, objSqlConn); cmdCredit.ExecuteNonQuery(); cmdDebit.ExecuteNonQuery(); } finally { cmdDebit.Dispose(); cmdCredit.Dispose(); objOracleConn.Close(); objSqlConn.Close(); } } } } Listing 4 If the method finishes successfully, then the component notifies to the coordinator that it's ready and willing with the changes, pending others. If anyone else in the distributed transaction aborts, then all the bets are off and no changes are committed. Now let's illustrate how to implement distributed transaction in .NET 2.0 using the class in the System.Transactions namespace. In this case, we don't need an instance of a ServicedComponent-inherited class. We just create an instance of a .NET managed class (see Listing 5). using using using using using using using System; System.Transactions; System.Data; System.Data.SqlClient; System.Data.OracleClient; System.Collections.Generic; System.Text;

namespace TransactionExampleCons { public class ManagedDistributedTransaction { public void FinancialAccount(int nDebitAccount, float fDebitAmount, int nCreditAccount, float fCreditAmount) { using(TransactionScope tsInstance = new TransactionScope()) { OracleConnection objOracleConn = new OracleConnection("oracleconnstring"); SqlConnection objSqlConn = new SqlConnection("oracleconnstring"); string strDebitCmd = String.Format("UPDATE tbAccount SET amount={0} WHERE accountid={1}", fDebitAmount, nDebitAccount); string strCreditCmd = String.Format("UPDATE tbAccount SET amount={0} WHERE accountid={1}", fCreditAmount, nCreditAccount);

OracleCommand cmdDebit = new OracleCommand(strDebitCmd, objOracleConn); SqlCommand cmdCredit = new SqlCommand(strCreditCmd, objSqlConn); cmdCredit.ExecuteNonQuery(); cmdDebit.ExecuteNonQuery(); tsInstance.Complete(); } } } } Listing 5 You can check the status of the distributed transaction when it's running by going to the Control Panel | Administrative Tools | Component Services and navigate through the tree on the left side to view the transaction list (see Figure 1).

Figure 1 Conclusion In this article, I've illustrated the main principles of transactions in ADO.NET through real-world example. Now, you can adapt these examples in your own business scenario.

You might also like