|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionThis is a simple ADO.NET database application that returns results from a database table, writes the output to a After getting lots of responses and suggestions from the users, I changed some points and made the code more readable. Like everyone else I also searched for a most requested method in MSDN Library to trap the keystrokes (Up, Down, Esc...) in Windows Forms and included it in the code because some users asked me desperately for that. You can find the other requested methods as well to get the contents of a cell/row in a I chose Microsoft Access database (as reflected in the ADO.NET OleDb objects) because it's easy to use and you don't need to have Microsoft SQL Server running. But ADO.NET is highly optimized if you are working with Microsoft SQL Server databases (as reflected in the ADO.NET Sql objects). I have now added a second part to this project (Personal Address Book) on Database Manipulation with ADO.NET for beginners where you can do data manipulation in Contents
This project was developed using Visual Studio .NET 2003 and Microsoft Access, on Windows XP Pro. 1. What is ADO.NET?ADO.NET is the new database technology of the .NET (Dot Net) platform, and it builds on Microsoft ActiveX® Data Objects (ADO). ADO is a language-neutral object model that is the keystone of Microsoft's Universal Data Access strategy. ADO.NET is an integral part of the .NET Compact Framework, providing access to relational data, XML documents, and application data. ADO.NET supports a variety of development needs. You can create database-client applications and middle-tier business objects used by applications, tools, languages or Internet browsers. ADO.NET defines ADO.NET provides data access services in the Microsoft .NET platform. You can use ADO.NET to access data by using the new .NET Framework data providers which are:
ADO.NET is a set of classes that expose data access services to the .NET developer. The ADO.NET classes are found in System.Data.dll and are integrated with the XML classes in System.Xml.dll. There are two central components of ADO.NET classes: the Data Provider is a set of components including:
The ADO.NET Object Model
2. Connection to an ADO.NET databaseBefore working with a database, you have to add (here) the using System.Data.OleDb;
Similarly for the using System.Data.SqlClient;
The Now, we have to declare a connection string pointing to a MS Access database "PersonDatabase.mdb". public string
conString=@"Provider=Microsoft.Jet.OLEDB.4.0;" +
@" DataSource=..\\..\\PersonDatabase.mdb";
The database should be in the specified path, otherwise you should change the path accordingly. The next step is to create an OleDbConnection con = new OleDbConnection(conString);
You can also explicitly reference declared objects if you don’t mind typing a lot. System.Data.OleDb.OleDbConnection con =
new System.Data.OleDb.OleDbConnection(conString);
Here is the code snippet for connection to a database: //using declaration for OLE DB
using System.Data.OleDb;
//specify the ConnectionString property
public string conString=
@"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=..\\..\\PersonDatabase.mdb";
//Initializes a new instance of the OleDbConnection
OleDbConnection con = new OleDbConnection(conString);
// open the database connection with the property settings
// specified by the ConnectionString "conString"
con.Open();
In many earlier applications, the tendency was to open a connection when you start the application and not close the connection until the application terminates. It is an expensive and time-consuming operation to open and close a database connection. Most databases have a limit on the number of concurrent connections that they allow. For example: each connection consumes a certain amount of resources on the database server and these resources are not infinite. Most modern OLE DB providers (including SQL Server provider) implement connection pooling. If you create database connections, they are held in a pool. When you want a connection for an application, the OLE DB provider extracts the next available connection from the pool. When your application closes the connection, it returns to the pool and makes itself available for the next application that wants a connection. This means that opening and closing a database connection is no longer an expensive operation. If you close a connection, it does not mean you disconnect from the database. It just returns the connection to the pool. If you open a connection, it means it's simply a matter of obtaining an already open connection from the pool. It's recommended in many ADO.NET books not to keep the connections longer than you need to. Therefore, you should:
For example: here is another way to get a connection to a database: // setup the global SqlConnection object and constr in your class
private SqlConnection con = null;
private string constr ="Integrated Security=SSPI;" +
"Initial Catalog=Northwind;" +
"Data Source=SONY\\MYSQLSERVER;";
private void fnGetConnection()
{
try
{
// setup the database connection
con = new SqlConnection(constr);
con.Open();
}catch (Exception ex) {
MessageBox.Show("Error in connection : "+ex.Message);
}finally {
// dispose of open objects
if (con != null)
con.Close();
} //finally
}
For example: you want to open the connection, fill the try
{
con.Open();
dadapter.Fill(dataset1);
con.Close();
} catch (Exception ex) {
MessageBox.Show("Error in retrieving data: " + ex.Message);
}
For example: if you want to save the data you changed, then you just open the connection, update the data, and close the connection and accept the changes. If it fails, display an error message, reject the changes, and close the connection. try
{
DataSet changes = dataset.GetChanges();
con.Open();
datapter.Update(changes);
con.Close();
dataset1.AcceptChanges();
}catch (Exception ex) {
MessageBox.Show("ErrorR: " + ex.Message);
dataset1.RejectChanges();
con.Close();
}
3. DataSetThe The
//Create a DataSet
DataSet dset = new DataSet();
There are two types of
1. Typed DataSet is derived from the base Example: the following code accesses the string str;
str=dset.Customers[0].CustomerID;
Create a typed DataSet without designer - manually
xsd.exe /d /l:cs mydataset.xsd /n:mynamespace
/d : you create a DataSet.
/l:cs - set the language as C#.
/n:mynamespace - the class should use the namespace "mynamespace".
The output of XSD.EXE with these arguments will be a .cs class file (mydataset.cs). Use csc.exe to compile the class. csc.exe /t:library mydataset.cs /r:System.dll /r:System.Data.dll
/r:System.XML.dll /out:bin/mydataset.dll /t:library
Compile as a library component (DLL).
2. Untyped DataSet is not defined by a schema, instead, you have to add tables, columns and other elements to it yourself, either by setting properties at design time or by adding them at run time. Typical scenario: if you don't know in advance what the structure of your program is that is interacting with a component that returns a The equivalent code above for Untyped DataSet is: string str;
str=(string)dset.Tables["Customers"].Row[0].["CustomerID"];
A You can populate a DataSet in a variety of ways:
4. DataAdapter
The
The four properties are set to Command objects that are used when data is manipulated. The
For example: When we call the //Create an instance of a OleDbDataAdapter
//by passing OleDbConnection object and select.. query
OleDbDataAdapter dAdapter = new
OleDbDataAdapter ("select * from PersonTable", con );
//fill the DataSet with records from the table "PersonTable"
dAdapter.Fill(dSet,"PersonTable");
Here is the method used in this project to get a data connection, public bool fnGetDataConnection()
{
try {
con =new OleDbConnection(conString);
dAdapter=new OleDbDataAdapter("select * from PersonTable", con);
dSet=new DataSet();
//refreshes rows in the DataSet
dAdapter.Fill(dSet,"PersonTable");
}catch(Exception ex) {
MessageBox.Show("Error : "+ex.Message);
//connectection failed
return false;
}//try-catch
//connection ok!
return true;
}
5. Display data in a DataGrid / data relationship between two tablesThe Windows Forms You can use the
Here is the binding to the this.dataGrid1 DataSource = datc.dSet.Tables["PersonTable"];
You can only show one table in the If you define a parent-child relationship between tables, you can navigate between the related tables to select the table you want to display in the For example: dset.Relations.Add("CustomerOrders",
dset.Tables["customers"].Columns["CustomerID"],
dset.Tables["orders"].Columns["CustomerID"]);
//now here you can use one of the following
this.dataGrid1.DataSource=dset.Tables["customers"];
OR this.dataGrid1.SetDataBinding(dset,"customers");
Here is a typical example of how to use the parent-child relationship between the tables "Customers" and "Orders" on a The To run and test this example, create a new project, drag/drop a public string fnGetConnectionString()
{
//it gives back the connection string :
// change for you the Data Source=.... accordingly
//for MS-Access
//return "Provider=Microsoft.Jet.OLEDB.4.0;
// Data Source=..\\..\\Northwind.mdb";
//for SQLSERVER2000
return "data source=SONY\\MYSQLSERVER;initial" +
" catalog=Northwind;integrated security=SSPI;";
}private void button1_Click(object sender, System.EventArgs e)
{
// for SQLServer2000
DataSet dset=new DataSet();
string strCustomers="select * from customers";
string strOrders="select * from orders";
SqlConnection sqlcon=new SqlConnection(fnGetConnectionString());
SqlDataAdapter dadapter=new SqlDataAdapter(strCustomers,sqlcon);
dadapter.Fill(dset,"Customers");
dadapter=new SqlDataAdapter(strOrders,sqlcon);
dadapter.Fill(dset,"Orders");
// Add the relation to the DataSet.
dset.Relations.Add("Customer Orders",
dset.Tables["Customers"].Columns["CustomerID"],
dset.Tables["Orders"].Columns["CustomerID"]);
//Display data in the DataGrid
//both works fine
this.dataGrid1.DataSource=dset.Tables["Customers"];
//this.dataGrid1.SetDataBinding(ds,"Customers");
//for MS-Access
/*
//create a DataSet object which will contain the following 2 DataTables
DataSet dset=new DataSet();
string strCustomers="select * from customers";
string strOrders="select * from orders";
OleDbConnection con=new OleDbConnection(fnGetConnection());
OleDbDataAdapter dadapter=new OleDbDataAdapter(strCustomers,con);
//fill the DataSet with the records from the Customers table
dadapter.Fill(dset,"Customers");
dadapter=new OleDbDataAdapter(strOrders,con);
//fill the DataSet with the records from the Orders table
dadapter.Fill(dset,"Orders");
//establish the relation between the 2 DataTable objects
dset.Relations.Add("Customer Orders",
dset.Tables["Customers"].Columns["CustomerID"],
dset.Tables["Orders"].Columns["CustomerID"]);
//both works fine
this.dataGrid1.DataSource=dset.Tables["Customers"]; //show the data in DataGrid
//this.dataGrid1.SetDataBinding(ds,"Customers");
*/
}
Now if you update the data in the bound
The first time this application was published, I got e-mails from users asking me how to get the contents of a // you click in the cell or the rows
// of the DataGrid and get the content of it
private void dataGrid1_CurrentCellChanged(object sender, System.EventArgs e)
{
/* be warned: if you click the last cell on the Datagrid you get
an unhandled exception of type 'System.ArgumentOutOfRangeException.
because there is no further columns after the last column(Country)
to avoid this I tried a different way: in a try-catch get the right
cell content. if the last column cell clicked, display the exception
and the cell content one before. But you can comment
the MessageBox.Show line if not wished */
//get the row number on the DataGrid
int iRownr=this.dataGrid1.CurrentCell.RowNumber;
//get the column number on the DataGrid
int iColnr=this.dataGrid1.CurrentCell.ColumnNumber;
//get the content of the cell in the clicked cell on the Datagrid
object cellvalue1=this.dataGrid1[iRownr, iColnr];
object cellvalue2=null;
//get the next cell content in the same row
try {
cellvalue2=this.dataGrid1[iRownr, iColnr+1];
//display (cellvalue1+cellvalue2) in TextBox "textBox1"
this.textBox1.Text=cellvalue1.ToString()+" "+cellvalue2.ToString();
} catch(Exception ex) {
//the exception occurs here because we increment iColnr+1
MessageBox.Show("No further columns after the last " +
"column(Country) -->> "+ex.Message,"STOP");
cellvalue2=this.dataGrid1[iRownr, iColnr-1];
//display this time (cellvalue2+cellvalue1) in TextBox "textBox1"
this.textBox1.Text=cellvalue2.ToString()+" "+cellvalue1.ToString();
}//catch
}
6. DataBindings for TextBoxesDataBinding is the ability to bind some elements of a data source with some graphical elements of an application. The data in Windows Forms is bound by calling Windows Forms Controls support two types of data binding:
1. Simple Data Binding allows you to display a single data element, such as a column value from a For example: // Simple DataBinding for TextBox "textBox1"
textBox1.DataBindings.Add("Text", dataset, "studentTable.studentID");
The control " 2. Complex data binding is the ability of a control to bind to more than one data element, typically more than one record in a database, or to more than one of any other type of bindable data element. Typical scenario: You want to display the names of products in a list box and then retrieve in a
For example: You could add complex data binding by using the datagrid1.DataSource = dSet;
// Use the DataMember property to specify the DataTable.
datagrid1.DataMember = "PersonTable";
Here is the method used in this project to bind all private void fnGetDataBindingForTextBoxes()
{
this.textboxFirstname.DataBindings.Add("Text",
datc.dSet.Tables["PersonTable"],"FirstName");
this.textboxLastname.DataBindings.Add("Text",
datc.dSet.Tables["PersonTable"],"LastName");
this.textboxTitle.DataBindings.Add("Text",
datc.dSet.Tables["PersonTable"],"Title");
this.textboxCity.DataBindings.Add("Text",
datc.dSet.Tables["PersonTable"],"City");
this.textboxCountry.DataBindings.Add("Text",
datc.dSet.Tables["PersonTable"],"Country");
}
7. Using the CurrencyManager
You use the Every Windows Form has a In a normal case where you are using an ADO.NET database (connecting and closing database) and displaying the records, e.g., in a For example: If you want to know how many records are in a this.BindingContext[dataset1,"PersonTable"].Count - 1 ;
If you want to get the current position from the this.BindingContext[dataset1, "PersonTable"].Position + 1;
After data binding, you call and initialize public void fnSetCurrencyManager()
{
currManager = (CurrencyManager)this.
BindingContext [ datc.dSet.Tables["PersonTable"]] ;
}
8. Navigation through records with Next, Previous, Last, First buttonsAs soon as you get the data populated in the If the In order to capture keystrokes on the I also included two new methods in order to highlight the records in the 1st method: fnSelectUnselectLastFirstRow(int posi)
If you click First or Last button, the first or last record will be selected and highlighted in the fnSelectUnselectLastFirstRow(this.currManager.Count-1);
Here is the 1st method I used for this purpose: private void fnSelectUnselectLastFirstRow (int posi)
{
//unselect the last selected/highlighted row
this.dataGrid1.UnSelect(this.dataGrid1.CurrentRowIndex);
//select the last or first row
this.dataGrid1.Select(posi);
}
2nd method: fnSelectUnselectCurrentRow(int num1, int num2)
If you click Next or Previous button, the next or previous record will be selected and highlighted in the Here is the 2nd method used for it: private void fnSelectUnselectCurrentRow(int num1, int num2)
{
//get the current row index
this.iRowIndex=this.dataGrid1.CurrentRowIndex;
//increment or decrement the index by (num1,bum2)1,-1 or -1,1 depending on
//Next or Previous button because we want to select next or previous row
//if num1 is +1 you clicked Next so select next row
//if num1 -1 you clicked Previous so select previous row
//I use in both select and unselect plus(+)
// it´s like in math: e.g.7+(-1)=7-1= 6 or7+(+1)=7+1=8
this.iRowIndex=this.iRowIndex+num1;
//select the current row
this.dataGrid1.Select(this.iRowIndex);
//increment or decrement the index by -1 or 1
//so that we can unselect the previous row
this.iRowIndex=this.iRowIndex+num2;
//unselect the previous row
this.dataGrid1.UnSelect(this.iRowIndex);
}
Now back to enabling and disabling the buttons: When you click First button, position will be set to 0 (zero) because the first row starts by zero. currManager.Position=0;
and
When you click Next button, position in the data is increased by 1 and moved to the next row. currManager.Position +=1;
and
When you click Previous button, position in the data is decreased by -1 and moved to the previous row. currManager.Position -=1;
and
When you click Last button, position in the data is set to the last record (row). this.currManager.Position=this.currManager.Count-1;
and
To enable and disable the buttons, I use the function/method private void fnEnableDisableButtons(Button bt1, Button bt2, string str, bool b)
{
bt1.Enabled=b;
bt2.Enabled=b;
this.statusBar1.Text=str;
}
9. How to trap keystrokes (Up, Down, Esc, NumLock...) in the DataGridEvery time you press the keys Up, Down, NumLock and Esc in the Like many users, I also looked for a method to catch the keystrokes in a If no data was assigned to the grid, the arrow keys (LEFT, RIGHT, UP, and DOWN) raise only the protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
const int WM_KEYDOWN = 0x100;
const int WM_SYSKEYDOWN = 0x104;
if ((msg.Msg == WM_KEYDOWN) || (msg.Msg == WM_SYSKEYDOWN))
{
switch(keyData)
{
case Keys.Down:
this.statusBarPanel2.Text="Down";
this.statusBarPanel1.Text = "Trapped keystrokes on DataGrid...";
break;
case Keys.Up:
this.statusBarPanel2.Text="Up";
this.statusBarPanel1.Text ="Trapped keystrokes on DataGrid...";
break;
case Keys.NumLock:
this.statusBarPanel2.Text="NumLock";
this.statusBarPanel1.Text ="Trapped keystrokes on DataGrid...";
break;
case Keys.Escape:
this.statusBarPanel2.Text="Escape";
this.statusBarPanel1.Text ="Trapped keystrokes on DataGrid...";
//invoke the method "fnExitUniversal" from the class "ExitClass"
ExitClass ec=new ExitClass();
ec.fnExitUniversal();
break;
/*
case Keys.Tab:
this.statusBarPanel1.Text="Tab Key Captured";
break;
case Keys.Control | Keys.M:
this.statusBarPanel1.Text="<CTRL>+ M Captured";
break;
case Keys.Alt | Keys.Z:
this.statusBarPanel1.Text="<ALT> + Z Captured";
break;
*/
} //switch
} //if
return base.ProcessCmdKey(ref msg,keyData);
}
In conclusionI tried to show the basics of ADO.NET to the beginners, and how to use ADO.NET in a database application and also keep the code as readable as possible. In addition, I also tried to show some interesting tips and methods for the There is now a second part to this project (Personal Address Book): Database Manipulation with ADO.NET for beginners, where you can do data manipulation in I hope it can help you understand (a bit) what ADO.NET is, and you can find something useful here for your projects. Good coding!
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||