![]() |
Database »
Database »
Databases
Intermediate
License: The Code Project Open License (CPOL)
VB.NET Class Library: Access Table InterfaceBy George B GilbertA toolkit that simplifies querying and updating Access database tables. |
VB, SQL, Windows, .NET, Visual Studio, ADO.NET, DBA, Dev
|
|
Advanced Search Add to IE Search |
|
|
||||||||||||||||||
* Two of the DLLs in the demo project's BIN folder are 2gs_datetextbox.dll and 2gs_extendedtextbox.dll. Click here to read about these user controls.

Demo project main form

Demo project New dialog box

Demo project Change dialog box (same form as New dialog box)

Demo project Remove dialog box
The Access Table class library (2gs_accesstable.dll) houses one class.
C_AccessTable ... used to instantiate a data extraction and update interface for a table in an Access database. This class has three constructors, and exposes five methods and eleven properties. The demo project comes with an Access database (demo.mdb) that contains a table named Products. The main demo form lists all of the records from the Products table, and provides buttons for adding, changing, and deleting products. A second form is used for both the New and Change functions. Communication of data and states between the main and the second form is done primarily via PO box variables in a common module.
Many moons ago, I discovered that "DLL Hell" was only one of the mine fields we programmers had to traverse. What I refer to as "MDAC Attack" is a similar pit of horrors with which I became acquainted the first time I prepared an application for distribution that included an Access database. To my chagrin, the MDAC added more than 10 MB to my download file which, without the database interface, was less than 1 MB. Then, I was introduced to the potential version conflicts possible with an MDAC. This experience convinced me to stay away from Access databases for my future applications. In desperation, I began using what I affectionately call normalized text files.
The MDAC quirks, along with DLL Hell, have apparently been obviated by the .NET Framework. I am again returning to Access databases as my preferred data storage medium for standalone applications. With my return to the Access fold, I began thinking about a way to simplify the extraction and updating of Access tables in situations such as table maintenance, where the SQL requirements are minimal. I am presently working on three applications, and I can foresee having to write very similar code for many, many table maintenance forms where the database connection string is always the same and the SQL statements differ only in table and column names. It occurred to me that there might be some way to encapsulate all that consistency.
I played with the CommandBuilder object, and found out, thanks to several articles on other sites, that the CommandBuilder is nice for very simple table updates; however, this do-all object can be ornery. It is supposedly very sensitive to such things as table column names that contain a space. Blows the CommandBuilder right out of the water. Special characters do the same. These and other simplistic errors stop the CommandBuilder which, thank you very much, does not seem to include much in the way of meaningful exception messages. In my opinion, the CommandBuilder object is a tool to be wary of for all but exceptionally simple table updates.
The CommandBuilder also does not address the data extraction side of the table maintenance equation. Granted the DataAdapter's Fill method does that nicely, however, SQL and database connection strings must be built before the DataAdapter can be invoked. I envisioned a simpler scenario where the requisite strings would be built for me and then fed to the DataAdapter. I also wanted something that would work for most, if not all, Access tables with no code changes. The concept of a class that would sit between my database table maintenance forms and the database began to take on substance. The Access Table class library is the result.
Follow these steps to make the 2gs_accesstable class library available in a project.
At the top of each class and module in which the C_AccessTable class is consumed, add this statement:
Imports _2gs_accesstable
There are two functions performed by the Access Table object in its role as an interface between an Access table and the form or forms that maintain the data stored in the table.
After instantiating a C_AccessTable object to extract data from the table, you provide the path to the database, the name of the table, and, if needed, the database password. With that information, the Access Table object builds the database connection string and, if you so elect, the SQL query that will extract the needed data. If you prefer, you can code your own SQL query and pass the entire command string to the Access Table object.
With the connection string and SQL query in place, invoking the PopulateDataTable method extracts the needed data. You can then either retrieve a copy of the DataTable for local use in a form, or keep the C_AccessTable object instantiated and work directly with the DataTable via the FilledDataTable property.
What you do with the DataTable to expose its contents to the user is entirely up to you. The DataTable can be bound to a control, or, as is my preference, used as a container in the background, from which a control is populated, and to which the user changes are posted after each change is completed. If you prefer to use the DataTable as a bound data source, the Access Table object exposes a UseCommandBuilder method with which you can post multiple DataTable changes all at once. If, as in my case, you prefer to avoid bound controls like the plague, there are insert, update, and delete methods that will build the needed SQL statements and perform row updates, one row at a time.
The C_AccessTable class affords three constructor options.
| Constructor Option | Signature | Description |
| No parameters | Empty | Instantiate a skeleton object with all properties set to their default values. |
| Database path | String |
The database path is validated and, if valid, a database connection string is built without a password parameter. |
| Database path and password | String, String |
The database password property is set. The database path is validated and, if valid, a database connection string is built. |
The C_AccessTable class exposes five methods. They are listed here in alphabetical order:
| Method | Parameters | Description |
DeleteRow |
DataTable, String |
Builds an SQL DELETE command to remove a row from the Access table. The String parameter is the WHERE expression that identifies the row (or rows) to be deleted. Updates the database and returns True if the delete is successful. False is returned should the delete fail. In the latter case, an error message is displayed that includes the exception Message property along with the complete SQL DELETE statement. |
InsertRow |
DataTable |
Builds an SQL INSERT command to add a row to the Access table. The row being added is assumed to be the highest indexed row in the DataTable. Updates the database and returns True if the insertion is successful. False is returned should the insertion fail. In the latter case, an error message is displayed that includes the exception Message property along with the complete SQL INSERT statement. |
PopulateDataTable |
None |
Populates the The name of the filled |
UpdateRow |
DataTable, Integer, String |
Builds an SQL UPDATE command to update a row in the Access table from the corresponding changed row in the DataTable. The Integer parameter is the index of the DataTable row that was changed. The String parameter is the WHERE expression that identifies the Access table row to be updated. Updates the database and returns True if the update is successful. False is returned should the update fail. In the latter case, an error message is displayed that includes the exception Message property along with the complete SQL UPDATE statement. |
UseCommandBuilder |
None | Updates the Access table with transactions generated by the CommandBuilder object. Transactions are based on the FilledDataTable and SQLString properties. The SQLString property must contain exactly the same SQL query that was originally used to populate the DataTable. Returns the total number of Access table rows that were added, updated, and deleted. If the database update fails, -1 is returned, and an error message is displayed that includes the exception Message property, the complete SQLString property, and the complete database connection string. |
The C_AccessTable class exposes eleven properties. They are listed here in alphabetical order:
| Property | Variable Type | Set Value (=) or (Parameters) | Description |
ConnectionReady |
Boolean |
N/A | Read only property that returns the state of the database connection string. |
DatabasePassword |
N/A | = String |
Write only property that sets the password parameter for the database connection string. Setting the property to Nothing or an empty string clears the property. If the DatabasePath property is set, the database connection string is re-built to update or remove the password parameter. |
DatabasePath |
String |
= String |
Get/set the fully qualified path to the Access database. If the database path validates, the connection string is rebuilt. If the path to the database is not valid, the database connection string is cleared and the ConnectionReady property is set to False. |
DatabaseTableName |
String |
(Boolean) defaults to False |
Get/set the name of the table in the Access database. If the passed table name is enclosed in brackets, the brackets are removed (the table name is enclosed in brackets whenever the name is used in an SQL statement). When a True parameter is also passed, the SQLString property is populated with an SQL SELECT command. |
FilledDataTable |
DataTable |
= DataTable |
Get/set the DataTable. |
SQLDistinct |
Boolean |
= Boolean |
Get/set the flag that specifies if the DISTINCT keyword is to be included when the SQL SELECT statement is built. |
SQLOrderBy |
String |
= String |
Get/set the ORDER BY expression to be included when the SQL SELECT statement is built. When this property is not set, the ORDER BY clause is not included in the SELECT command. |
SQLOrderByAscending |
Boolean |
= Boolean |
Get/set the flag that specifies if the DataTable is to be sorted in ascending or descending sequence. When True, ASC is appended to the ORDER BY clause. DESC is appended when this property is False. |
SQLSelectList |
String |
= String |
Get/set the property holding the list of fields to include in the DataTable. When this property is not set, an asterisk is used for the list of fields in the SQL SELECT statement. |
SQLString |
String |
= String |
Get/set the entire SQL command string. |
SQLWhere |
String |
= String |
Get/set the WHERE expression to be included when the SQL SELECT statement is built. When this property is not set, the WHERE clause is not included in the SELECT command. |
These code samples are all from the demo project. Not all possible uses of the C_AccessTable class are illustrated. However, the UseCommandBuilder method is used to update changed records even though that is out of context with the rest of the code. I did it to show how the CommandBuilder object is used with the C_AccessTable class.
The first item of business when setting up to use the C_AccessTable object is to code the information needed about the Access database table. In the demo project, I put this information in constants in the M_Common module. This gives this information global scope, so it is accessible regardless of where I may need it. This information could also be made available as properties in a class if that is your preference. It doesn't matter as long as the information has the appropriate scope.
In the demo project, the Access database is located in the project's BIN folder. Only the database name is needed for the path.
'** The Access database path and table name
Public Const gtACCESS_TABLE_NAME As String = "Products"
Public Const gtDATABASE_PATH As String = "demo.mdb"
'** the Access table column names
Public Const gtTBL_COL_ADDED As String = "Added"
Public Const gtTBL_COL_PRODNUMBER As String = "ProdNumber"
Public Const gtTBL_COL_DESCRIPTION As String = "Description"
Public Const gtTBL_COL_UOM As String = "UOM"
Public Const gtTBL_COL_PRICE As String = "Price"
Public Const gtTBL_COL_ONHAND As String = "OnHand"
Public Const gtTBL_COL_ONORDER As String = "OnOrder"
With the above information about the target Access table in the code, you are ready to begin extracting data from, and updating that table via the C_AccessTable object.
As I stated previously, I avoid bound controls like the plague. (Please don't ask why. Let's just leave it as a personal preference forged by experience.) In the demo project, a DataTable is populated in a C_AccessTable object, with all rows and columns from the Products table. The populated DataTable is then used to populate the ListView on the main form. This all happens in the main form's PopulateDataTable and PopulateListview procedures. The local copy of the DataTable is stored in a variable dimensioned in the form's declarations section.
#Region " Members "
'** A datatable to contain the database table rows being maintained
Dim theDataTable As New DataTable
#End Region#Region " ... PopulateDataTable "
Private Sub PopulateDataTable(Optional ByVal _
targetItem As Integer = Nothing)
'-----------------------------------------------------
' Populate the datatable from the database
' and then the listview from the datatable
' Pass: targetItem When passed, the item number
' to be selected in the
' listview after
' the listview is populated
' Return: N/A
'-----------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- -------------------
' 05/18/2006 G Gilbert Original code
'-----------------------------------------------------
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
SetDataTableParms(at)
'** Attempt to populate the datatable from the database
If .PopulateDataTable() Then
'** Grab a copy of the populated datatable
theDataTable = .FilledDataTable
'** Populate the listview from the datatable
PopulateListview(targetItem)
Else
'** Populating of the datatable failed. Inform the user
'** and turn off all buttons except Exit.
DisplayOops("Reading of Products from the database failed")
btnNew.Enabled = False
btnChange.Enabled = False
btnRemove.Enabled = False
End If
End With
at = Nothing
End Sub
#End Region
#Region " ... PopulateListview "
Private Sub PopulateListview(Optional ByVal _
targetItem As Integer = Nothing)
'---------------------------------------------------
' Display all of the rows in the datatable
' in the listview
' Pass: targetItem When passed, the number
' of the item to be selected
' in the listview after
' the listview is populated
' Return: N/A
'---------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- -----------------
' 05/11/2006 G Gilbert Original code
'---------------------------------------------------
'---------------------------------------------------
' Populate the listview control
'---------------------------------------------------
With lvwProducts
.BeginUpdate()
.Items.Clear()
For i As Integer = 0 To theDataTable.Rows.Count - 1
Dim li As New ListViewItem
With theDataTable.Rows(i)
Dim dw As New _
C_DateWizard(CType(.Item(gtTBL_COL_ADDED), Date))
li.SubItems(0).Text = dw.BaseDate.ToShortDateString
dw = Nothing
li.SubItems.Add(.Item(gtTBL_COL_PRODNUMBER).ToString)
li.SubItems.Add(.Item(gtTBL_COL_DESCRIPTION).ToString)
li.SubItems.Add(.Item(gtTBL_COL_UOM).ToString)
'** Display two decimal places
' with no thousands separators since
'** the _ThousandsSeparator property
' in the Price Extended Textbox
'** in the New/Change form is set to False
li.SubItems.Add(FormatNumber(.Item(gtTBL_COL_PRICE), _
2, , , _
TriState.False))
li.SubItems.Add(.Item(gtTBL_COL_ONHAND).ToString)
Select Case .Item(gtTBL_COL_ONORDER)
Case True : li.SubItems.Add("Yes")
End Select
End With
.Items.Add(li)
li = Nothing
Next
.EndUpdate()
End With
'--------------------------------------------------
' If a specific item is to be selected, do so;
' otherwise, select the first item
' listed
'--------------------------------------------------
With lvwProducts
If .Items.Count > 0 Then
If targetItem = Nothing Then
'** Select the first item
.Items(0).Selected = True
Else
'** Select the targeted item
For i As Integer = 0 To .Items.Count - 1
If CType(.Items(i).SubItems(1).Text, _
Integer) = targetItem Then
.Items(i).Selected = True
Exit For
End If
Next i
End If
.Select()
End If
End With
End Sub
#End Region
#Region " ... SetDataTableParms "
Private Sub SetDataTableParms(ByRef at As C_AccessTable)
'----------------------------------------------------
' Set the C_AccessTable object parameters
' in preparation for populating the datatable
' Pass: at The C_AccessTable object
' being configured
' Return: N/A
'----------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- ------------------
' 05/20/2006 G Gilbert Original code
'----------------------------------------------------
'** Add an ORDER BY clause to the SQL SELECT
' query to sort on the product number
at.SQLOrderBy = gtTBL_COL_PRODNUMBER
'** Set the Access table name.
' Use the default SQL SELECT command
'** (built in the C_AccessTable class)
' instead of passing a complete
'** SQL string.
at.DatabaseTableName(True) = gtACCESS_TABLE_NAME
End Sub
#End Region
The SetDataTableParms procedure illustrates how easy it is to populate a DataTable. In the demo application, two lines of code are needed to:
ORDER BY expression,
SELECT statement. Back in the PopulateDataTable procedure, the .PopulateDataTable method is then invoked to fill the DataTable. Life is good.
The steps for adding a new Product to the demo database are as follows:
DataTable.
C_AccessTable object.
DataTable and update the ListView. Can you find the two lines of code below that accomplish step 3?
#Region " ... New "
Private Sub btnNew_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnNew.Click
'--------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- ----------------
' 05/11/2006 G Gilbert Original code
'--------------------------------------------------
'--------------------------------------------------
' Tell the add/change form to be in add mode
'--------------------------------------------------
gePO_Box_01 = FormMode.Add
'--------------------------------------------------
' Display the form
'--------------------------------------------------
Dim DialogForm As New F_New_Change
With DialogForm
If .ShowDialog = DialogResult.OK Then
'** Retrieve the new product information from the PO box
TurnOnHourglass(Me)
Dim productFields() As String
productFields = Split(gtPO_Box_01, Chr(12))
gtPO_Box_01 = ""
'** Add the product to the datatable
Dim newRow As DataRow = theDataTable.NewRow
newRow(gtTBL_COL_ADDED) = Now().ToShortDateString
newRow(gtTBL_COL_PRODNUMBER) = CType(productFields(0), Integer)
newRow(gtTBL_COL_DESCRIPTION) = productFields(1)
newRow(gtTBL_COL_UOM) = productFields(2)
newRow(gtTBL_COL_PRICE) = CType(productFields(3), Single)
newRow(gtTBL_COL_ONHAND) = CType(productFields(4), Integer)
newRow(gtTBL_COL_ONORDER) = CType(productFields(5), Boolean)
theDataTable.Rows.Add(newRow)
newRow = Nothing
'** Update the database with the new product
Dim insertedOK As Boolean = True
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
If Not .InsertRow(theDataTable) Then
TurnOnArrow(Me)
DisplayOops("Adding of New Product failed")
insertedOK = False
End If
End With
at = Nothing
'** Refresh the datatable and update the listview if
'** the insert went OK
If insertedOK Then
PopulateDataTable(CType(productFields(0), Integer))
TurnOnArrow(Me)
End If
End If
.Dispose()
End With
'--------------------------------------------------
' Shift the focus back to the listview
'--------------------------------------------------
lvwProducts.Focus()
End Sub
#End Region
Changing a Product in the demo program is, of course, a little more complex than adding a new Product. The user has to be presented with the existing Product information to which changes can be made.
DataTable.
C_AccessTable object.
DataTable and update the ListView. As stated earlier, for illustration purposes, the UseCommandBuilder method is used in the demo project to update changed Product information instead of the more appropriate UpdateRow method. So as to make the demo more complete, the code to invoke the UpdateRow method is also included (commented out) just before the UseCommandBuilder code.
#Region " ... Change "
Private Sub btnChange_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnChange.Click
'-------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- ---------------
' 05/11/2006 G Gilbert Original code
'-------------------------------------------------
'-------------------------------------------------
' Bail if there are no products in the listview
'-------------------------------------------------
If lvwProducts.Items.Count <= 0 Then
Beep()
lvwProducts.Focus()
Exit Sub
End If
'-------------------------------------------------
' Tell the add/change form to be in change mode
'-------------------------------------------------
gePO_Box_01 = FormMode.Change
'-------------------------------------------------
' Build a string to pass the selected
' product info to the dialog box. The date
' added is not passed since that field
' is not entered by the user. Separate the
' product fields with the
' unprintable character Chr(12).
'-------------------------------------------------
Dim sb As New StringBuilder("")
With lvwProducts.SelectedItems(0)
sb.Append(.SubItems(1).Text)
sb.Append(Chr(12))
sb.Append(.SubItems(2).Text)
sb.Append(Chr(12))
sb.Append(.SubItems(3).Text)
sb.Append(Chr(12))
sb.Append(.SubItems(4).Text)
sb.Append(Chr(12))
sb.Append(.SubItems(5).Text)
sb.Append(Chr(12))
If .SubItems.Count > 6 Then
sb.Append("True")
Else
sb.Append("False")
End If
gtPO_Box_01 = sb.ToString
End With
sb = Nothing
'-------------------------------------------------
' Display the form
'-------------------------------------------------
Dim DialogForm As New F_New_Change
With DialogForm
If .ShowDialog = DialogResult.OK Then
'** Retrieve the changed product information from the PO box
TurnOnHourglass(Me)
Dim productFields() As String
productFields = Split(gtPO_Box_01, Chr(12))
gtPO_Box_01 = ""
'** Update the product in the datatable
With theDataTable.Rows(lvwProducts.SelectedItems(0).Index)
.Item(gtTBL_COL_DESCRIPTION) = productFields(1)
.Item(gtTBL_COL_UOM) = productFields(2)
.Item(gtTBL_COL_PRICE) = CType(productFields(3), Single)
.Item(gtTBL_COL_ONHAND) = CType(productFields(4), Integer)
.Item(gtTBL_COL_ONORDER) = CType(productFields(5), Boolean)
End With
'** Update the database with the changed datatable row
Dim updatedOK As Boolean = True
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
'** Update the database using the C_AccessTable object UpdateRow
'** method
'If Not .UpdateRow(theDataTable, _
' lvwProducts.SelectedItems(0).Index, _
' gtTBL_COL_PRODNUMBER & _
' " = " & _
' productFields(0)) Then
' TurnOnArrow(Me)
' DisplayOops("Changing of the Product failed")
' updatedOK = False
'End If
'** When the CommandBuilder object is used to update the database,
'** care must be taken to ensure the SQL statement used by the
'** DataAdapter (in C_AccessTable) is identical to the SQL
'** statement used to originally populate the datatable.
SetDataTableParms(at)
'** Update the database using CommandBuilder
.FilledDataTable = theDataTable
If .UseCommandBuilder < 0 Then
TurnOnArrow(Me)
DisplayOops("Changing of the Product failed")
updatedOK = False
End If
End With
at = Nothing
'** Refresh the datatable and update the listview if
'** the update went OK
If updatedOK Then
PopulateDataTable(CType(productFields(0), Integer))
TurnOnArrow(Me)
End If
End If
.Dispose()
End With
'-------------------------------------------------
' Shift the focus back to the listview
'-------------------------------------------------
lvwProducts.Focus()
End Sub
#End Region
Removing a Product from the demo database is the simplest maintenance task. Instead of displaying the New/Change form, a message is displayed to the user to ensure that they want to delete the Product selected in the ListView and, after the user confirms, the Product is deleted.
DataTable.
C_AccessTable object.
DataTable and update the ListView. Note that, in this case, the product is not deleted from the DataTable before the record is removed from the table in the database. The product is deleted from the DataTable when the DataTable is refreshed from the database just before the ListView is updated.
#Region " ... Remove "
Private Sub btnRemove_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles btnRemove.Click
'---------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- -----------------
' 05/15/2006 G Gilbert Original code
'---------------------------------------------------
'---------------------------------------------------
' Bail if there are no products in the listview
'---------------------------------------------------
If lvwProducts.Items.Count <= 0 Then
Beep()
lvwProducts.Focus()
Exit Sub
End If
'---------------------------------------------------
' Ensure the user is serious
'---------------------------------------------------
Dim removeMsg As String
Dim sb As New StringBuilder("")
With sb
.Append(lvwProducts.SelectedItems(0).SubItems(1).Text)
.Append(" ")
.Append(lvwProducts.SelectedItems(0).SubItems(2).Text)
.Append(vbCrLf)
.Append(vbCrLf)
.Append("Delete this product?")
removeMsg = .ToString
End With
sb = Nothing
If MessageBox.Show(removeMsg, _
"Remove Product", _
MessageBoxButtons.OKCancel, _
MessageBoxIcon.Question, _
MessageBoxDefaultButton.Button2) = DialogResult.OK Then
'** Update the database to remove the deleted row
TurnOnHourglass(Me)
Dim deletedOK As Boolean = True
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
If Not .DeleteRow(theDataTable, _
gtTBL_COL_PRODNUMBER & _
" = " & _
lvwProducts.SelectedItems(0).SubItems(1).Text) Then
TurnOnArrow(Me)
DisplayOops("Removal of the Product failed")
deletedOK = False
End If
End With
at = Nothing
'** Refresh the datatable and update the listview if
'** the delete went OK
If deletedOK Then
PopulateDataTable()
TurnOnArrow(Me)
End If
End If
'---------------------------------------------------
' Shift the focus back to the listview
'---------------------------------------------------
lvwProducts.Focus()
End Sub
#End Region
The C_AccessTable class can be useful for other than maintaining an Access table. Data extractions can be done by either coding a complete SQL statement and then using it to set the C_AccessTable SQLString property, or by manipulating the SQL properties to customize the automatically generated SELECT statement. In the example below from the demo project, a list of existing UOM (Unit of Measure) codes is extracted from the Products table and displayed in the New/Change form as a reference for the user. (When the user clicks on a UOM code in the list, the clicked code is copied to the UOM textbox.)
#Region " ... ListUOMs "
Private Sub ListUOMs()
'---------------------------------------------------
' List all existing Units of Measure as a reference
'---------------------------------------------------
' Date Developer Code Change
' ---------- -------------------- -----------------
' 05/20/2006 G Gilbert Original code
'---------------------------------------------------
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
'** List each UOM only once
.SQLDistinct = True
'** Override the default * in the SELECT
' query to select only the UOM
'** column
.SQLSelectList = gtTBL_COL_UOM
'** Sort the UOMs (ascending sequence is default)
.SQLOrderBy = gtTBL_COL_UOM
'** Build the SQL SELECT query
.DatabaseTableName(True) = gtACCESS_TABLE_NAME
'** Populate the datatable and, if there are UOMs on file, list
'** same
If .PopulateDataTable Then
For i As Integer = 0 To .FilledDataTable.Rows.Count - 1
lstUOM.Items.Add(.FilledDataTable.Rows(i).Item(0))
Next
End If
End With
at = Nothing
End Sub
#End Region
In the demo project, part of the editing of the user's input for a new Product is checking that the Product number is not already in use. This requires building and executing a SQL SELECT statement that tries to read a record from the Products table that has a specific number. The code below does this by setting the C_AccessTable SQLWhere property. Note that the WHERE expression does not include the WHERE keyword.
'** Check if the product number is already assigned
Dim duplicateRecords As Integer = 0
Dim at As New C_AccessTable(gtDATABASE_PATH)
With at
'** Add a WHERE clause to the default SQL command
.SQLWhere = gtTBL_COL_PRODNUMBER & " = " & txtNumber.Text
'** Set the Access table name. Use the default SQL SELECT command
'** (built in the C_AccessTable class) instead of passing a complete
'** SQL string.
.DatabaseTableName(True) = gtACCESS_TABLE_NAME
'** Attempt to populate the datatable
If .PopulateDataTable() Then
duplicateRecords = .FilledDataTable.Rows.Count
End If
End With
at = Nothing
If duplicateRecords > 0 Then
DisplayOops("That Number is already in use")
txtNumber.Focus()
Exit Function
End If
There are no points of interest that come to mind for this article. It was interesting doing the needed research, but nothing worth mentioning.
With three fairly large VB.NET projects (one of which includes some ASP.NET) staring me in the face, I feel more confident in my timeline with the C_AccessTable class in my tool bag. I think it will save me significant coding time. Here's hoping you find the same to be true.
You may use all code offered in this article any way you choose without restriction.
Under no circumstances, and under no legal theory, tort, contract or otherwise, will George Gilbert (hereafter referred to as "software author") or his licensors, be liable to the user of the Double Text library and all code offered in this article (hereafter referred to collectively as "article code") for any damages, including any lost profits, lost data, or other indirect, special, incidental or consequential damages, arising out of the use or inability to use the article code, and data or information supplied, even if the software author, his licensors or authorized dealer have been advised of the possibility of such damages, or for any claim by any other party.
WHERE expression is not needed when updating tables that contain only one row. To allow for this situation, the whereExpression parameter of the UpdateRow method has been made optional. The method will also work if an empty string is passed for the whereExpression.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 12 Sep 2006 Editor: Smitha Vijayan |
Copyright 2006 by George B Gilbert Everything else Copyright © CodeProject, 1999-2009 Web22 | Advertise on the Code Project |