The MySqlDataTable component is one of the most effective tools in the dotConnect for MySQL arsenal. It combines connection to server, command object and data storage in single component with really comprehensive capabilities. In addition, it can accomplish data access tasks in both connected and disconnected models. This topic describes how you can use some of the MySqlDataTable features.
The MySqlDataTable component can be used both as a standalone data processing unit and in conjunction with GUI controls like grids. The behavior of the MySqlDataTable component can be described in a declaratively way with properties, which means that it is very convenient to build and test the application in design time.
The MySqlDataTable component supports server-specific data types. It is used by MySqlDataSet components to build the schema with server-specific features. However, this does not break compatibility with common data access techniques.
The MySqlDataTable component provides rich set of data fetch mechanisms. Besides the traditional mode where selected data is retrieved at once, it supports sequential, paginal, and asynchronous fetch modes. The following MySqlDataTable members are involved into the fetch control:
This list demonstrates that MySqlDataTable has all flavors of data access mechanisms. The component members mentioned in the list can be used in different combinations. The following sections of the topic describe some combinations, their effect and problems that can be solved best with chosen fetch mode.
The usual approach to requesting data is to transfer the whole resultset to client side in single operation. The advantages of this approach are obvious: the entire resultset is available once fetched, the application does not depend on network stability, there are no delays during navigation through large datasets. On the other hand, the disadvantages of this approach are obvious as well: long initial timeout, possibly excessive memory consumption, higher requirements to network connection speed.
To perform traditional fetch with the MySqlDataTable component, just invoke the Open method (or set Active property to true). Make sure that the component is configured as follows:
With these conditions, the Open method will return only when the whole dataset is transferred to client side. However, you can set the NonBlocking property to true, which will make the method return immediately. To capture the end moment of the operation in a non-blocking fetch, watch for the SyncRoot property or handle the FetchFinished event.
Another way is to call the Fill method, which ignores all of the mentioned properties and just fetches the whole resultset.
[C#]
static void UseDataTable(MySqlDataTable myDataTable, MySqlCommand myCommand)
{
myCommand.CommandText = "SELECT * FROM Test.Dept";
myDataTable.SelectCommand = myCommand;
myDataTable.FetchAll = true;
try
{
myDataTable.Active = true;
foreach(DataRow myRow in myDataTable.Rows)
{
foreach(DataColumn myCol in myDataTable.Columns)
{
Console.Write(myRow[myCol]+"\t");
}
Console.WriteLine();
}
}
finally
{
myDataTable.Active = false;
}
}
[Visual Basic]
Public Sub UseDataTable(ByVal myDataTable As MySqlDataTable, ByVal myCommand As MySqlCommand)
myCommand.CommandText = "SELECT * FROM Test.Dept"
myDataTable.SelectCommand = myCommand
myDataTable.FetchAll = True
Try
myDataTable.Active = True
Dim myRow As DataRow
Dim myCol As DataColumn
For Each myRow In myDataTable.Rows
For Each myCol In myDataTable.Columns
Console.Write(myRow(myCol) & Chr(9))
Next myCol
Console.WriteLine()
Next myRow
Finally
myDataTable.Active = False
End Try
End Sub
A more sophisticated approach is to transfer to client only rows that are necessary for rendering or updating. When client needs to fetch more records (for example, user scrolls a grid), another request to server is performed. In contrast to the traditional fetch mode, this way the initial timeout is much shorter, there is no redundant memory consumption, and possibly slow connection would not freeze the application too much. However, sequential mode assumes that you have stable network, so that client does not have to wait every time a new portion of the resultset is requested.
To perform sequential fetch, set the FetchAll property to false, MaxRecords property to 0, and call Open. Note that the NonBlocking property does not affect the sequential fetch, and that the Fill method ignores the FetchAll property as well.
To improve behavior of sequential mode, the MySqlDataTable component provides two additional properties, QueryRecordCount and RecordCount. The QueryRecordCount property determines whether to perform additional roundtrip to server to find out how many rows are there in the resultset. If the QueryRecordCount property is set to true, the RecordCount property contains the number of rows, otherwise it contains number of rows currently fetched to the client.
When you know for sure which subset of rows the application actually needs, you can switch to paginal mode that allows selecting rows range explicitly. In this mode it is up to you to determine which and how many rows should be retrieved. The MySqlDataTable component has two ways to limit the range:
While the first way is self-sufficient and is not affected by any property, the second way still can be modified by the FetchAll and NonBlocking properties (see above for explanation). For example, the following assignments will cause the Open method return before a subrange of rows is entirely fetched:
[C#]
static void UseDataTable(MySqlDataTable myDataTable, MySqlConnection myConnection) {
myDataTable.Connection = myConnection;
myDataTable.SelectCommand = myConnection.CreateCommand();
myDataTable.SelectCommand.CommandText = "SELECT * FROM Dept";
myDataTable.FetchAll = false;
myDataTable.NonBlocking = true;
myDataTable.StartRecord = 10;
myDataTable.MaxRecords = 5;
myDataTable.RowFetched += new EventHandler(myDataTable_RowFetched);
myDataTable.FetchFinished += new EventHandler(myDataTable_FetchFinished);
myDataTable.Open();
}
static void myDataTable_RowFetched(object sender, EventArgs e) {
Console.Write(string.Format("{0} rows are fetched", ((MySqlDataTable)sender).RecordCount));
}
static void myDataTable_FetchFinished(object sender, EventArgs e) {
Console.Write("All records are fetched");
}
[Visual Basic]
Private Shared Sub UseDataTable(ByVal myDataTable As MySqlDataTable, ByVal myConnection As MySqlConnection)
myDataTable.Connection = myConnection
myDataTable.SelectCommand = myConnection.CreateCommand
myDataTable.SelectCommand.CommandText = "SELECT * FROM Dept"
myDataTable.FetchAll = False
myDataTable.NonBlocking = True
myDataTable.StartRecord = 10
myDataTable.MaxRecords = 5
AddHandler myDataTable.RowFetched, New EventHandler(AddressOf Form1.myDataTable_RowFetched)
AddHandler myDataTable.FetchFinished, New EventHandler(AddressOf Form1.myDataTable_FetchFinished)
myDataTable.Open()
End Sub
Private Shared Sub myDataTable_RowFetched(ByVal sender As Object, ByVal e As EventArgs)
Console.Write(String.Format("{0} rows are fetched", DirectCast(sender, MySqlDataTable).RecordCount))
End Sub
Private Shared Sub myDataTable_FetchFinished(ByVal sender As Object, ByVal e As EventArgs)
Console.Write("All records are fetched")
End Sub
The traditional and paginal fetch modes provide capability of transparent asynchronous fill operations with the NonBlocking property set to true. You can control the asynchronous fetch entirely using the following set of methods:
For more information about the asynchronous operations in MySqlDataTable please refer to topic Asynchronous Execution. The topic describes some useful techniques and provides more examples on the subject.
[C#]
static void UseDataTable(MySqlDataTable myDataTable, MySqlConnection myConnection) {
myDataTable.Connection = myConnection;
myDataTable.SelectCommand = myConnection.CreateCommand();
myDataTable.SelectCommand.CommandText = "SELECT * FROM Dept";
IAsyncResult aRes = myDataTable.BeginFill(null, null);
Console.Write("Fetch in process");
Thread.Sleep(100);
myDataTable.SuspendFill(true);
Console.Write("Fetch is stopped");
myDataTable.EndFill(aRes);
Console.Write("All records are fetched");
}
[Visual Basic]
Private Shared Sub UseDataTable3(ByVal myDataTable As MySqlDataTable, ByVal myConnection As MySqlConnection)
myDataTable.Connection = myConnection
myDataTable.SelectCommand = myConnection.CreateCommand
myDataTable.SelectCommand.CommandText = "SELECT * FROM Dept"
Dim result1 As IAsyncResult = myDataTable.BeginFill(Nothing, Nothing)
Console.Write("Fetch in process")
Thread.Sleep(100)
myDataTable.SuspendFill(True)
Console.Write("Fetch is stopped")
myDataTable.EndFill(result1)
Console.Write("All records are fetched")
End Sub
In addition to classic master-detail relationship, the MySqlDataTable component is capable of establishing a relationship where details data is not cached on the client. Every time the current position in the master table is changed, the client MySqlDataTable requests the appropriate portion of data from the server. This goal is achieved using the ParentDataRelation class. The query-based master-detail relationship is designed to improve performance of the application and leverage network load.
[C#]
MySqlConnection connection = new MySqlConnection("User Id=root;Host=localhost;Database=Test");
connection.Open();
MySqlDataTable deptTable = new MySqlDataTable("SELECT * FROM dept", connection);
MySqlDataTable empTable = new MySqlDataTable("SELECT * FROM emp", connection);
empTable.ParentRelation.ParentTable = deptTable;
empTable.ParentRelation.ParentColumnNames = new string[] { "deptno" };
empTable.ParentRelation.ChildColumnNames = new string[] { "deptno" };
deptTable.Owner = this;
empTable.Owner = this;
deptTable.Open();
empTable.Open();
deptDataGrid.DataSource = deptTable;
empDataGrid.DataSource = empTable;
[Visual Basic]
Dim connection As New MySqlConnection("User Id=root;Host=localhost;Database=Test")
connection.Open()
Dim deptTable As New MySqlDataTable("SELECT * FROM dept", connection)
Dim empTable As New MySqlDataTable("SELECT * FROM emp", connection)
empTable.ParentRelation.ParentTable = deptTable
empTable.ParentRelation.ParentColumnNames = New String() {"deptno"}
empTable.ParentRelation.ChildColumnNames = New String() {"deptno"}
deptTable.Owner = Me
empTable.Owner = Me
deptTable.Open()
empTable.Open()
deptDataGrid.DataSource = deptTable
empDataGrid.DataSource = empTable
The MySqlDataTable component is designed to avoid redundant data transfer. One of the tools you can use for this purpose is partial column read. The main point of the technique is having a full dataset schema on client side, but requesting only a subrange of columns. When you decide that a row really needs the rest of the columns, you invoke the ReadComplete method for the chosen row. This can be illustrated with a photo database, where initially you fetch only a short description of a photo, and the image itself is transferred only if the user requests it.
[C#]
static void UseDataTable(MySqlDataTable myDataTable, MySqlConnection myConnection) {
myDataTable.Connection = myConnection;
myDataTable.SelectCommand = myConnection.CreateCommand();
myDataTable.SelectCommand.CommandText = "SELECT DEPTNO FROM Dept";
System.Data.DataColumn column_DEPTNO = new System.Data.DataColumn();
System.Data.DataColumn column_DNAME = new System.Data.DataColumn();
System.Data.DataColumn column_LOC = new System.Data.DataColumn();
column_DEPTNO.ColumnName = "DEPTNO";
column_DEPTNO.DataType = typeof(int);
column_LOC.ColumnName = "LOC";
column_DEPTNO.DataType = typeof(string);
myDataTable.Columns.AddRange(new System.Data.DataColumn[] {column_DEPTNO, column_DNAME, column_LOC});
myDataTable.FetchAll = true;
myDataTable.Open();
Console.Write("DEPTNO column is loaded");
myDataTable.ReadComplete(myDataTable.Rows[0]);
Console.Write("DEPTNO and LOC columns are loaded");
}
[Visual Basic]
Private Shared Sub UseDataTable(ByVal myDataTable As MySqlDataTable, ByVal myConnection As MySqlConnection)
myDataTable.Connection = myConnection
myDataTable.SelectCommand = myConnection.CreateCommand
myDataTable.SelectCommand.CommandText = "SELECT DEPTNO FROM Dept"
Dim column1 As New DataColumn
Dim column2 As New DataColumn
Dim column3 As New DataColumn
column1.ColumnName = "DEPTNO"
column1.DataType = GetType(Integer)
column3.ColumnName = "LOC"
column1.DataType = GetType(String)
myDataTable.Columns.AddRange(New DataColumn() {column1, column2, column3})
myDataTable.FetchAll = True
myDataTable.Open()
Console.Write("DEPTNO column is loaded")
myDataTable.ReadComplete(myDataTable.Rows.Item(0))
Console.Write("DEPTNO and LOC columns are loaded")
End Sub
The MySqlDataTable component is designed to provide comprehensive data binding capabilities. It supports the InterForm technology, which means that you can bind controls on another form to the MySqlDataTable. The component even allows updating underlying datasets in design time with data binding (when the CachedUpdates property is set to false). In addition, the QueryRecordCount property enables informing GUI controls about real quantity of rows in a resultset. These features make MySqlDataTable component the best choice for both design time and run time data processing.
General Concepts in Database Application Development | Developing Database Applications with dotConnect for MySQL | Asynchronous Execution | InterForm Technology | MySqlDataTable Reference | ParentDataRelation Reference
© 2002-2008 Devart. All rights reserved.