š VB.NET Phonebook Example Using Disconnected Mode (with MS Access Database)

Welcome back! If you've already explored our Connected Mode tutorial, you're ready to level up with Disconnected Mode in ADO.NET. Unlike Connected Mode, where we constantly interact with the database, Disconnected Mode lets us load data into memory, work on it offline, and update the database only when needed. This is perfect for apps like our phonebook, especially in scenarios with limited database access.
In this tutorial, we'll adapt our Phonebook project to use Disconnected Mode, leveraging key ADO.NET components:
OleDbDataAdapter
: Transfers data between the database and our in-memoryDataSet
.DataSet
: Stores data offline, acting like an in-memory database.CommandBuilder
: Automatically generates SQL commands for inserting, updating, and deleting records.
Ready to dive in? Let's get started!
š Project Setup
We're using the same setup as our Connected Mode tutorial, so if you're familiar with that, you're good to go. Here's a quick recap:
Database: We have an MS Access database named PhoneB.accdb
with a table called Phone1
. The table includes columns for:
Fname
,Lname
,Country
,City
,Phone
,Mobile
,Lemail
(all Short Text)Lphoto
(OLE Object for storing image byte arrays)
Form: Our form, MainForm
, includes:
- TextBoxes:
TxtFname
,TxtLname
,TxtCountry
,TxtCity
,TxtPhone
,TxtMobile
,TxtLemail
- PictureBox:
P_Lphoto
for displaying photos - Buttons:
BtnNew
,BtnSave
,BtnEdit
,BtnDelete
,BtnSearch
,BtnLoad
,BtnExit
- DataGridView:
DG1
to display all records
š” Step 1: Setting Up Global Variables and Form Load
First, we need to define our global variables and initialize the form. This sets up the connection to our database and prepares the DataSet
for offline work.
Imports System.Data.OleDb Imports System.IO Public Class MainForm ' Connection string for the MS Access database Dim connStr As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=PhoneB.accdb" ' Connection object Dim conn As New OleDbConnection(connStr) ' DataAdapter for data transfer Dim da As OleDbDataAdapter ' DataSet to hold data in memory Dim ds As New DataSet() ' CommandBuilder for generating SQL commands Dim cb As OleDbCommandBuilder ' Form Load event to initialize the form Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load ' Set default image for PictureBox P_Lphoto.InitialImage = My.Resources.Image_no ' Load data into DataSet LoadDataIntoDataSet() End Sub
š” Step 2: Loading Data into DataGridView
Next, we load data from the database into our DataSet
and display it in the DataGridView
. This is done once, and all operations happen in memory until we update the database.
Sub LoadDataIntoDataSet() Try ' Create DataAdapter to fetch data from Phone1 table da = New OleDbDataAdapter("SELECT * FROM Phone1", conn) ' Generate SQL commands automatically cb = New OleDbCommandBuilder(da) ' Clear existing data in DataSet ds.Clear() ' Fill DataSet with data da.Fill(ds, "Phone1") ' Bind DataTable to DataGridView DG1.DataSource = ds.Tables("Phone1") ' Customize DataGridView headers and image column RenameDG1Headers() ResizeImageColumn() Catch ex As Exception MsgBox("Error loading data: " & ex.Message) End Try End Sub
š” Step 3: Displaying Data on Row Click
When a user clicks a row in the DataGridView
, we populate the text boxes and PictureBox
with the selected record's data, all from the in-memory DataSet
.
Private Sub DG1_CellClick(sender As Object, e As DataGridViewCellEventArgs) Handles DG1.CellClick If e.RowIndex >= 0 Then Dim row As DataGridViewRow = DG1.Rows(e.RowIndex) ' Populate text boxes with row data TxtFname.Text = row.Cells("Fname").Value?.ToString() TxtLname.Text = row.Cells("Lname").Value?.ToString() TxtCountry.Text = row.Cells("Country").Value?.ToString() TxtCity.Text = row.Cells("City").Value?.ToString() TxtPhone.Text = row.Cells("Phone").Value?.ToString() TxtMobile.Text = row.Cells("Mobile").Value?.ToString() TxtLemail.Text = row.Cells("Lemail").Value?.ToString() ' Load photo if available If row.Cells("Lphoto").Value IsNot DBNull.Value Then Dim imgData As Byte() = CType(row.Cells("Lphoto").Value, Byte()) Using ms As New MemoryStream(imgData) P_Lphoto.Image = Image.FromStream(ms) End Using Else P_Lphoto.Image = Nothing End If End If End Sub
š” Step 4: Saving a New Record
To add a new contact, we create a new row in the DataTable
, fill it with data from the text boxes, and update the database using the DataAdapter
.
Private Sub BtnSave_Click(sender As Object, e As EventArgs) Handles BtnSave.Click If String.IsNullOrEmpty(TxtFname.Text) OrElse String.IsNullOrEmpty(TxtLname.Text) Then MsgBox("First and Last name are required.") Exit Sub End If Try ' Create new row in DataTable Dim newRow As DataRow = ds.Tables("Phone1").NewRow() ' Fill row with text box data newRow("Fname") = TxtFname.Text newRow("Lname") = TxtLname.Text newRow("Country") = TxtCountry.Text newRow("City") = TxtCity.Text newRow("Phone") = TxtPhone.Text newRow("Mobile") = TxtMobile.Text newRow("Lemail") = TxtLemail.Text ' Handle photo if present If P_Lphoto.Image IsNot Nothing Then Using ms As New MemoryStream() P_Lphoto.Image.Save(ms, Imaging.ImageFormat.Jpeg) newRow("Lphoto") = ms.ToArray() End Using Else newRow("Lphoto") = DBNull.Value End If ' Add row to DataTable and update database ds.Tables("Phone1").Rows.Add(newRow) da.Update(ds, "Phone1") LoadDataIntoDataSet() ClearAll() MsgBox("Saved successfully.") Catch ex As Exception MsgBox("Error saving data: " & ex.Message) End Try End Sub
š” Step 5: Editing a Record
To edit a contact, we find the row in the DataTable
using the first name, update its values, and save changes to the database.
Private Sub BtnEdit_Click(sender As Object, e As EventArgs) Handles BtnEdit.Click Try Dim fnameKey As String = TxtFname.Text Dim rows() As DataRow = ds.Tables("Phone1").Select("Fname = '" & fnameKey.Replace("'", "''") & "'") If rows.Length > 0 Then With rows(0) ' Update row with new values .Item("Lname") = TxtLname.Text .Item("Country") = TxtCountry.Text .Item("City") = TxtCity.Text .Item("Phone") = TxtPhone.Text .Item("Mobile") = TxtMobile.Text .Item("Lemail") = TxtLemail.Text ' Update photo if present If P_Lphoto.Image IsNot Nothing Then Using ms As New MemoryStream() P_Lphoto.Image.Save(ms, Imaging.ImageFormat.Jpeg) .Item("Lphoto") = ms.ToArray() End Using Else .Item("Lphoto") = DBNull.Value End If End With ' Save changes to database da.Update(ds, "Phone1") LoadDataIntoDataSet() ClearAll() MsgBox("Record updated.") Else MsgBox("Record not found for update.") End If Catch ex As Exception MsgBox("Error editing record: " & ex.Message) End Try End Sub
š” Step 6: Deleting a Record
To delete a contact, we find the row by first name, mark it for deletion, and update the database.
Private Sub BtnDel_Click(sender As Object, e As EventArgs) Handles BtnDel.Click Try Dim fnameKey As String = TxtFname.Text Dim rows() As DataRow = ds.Tables("Phone1").Select("Fname = '" & fnameKey.Replace("'", "''") & "'") If rows.Length > 0 Then ' Mark row for deletion rows(0).Delete() ' Update database da.Update(ds, "Phone1") LoadDataIntoDataSet() ClearAll() MsgBox("Record deleted.") Else MsgBox("Record not found for deletion.") End If Catch ex As Exception MsgBox("Error deleting record: " & ex.Message) End Try End Sub
š” Step 7: Searching by First Name
Searching is fast in Disconnected Mode since all data is in memory. We use the Select
method to find a record by first name and display it.
Private Sub BtnSearch_Click(sender As Object, e As EventArgs) Handles BtnSearch.Click Dim fnameKey As String = InputBox("Enter First name.") Dim rows() As DataRow = ds.Tables("Phone1").Select("Fname = '" & fnameKey.Replace("'", "''") & "'") If rows.Length > 0 Then With rows(0) ' Populate text boxes with found record TxtFname.Text = .Item("Fname").ToString() TxtLname.Text = .Item("Lname").ToString() TxtCountry.Text = .Item("Country").ToString() TxtCity.Text = .Item("City").ToString() TxtPhone.Text = .Item("Phone").ToString() TxtMobile.Text = .Item("Mobile").ToString() TxtLemail.Text = .Item("Lemail").ToString() ' Load photo if available If Not IsDBNull(.Item("Lphoto")) Then Dim imgBytes() As Byte = CType(.Item("Lphoto"), Byte()) Using ms As New MemoryStream(imgBytes) P_Lphoto.Image = Image.FromStream(ms) End Using Else P_Lphoto.Image = Nothing End If End With Else MsgBox("Record not found.") End If End Sub
š Final Notes
- Photo Handling: We use
FileStream
and byte arrays to store images in theLphoto
column. - Error Handling: Always use Try/Catch blocks to catch and display errors gracefully.
- Resource Management: While this example uses a class-level connection, consider using
Using
blocks for connections to ensure proper disposal. - Scalability: Disconnected Mode is great for small datasets like this phonebook but may consume more memory for larger datasets.
That's it! You've built a fully functional phonebook app using VB.NET and ADO.NET in Disconnected Mode. This approach makes your app efficient and robust, especially in low-connectivity scenarios. Try out the code, download the project, and let us know in the comments if you have questions or ideas to enhance it. Happy coding!
No comments:
Post a Comment