Академический Документы
Профессиональный Документы
Культура Документы
NET 2005
Short Notes
Chapter 3: Object Oriented Programming with VB.NET
1. Class Basics
A class is one form of data type. In object-oriented design, classes are intended to represent the definition of
real-world objects, such as customer, order, product, etc. The class is only the definition, not an object itself. An
object would be a customer, an order, or a product. A class declaration defines the set of members— fields,
properties, methods, and events— that each object of that class possesses. Together, these members define an
object's state, as well as its functionality. An object is also referred to as an instance of a class. Creating an
object of a certain class is called instantiating an object of the class.
Eg.1.
Public Class Employee
Public EmployeeID As Integer
Public FIrstName As String
Public LastName As String
Public DateOfBirth As Date
Public Salary As Decimal
Public Function Format( ) As String
Return FirstName & " " & LastName
End Function
End Class
The code in the Example defines a class called Employee. It has five public fields (also known as
data members) for storing state, as well as one member function. The class could be used as shown
in Eg. 2.
Class TestEmployee
Dim emp As New Employee( )
emp.EmployeeID = 10
emp.FirstName = "Lamma"
emp.LastName = "Bekele"
emp.DateOfBirth = #1/28/1965#
emp.Salary = 5000
P age |1
The resulting output is:
To taste the avove example in using visual studio. Start a new console application and type the entire code (both classes in
Eg.1. and Eg. 2 ) by deleting the default module block. After you finish writing the code change the project start up object
to TestEmployee. Finally, run the application.
The Dim statement declares a variable that is capable of holding a reference to an object of type Employee, but it
doesn't actually create the object. You must use the New operator in either of the two ways shown above.
2. Fields
Fields, also known as data members, hold the internal state of an object. Their declarations appear only within class
declarations. Field declarations include an access modifier, which determines how visible the field is from code outside
the containing class definition. The value stored in a field is specific to a particular object instance. Two instances can
have different values in their corresponding fields. For example:
Dim emp1 As New Employee( )
Dim emp2 As New Employee( )
emp1.EmployeeID = 10
emp2.EmployeeID= 20 'this doesn't affect emp1.
Sometimes it is desirable to share a single value among all instances of a particular class. Declaring a
field using the Shared keyword does this, as shown here:
Public Class Sample
Public Shared Val As Integer
End Class
Changing the field value through one instance affects what all other instances see. For example:
…
Dim Smp1 As New Sample( )
Dim Smp2 As New Sample( )
Samp1.Val = 10
Samp2.Val = 20
Console.WriteLine(Samp1.VaL) ' Writes 20, not 10.
P age |2
One important characteristic of Shared is that they are also accessible through the class name. This is because their
scope is indirectly the entire class instead of an instance. For example the following statement is correct.
Console.WriteLine(Sample.Val)
…
3. Methods
Methods are members that contain code. They are either subroutines (which don't have a return value) or functions
(which do have a return value).
Subroutine definitions look like this:
[method_modifiers ] Sub [ attribute_list ] _
method_name ( [ parameter_list ] ) [ handles_or_implements ]
[ method_body ]
End Sub
Function definitions look like this:
[method_modifiers] Function [ attribute_list ] _
method_name ( [ parameter_list ] ) [ As type_name ] _
[ handles_or_implements ]
[ method_body ]
End Function
The elements of method definitions are:
Access modifiers : Public, Protected, Friend, Protected Friend, or Private. If no access-modifier keyword is given, Public
is assumed.
Shared keyword specifies that this method does not access object state. That means that the method does not access
any nonshared members.
Sub or Function keyword
Specifies whether this method is a subroutine or a function.
method_name The name of the method.
parameter_list an optional list of formal parameters for the method.
As type_name for functions only, the data type of the value returned from this function. If Option Strict is off, the As
type_name clause is optional; otherwise, it is required. If it is omitted, the function's return type defaults to Object.
Subroutine declarations do not have an As type_name clause. handles_or_implements Either the Handles keyword
followed by a list of events from the enclosing class's data members, or the Implements keyword followed by a list of
methods from an interface implemented by the enclosing class
method_body :Visual Basic .NET statements.
End Sub or End Function keywords Indicates the end of the method definition.
Method parameters
Methods can be defined to take arguments. As already shown, method definitions can take an optional
parameter list. A parameter list looks like this:
parameter { , parameter }
That is, a parameter list is one or more parameters separated by commas. Each parameter in the list is of the form:
[ Optional ] [ ParamArray ] [ ByRef | ByVal ] [ attribute_list ] _
parameter_name [ As type_name ] [ = constant_expression ]
The elements of each parameter declaration are:
Optional keyword
Specifies that an actual argument may be omitted for this parameter in a call to this method. If Optional is specified, the
= constant_expression, which defines the default value of an omitted argument, must also be specified. Nonoptional
P age |3
parameters can't follow optional parameters in a parameter list. Optional and ParamArray parameters can't appear in
the same parameter list ParamArray keyword Specifies that the caller can provide a variable number of arguments. The
actual arguments are passed to the method in an array. Only the last parameter in a list may have the ParamArray
keyword attached to it. Optional and ParamArray parameters can't appear in the same parameter list.
ByRef or ByVal keyword Specifies whether the actual argument will be passed to the method by reference or by value.
When an argument is passed by reference, the address of the argument is passed to the routine; as a result,
assignments to the parameter within the method affect the argument in the calling environment. When an argument is
passed by value, a copy of the argument is passed to the routine; as a result, assignments to the parameter within the
method do not affect the argument in the calling environment. Consider this code:
Public Sub TestByRef(ByRef MyParameter As Integer)
MyParameter += 1
End Sub
Public Sub TestByVal(ByVal MyParameter As Integer)
MyParameter += 1
End Sub
Public Shared Sub DoTest( )
Dim x As Integer = 1
TestByRef(x)
Console.WriteLine("x = " & x)
Dim y As Integer = 1
TestByVal(y)
Console.WriteLine("y = " & y)
End Sub
The output of the DoTest method is:
x=2
y=1
The TestByRef and TestByVal methods both increment the values of the arguments passed to them by one. However,
because the parameter of the TestByRef method is ByRef, the new value is written back to the argument in the caller (in
this case, the variable x in the DoTest method). In contrast, the TestByVal method's parameter is ByVal, so the
assignment to the parameter doesn't affect the caller. Be aware of the effects of ByRef and ByVal on arguments that are
reference types. ByRef means that a reference to the reference is being passed; ByVal means that the reference itself is
being passed. That means that inside the method, the reference could be used to modify the state of the object in the
calling environment.
P age |4
a(0) = "First"
a(1) = "Second"
a(2) = "Third"
a(3) = "Fourth"
a(4) = "Fifth"
SomeMethod(a)
End Sub
In the SomeMethod method, parameter x represents an array of String objects. In the TestSomeMethod method, a
String array is allocated, its elements are assigned, and the array as a whole is passed to the SomeMethod method,
which then prints the array's contents. All array types are reference types. That means that when passing an array as a
parameter, only a reference to the array is passed. Because the target method receives a reference to the array, the
array elements can be changed by the method, even if the array reference was passed by value. If the array reference is
passed by reference, the array reference itself can be changed by the method. For example, the method could allocate a
new array and return it through the ByRef parameter, like this:
Main method
When an executable application is compiled, some code must be identified as the startup routine. This portion is what is
executed when the application is run. The Visual Basic .NET compiler looks for a method named Main to fulfill this need.
In .NET, all code exists as methods within classes, even the Main method. To make it accessible without having to
instantiate a class, the Main method must be declared as shared. For example:
Public Class App
Public Shared Sub Main( )
' ...
End Sub
End Class
The name of the class is not important. At compile time, the Visual Basic .NET compiler looks for a public shared
subroutine named Main somewhere in the code. If more than one class has such a method, the developer must specify
which one to use by setting the startup object in the Project Properties dialog box. A program's Main method can also
appear within a Visual Basic .NET module (not to be confused
with .NET modules. Because Visual Basic .NET modules are classes wherein everything is shared, the Shared keyword is
not used in such a declaration:
Module App
Public Sub Main( )
' ...
End Sub
End Module
4. Properties
In Visual Basic .NET a property is similar to a field but a property is more encapsulated than a field. First, a property data
is stored as private. Second, two property procedures will be written for accessing the property. These procedures are
Get and Set procedures. This is important if you want to protect data from unwanted modifications and access from
outside the class. The property procedures are written within the Property… End Property block, which defines the
property’s nam e,its type,and its argum ent signature.
Inside the Property block,you w rite a G et… End G et block,w hich defines w hat value the property returns,and a Set… End
Set block, which defines how values are assigned to the property. In most cases, a property simply maps to a Private
Field, so the code for these two blocks often looks like this:
P age |5
Eg. 4.
Class PropSample
‘You can define variables anyw here in a class or m odule.
Dim m_BirthDate As Date
Property BirthDate() As Date
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date) ‘this procedure can validate the value
If value <= Date.Now Then
m_BirthDate = Value
Else
M_BirthDate= Date.Now
End If
End Set
End Property
…
End Class
Alternatively, the Get block can return the value by assigning the variables value to the Property method.
Property BirthDate() As Date
Get
‘Another w ay to return a value
BirthDate = m_BirthDate
End Get
End Property
The Set… End Set block alw ays receives a Value argum ent that stands for the value being assigned to the property itself.
This argument must be of the same type as the type defined in the Property statement and must be declared using
ByVal. If you happen to have a field named Value, you can distinguish between the field and the Value
A User of the above class can work with it as if the there is a public or shared member is used.
Class TestPropSample
Dim Ps as New PropSample
Public Function SetBirthdate( dt as Date)
Ps.BirthDate = dt
Console.WriteLine(Ps.BirthDate)
End function
End Class
To access a data member or field from within the class, you can prefix it with the Me keyword
‘A class that has a Value field
Class ValueClass
Private Value As Double
‘A property that uses the Value field
Property DoubleValue() As Double
Get
P age |6
Return Me.Value * 2
End Get
Set(ByVal newValue As Double)
Me.Value = newValue / 2
End Set
End Property
End Class
Note that Me.Value is a legal syntax, even if the Value field is private.
Similarly, you can create a write-only property by om itting the G et… End G et block and using the WriteOnly keyword in
the Property block:
‘LoginD ate is a w rite-only property.
WriteOnly Property LoginDate() As Date
Set(ByVal Value As Date)
m_LoginDate = Value
End Set
End Property
WriteOnly properties are can not be read where as ReadOnly properties can not be written to by and user class
5. Constructors
When a class is instantiated, some initialization often might be performed before the type can be used as it contains
several fields and methods that may require initial values. To provide such initialization, a class may define a
constructor. A constructor is a special kind of method. It is automatically run whenever an object of the class is
instantiated. Constructor declarations use the same syntax as regular method declarations, except that in place of a
method name, the constructor declaration uses the keyword New with in the class. For example:
The message – I am just Initalized !!! – will be displayed when this line executes.
P age |7
Note the parentheses (( )) following the name of the class. Until you get used to it, this method-style syntax following a
class name may appear odd. However, the empty parentheses indicate that the class's constructor takes no arguments.
Constructors can take arguments, if they are necessary for the initialization of the object such constructors are called
parameterized constructors:
When objects of this class are instantiated, a value must be provided for the constructor's argument:
Eg. Dim obj As New SomeClass(27)
This behavior leads us to the possibility that more than one constructor may be used in a class which is called
overloading. Constructors can be overloaded, if desired. For example:
The shared constructor is guaranteed to run sometime before any members of the type are referenced.
If any shared fields have initializers in their declarations, the initializers are assigned to the fields
before the shared constructor is run. Shared constructors may not be overloaded, nor may they have access modifiers
(Public, Private, etc.). Neither feature is meaningful in the context of shared constructors.
P age |8
6. An Example
The following class diagram shows a sample relationship between the classes of a very simple grading application. The
Grade class generally is the user of the Student and the Course Classes. Hence, every instance of the Grade class must
also instantiate objects of the other two classes.
The Classes are implemented as follows. Start a console application and write the following code to test the application.
The application is concerned with storing a grade. But it requires objects that store the course and the Student
Information.
Eg. 5.
Namespace Grading ‘ this namespase is optional
P age |9
Public Function GetAge() As Integer
Return Date.Today.Year - m_BirthDate.Year
End Function
Class Course
Dim m_CourseID As String
Dim m_CourseName As String
Dim m_CreditHours As Byte
Class Grade
Dim Stud As New Student
Dim Cour As New Course
Dim m_sem As String
Dim m_sYear As String
Dim m_Grade As String
Dim ValidGrades As String = "A A+ A- B B+ B- C C+ C- D D+ D- F"
P a g e | 10
Stud.StudentID = sID
' Stud.BirthDate = ....
Cour.CourseId = CID
'Cour.CreditHOurs ....
Me.Grade = Gr
End Sub
End Function
End Class
____________________________________________________________________________
Public Class GradeUser ' This implements the grade class and the others
Public Shared Sub Main()
Dim StudGrade As New Grade()
StudGrade.SetStudentRec("001", "CS-235", "A+")
Console.WriteLine("Points for " & StudGrade.Grade & ": " &
StudGrade.GetPoints())
Console.WriteLine()
Console.WriteLine("Here is the student information")
Console.WriteLine()
StudGrade.DisplyInfo()
Console.ReadLine()
End Sub
End Class
End Namespace
P a g e | 11
Windows Programming with Visual Basic .NET
Worksheet I
1. Create a console application in Visual Basic .NET that accepts a list of Numbers of any size and then displays the
following report on the numbers.
a. The largest value
b. The smallest Value
c. The Sum
d. The average
e. The number of negative values
f. The Number of positive values
2. Write a console application that implements a simple payroll processing. The program displays a menu for
performing the following tasks
a. Accept a new employee information (ID, Name, Salary values)
b. Display existing information ( a Tabular output)
c. Display information about a given employee
d. Display a paryroll by calculating and including the Tax, and Net Pay ( in a tabula format) .
[ use the Ethiopian Tax rule to calculate the Tax)
Output sample
ID Name Salary Tax NetPay
001 Abebe M. 500 50 450
034 Hirut S. 600 60 540
…
3. Implement a simple library application that contains about four interacting objects roughly shown below.
Book Loan
BookNo LBook: Book Member
Title LMember: Member MemberID
Author IssuDate FullName
Publisher DueDate Phone
… GetOverDue () …
SetNewLoanRec () GetAddress ()
.. …
Publisher
PublisherID
PubName
City
Country
…
P a g e | 12
7. Inheritance
Inheritance is implemented in visual basic using the Inherits keyword. The following diagram shows a
typical class inheritance hierarchy.
Person
Employee BusinessPerson
The Class Person is called the Base Class and the other two are called Derived Classes. The derived
classes inherit all inheritable elements of the Base Class and add their own new members. A derived
class also can extend methods defined in the base class by overloading or overriding.
Note that in terms of class inheritance VB.NET supports only Single Inheritance and its extensions. A
derived class can not inherit from more than one class.
Class Person
P a g e | 13
Property BirthDate() As Date
Get
Return m_BirthDate
End Get
Set(ByVal Value As Date)
m_BirthDate = Value
End Set
End Property
End Class
Class Employee
Inherits Person
End Function
P a g e | 14
End Class
Class EmpTest
Console.WriteLine("**************************")
Console.WriteLine() 'Empty line
Console.WriteLine("Spouse information")
Console.WriteLine(emp.Spouse.CompleteName)
Console.WriteLine("Address: " & emp.Spouse.Address)
Console.WriteLine("Birth Date: " & String.Format("{0:d}",
emp.Spouse.BirthDate)) ' Short date format
Console.ReadLine()
End Sub
End Class
P a g e | 15
Overriding Base Cass Methods
Methods can be defined with the same name in both the base class and the derived class. In this case,
the base class must allow the derived class to override its definition by declaring the method using the
Overridable keyword. Otherwise, the two functions will be considered as different for the two classes.
In general there are four basic types of method declarations concerning how the method will be treated
by derived classes. They are summarized as follows:
MustOverride Enforces that the function must be redefined. Protected Must Override Sub Add()
In this case the method will not have a body
in the base class
In derived Overrides Indicates that this the method overrides Public Overrides Function F1()
Classes another one in its base class … ..
End Function
End Class
P a g e | 16
' This second version of the Person class demonstrates overloaded
constructors,
Class Employee
Inherits Person
End Class
P a g e | 17
Class Base
Protected ID As Integer
Protected Friend PhoneNumber As String
Private Password As String
Public FullName As String
...
End Class
P a g e | 18
9. Interfaces
Interfaces are special programming language constructs used to implement several things such us polymorphism
and multiple inheritance(at least partially). An interface is a code block that contains constant declarattions and
method prototypes. Interfaces can not be instantiated. An interface must be implemented by a class inorder to be
used. Instances can be created from the class that implemts an interface. A class must implement the methods of
the interface it implements.
There are two types of interfaces. .NET interfaces and Custom interfaces. .NET interfaces are predefined with in
the .NET framewrok. Where as Custom interfaces are user defined.
IClonable: this interface also contains one method called Clone() which is used to create a duplicate copy of an
object (instance) so that it can be assined to an other reference.
Function Clone () as Object
Note that different classes can implement an interface using their own way which is an indication of polimorphic
behavior implemetntation.
End Class
P a g e | 19
Implementing multiple interfaces
A class can implement multiple interfaces but can inherit from only one class. As an example the above class
Employee can be modified as follows. The complete version is left as an exercice.
End Class
Interface IAsset
Property Division() As String
Function GetID() As Integer
End Interface
Class Computer
Implements IAsset
Get
Return divisionValue
End Get
Set(ByVal value As String)
divisionValue = value
End Set
End Property
Return IDValue
End Function
P a g e | 20
Interface IPerson 'IPerson interface definition
Property LastName( ) As String
Sub Display( )
End Interface
Class Employee 'Employee class definition
Implements IPerson 'Implements IPerson interface
Private strName As String
Private strCompany As String
'This method is public but also implements IPerson.Display
Public Sub Display( ) Implements IPerson.Display
MsgBox(LastName & " " & Company,, "Employee")
End Sub
'This property is private but implements IPerson.LastName
Private Property LastName( ) As String _
Implements IPerson.LastName
Get
Return strName
End Get
Set (ByVal Value As String)
...
End Property
Public Property Company( ) As String
...
End Property
End Class
P a g e | 21
Chapter 4: Working with Windows Forms (Visual Design)
1. Windows Programming Basics
One of the most important features of microsoft .NET is its inherent ablity to design applications for the
windows opertating system. Such applications will provide visual ( Graphical ) user interfaces to their
users. The basis for Graphical User Interface (GUI) based applications is called a Windows Form. All
windows that you work with are built from a form. Hence, the development of such applications
requires two related tasks from a developer. First the Window layout of the application must be
designed ( Visual design). Second, the code that makes the applications work must be written in relation
to user actions on the application’s w inddw such as cliking a button or a menu command. Such user
actions are called Events. The code you write to interact with events is called an Event Handler. Such
applications are often called Event Driven Applications. You usually create such applications using .NET.
The following diagram shows an example of a windows application. It has a form which conatins a
textbox and a botton. When a user clicks on the button the click event will be fired, in resoponse the
coder written as an event handler executes and displays “H ello U ser?!” on the text box.
P a g e | 22
3. Add the two controls, i.e., the TextBox and the Button.
To add a control to the form, Select it from the Tool Box and Draw it on the form.
4. Change the text displayed on the Button. To do so, use the Property sheet that is usually
displayed at the right side of the Form Designer.
a. Select the button
b. Go to the Text property and set it to “H ello”
5. Add the Event Handler procedure that displays the text “H ello U ser?!” on the text box
a. Doubleclick the botton
The code editer with the event handler template opens
b. Then add the following code;
Textbox.Text = “H ello U ser?!”
End Sub
End Class
A partial view of the toolbox A partial view of the Property Sheet with a form
selected
Controls
Other
Control
Categories
Figure 4.2: The ToolBox(left) where you select controls and the PropertySheet(right) where you set design time
Propertis of your controls and forms.
P a g e | 23
Common properties of forms and controls
Name: The name of the form. You use it for programatically accesing the the objects ( Form1, Textbox1,
Button1, etc are default names in VB.Net.
VB.NET naming conventions
Microsoft recommends are the following prefixes be used in naming your visual interface objects.
Object Sample Object Description Prefix Example
Form Serves as a container window for applications frm frmHelloSample
TextBox Displays text editable by users txt txtHelloMessage
Text: is the visible text displayed on objects (a form ’s title,a botton’s text,value ofa TextBox,etc)
P a g e | 24
Size: difines the actual width and heith of several objects such as forms and listboxes, etc
ForColor:defines the forgrown color of an object (Eg. text color ofa TextBox,color ofa botton’s text)
BackColor: defined the background color of the object(Eg.Color ofthe form ,TextBox itself,… )
Reading Assignment: Study other common controls that you may use in your applications. Some are
listed below:
ListView
MaskedTextbox
RichTextbox
Timer
MonthCalander
DateTimePicker
Scrollbars (VScrollBar, HScrollBar)
ProgressBar
TrackBar
ErrorProvider
Panel
StatusStrip/StatusBar
Treeview
TabControl
Windows dialobox controls
OpenFileDialog
SaveFileDialog
ColorDialog
PrintDialog
FontDialog
P a g e | 25
the same object type for their second parameter. For these types of events, you can use the same
event handler to handle both events.
You can also use the same event handler to handle the same event for different controls. For
example, if you have a group of RadioButton controls on a form, you could create a single event
handler for the Click event and have each control's Click event bound to the single event handler.
Observe the phrase starting with the Handles keyword in the above example.
The above example can be modified to handle click events of three buttons as follows:
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click,
Button3.Click
TextBox1.Text = "Hello User?!"
End Sub
You can also write multiple handlers for the same event. For example, the following two handlers
are related to the same event ( the click event of the a check box named chkPaid). The effect is
that when the the check box is clicked both handlers will execute in response.
An other way of associating one or events with one or more handlers is by using deligates. The
details of deligates is left as an exercice.
End Sub
P a g e | 26
Object
or Class
box
Event or
Method
box
Figure 4.3: the code editer with the object box listing all available objects on the current form
Form Inheritance
Traditionally, you will have a number of forms for different aspects of tasks in the same
application. M ost ofthem m ay have a sim ilar layout though.H ence,you don’t need to either
recreate the same layout and code for each form or Copy and rename your forms to get other
forms. You can create the most common layout and code in one form and then derive the other
forms from it. The only thing you do is Create and save the base form you want first. Then use the
following command to add an Inherited form.
1. Project -> Add Windows Form
2. Select Inherited Form
3. Then Give the name of the Base form , and Click Ok
You will get a form containing all inherited from the base class. All inherited elements
including code and object propeties must be changed in the base form. You can only add
new controls and code on the inherited forms.
However, if you have a plan of modifiying the properties, methods, and events of the base form
and its controls change the Modifiers property of each element to Public in the base form.
Figure 4.4: A typical view of a form inherited from an other form ( inherited cotrols appear different showing that
thy are inherited)
P a g e | 27
The Windows Forms Class Hierarchy
The classes in the System.Windows.Forms namespace make up a fairly complex hierarchy, at the
root of which is the System.Windows.Forms.Control class (see Figure 4.5). The Control class
inherits from the system.ComponentModel.Component class, which represents an object that
can be placed on a container. This means that forms and controls we have seen so far inherit
their common properties, methods, and events from the control class. You can explore the
Control class to get the details.
Form example the following text shows the message dialog in figure 5.
Private Sub btnConvert_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnConvert.Click
If txtDollars.Text = "" Then
MessageBox.Show("You must a Dollar value first", _
"Dollar Entry Error", MessageBoxButtons.OK, _
MessageBoxIcon.Exclamation)
Else
Dim brVal As Single
brVal = Convert.ToSingle(txtDollars.Text) * 8.75
txtBirr.Text = brVal.ToString
End If
End Sub
P a g e | 28
Figure 5. Message box demo
Other Messagebox
End Sub
P a g e | 29
Figure 6. Messge displayed by the above code ( Form_Closing event Handler)
All other return value constants are prefixed by vb ( vbYes, vbAbort, vbCancel, vbRetry, vbIgnore,… )
MessageBox.Show(Days(dt.DayOfWeek()))
' DayOfWeek returns values 0 to 6 ( 0 for Sunday, 6 for Saturday)
End Sub
P a g e | 30
WorkSheet II
Create Windows forms Applications for the following Applications
1. Problem statement: A payroll company calculates the gross earnings per week of employees from
the number of hours they worked and their hourly wages. Create an application that takes this
inform ation and calculates the gross earnings by m ultiplying the em ployee’s hourly w ages by the
number of hours worked. The application assumes a standard work week of 40 hours. Any hours
worked over 40 hours in a week are considered and the earning will be one and one-half times
the hourly wage. Use a procedure to determine whether the employee has earned overtime pay.
Salary for time and a half is calculated by multiplying the em ployee’s hourly w age by 1.5 and
multiplying the result of that calculation by the number of overtime hours worked. This value is
then added to the user’s earnings for the regular 40 hours of w ork to calculate the totalearnings
for that week. Use another procedure to display the user’s pay.You can use the following figure as
a sample layout, but it is better to use your own.
Current
Donation
Current
Donation after Total donations
expenses Donation after
expenses
P a g e | 31
3. A certain Instructor wants to calculate the grades of each student in his class. Assume that he has
60 students scoring values out of 100 for the subject. Create a an application for the Instructor
that uses a multicolumn list box to display the Name, Mark and Grade of each student side by
side. Use the following Grading rule to calculate the grades after inputting the name and mark of
each student.
Mark Grade
90-100 A
75-90 B
55-75 C
40-55 D
0-40 F
The layout of the form of this application is left as an exercise.
MDI Windows
Most applications use multiple documents windows for work. Such applications have one Parent Window
(form) and many child widows or forms. Any of your forms can be parents. The parent form ’s
isMdicontainer property must be set to True. You set it at in the forms designer (at design time).
When the child forms are opened or shown you must set the mdIParent property of a form with the name
of its parent form.
frmOrders.MdiParrent = frmMain ‘this can be added in the form s load event procedure.
P a g e | 32
Chapter 5: Database Programming with ADO.NET
Data access and ADO.NET
Most applications are database related. A databse is usually maitained and managed by a specific
DBMS. This makes the application development and the Database development two related but
different aspects of contemporary applications. While the application (usually termed as the
Front End) is implemented using a programming environment such as VB.NET, the corresponding
database (usually termed as the Back End) is designed and implemented using some DBMS ( such
as Microsoft Access, SQL server or Oracle). Since these two are deferent environments that are
incompatible to each other, some intermidiary component called data access component will be
useed by the appliction in order to get access to the database stored in a specific DBMS. Such an
intermediary tool is called a Data Access Tool. One example is ADO.NET.
ADO.NET (pronounced as ActiveX Data Objects.NET) is a set of objects (classes) that allow such
communication a data source and a .NET application.
Provide User
interface and Data Applications
to Users
Send Updates,
Connect to Database
Inserts and Delete
Send application
operations by users
requests fro Apps
to ADO Data Access Tools(ADO.NET) Return results from
DBMS
DBMS
Data Source
Store Data
Database
Maintain Security,
Integrity, Recovery
…
Figure 5.1. A typical data access methodology
P a g e | 33
Figure 5.2. ADO Data Access techniques and Objects
ADO provides data access in both connected (online) or disconnected (offline) architectures. But the most
functional is the latter one. The DataReader is the core component in the connected architecture while
the DataSet is the core component of the disconnected architecture of ADO.NET. The Connection object
provides connectivity to a data source in both the architectures.
The other core element of the ADO.NET architecture is the .NET data provider, whose components are
explicitly designed for Data Manipulation and fast, forward-only, read-only access to data.
The .NET Framework includes two .NET data providers:
The SQL Server .NET Data Provider: which works for only for SQL Server,
The OLE DB .NET Data Provider: w hich w orks for all other D BM S’s such as M icrosoft
Access.
The Command object enables access to database commands to return data, modify data, run stored
procedures, and send or retrieve parameter information. The DataReader provides a high-performance
stream of data from the data source. Finally, the DataAdapter provides the bridge between the DataSet
object and the data source.
P a g e | 34
The Data Adapter
Interaction with 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 OledbDataAdapter 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. Here, you have to note
that changes by users are saved in memory only in the dataset until they are sent back to the database
whenever the application requires. The DataAdapter uses the Connection object of the particular .NET
data provider to connect to a data source, and Command objects to retrieve data from and resolve
changes to the data source. The DataAdapter uses Command objects to execute SQL commands at the
data source to both load the DataSet with data, and reconcile changes made to the data in the DataSet
back to the data source.
The DataSet Object in Depth
The central component of any software solution using ADO.NET is the DataSet. A DataSet is an in-memory
copy of database data. A DataSet can contain data from any number of database tables or views. The
DataSet constitutes a disconnected view of the database data because it exists in memory without an
active connection to a database containing the corresponding tables or views. This disconnected
architecture enables greater scalability by only using database server resources when reading or writing
from the database.
The biggest advantage of using a DataSet is that it provides a view of the database with multiple tables
and their relations, all without having an active connection to the database. You can think of a DataSet as
a miniature relational database in memory. A DataSet is usually created and populated programmatically.
It contains any number of tables, each of which corresponds to a database table or view.
DataSet
Tables
DataTable
Rows
DataRow
Columns
DataColumn
Figure 5.4. A partial view of the DataSet Object Model
An ADO.NET DataSet contains a collection of zero or more tables represented by DataTable objects. The
DataTableCollection contains all the DataTable objects in a DataSet. A DataTable is defined in the
System.Data namespace and represents a single table of memory-resident data. It contains a collection of
columns represented by a DataColumnCollection, and constraints represented by a ConstraintCollection
(not shown), which together define the schema of the table. A DataTable also contains a collection of rows
represented by the DataRowCollection, which contains the data in the table. Along with its current state, a
DataRow retains both its current and original versions to identify changes to the values stored in the row.
P a g e | 35
ADO Usage Mechanisms and Connection Lifetime
The following diagram concisely shows the usage styles of ADO objects both the connected and the
disconnected architectures.
Application
DataSet
Slow, Updatable,
Scrollable
DataReader
Fast, ReadOnly,
ForwardOnly DataAdapter
SelectCommand()
InsertCommand()
UpdatteCommand()
DeleteCommand()
Command
ExecuteReader()
ExecuteScalar()
ExecuteNonQuerry()
Connection
Data Source
OLEDB
SQL Server
P a g e | 36
Working with ADO (Connected Architecture)
Now that you have got the architectural components of ADO.NET. In this section, we will see how we can
actually work with ADO connected style. This style requires the connection to be open throughout the
over all activity. How ever,this style doesn’t allow alloperations.It only allow s Reading in one direction
(forward only). Updates, Deletes and Inserts are not allowed. Its advantage is that it provides the fastest
navigation in cases where only reading is required. If you want to allow users to make changes, then you
will have to use the second style ( i.e., the Connected Style). You will use a Connection, Command and a
DataReader object for this case. Here are the basic steps used to create a connected style database access:
1. Create a connection to the Database
Create an instance of the appropriate Connection (SqlConnection, oledbConnection)
Set the ConnectionString Property of the connection instance
Open the connection ( use Open method)
2. Create a Command Object to fetch data from the database
Create an instance of the corresponding command (sqlCommand, oledbCommand)
Set the Connection property of the Command Object to the Open connection
Set the CommandType property to either of three settings ( Text, StoredProcedure)
Set The CommandText to the appropriate Command string depending on the type
Type Setting
CommandType.Text An appropriate Select statement
CommandType.StoredProcedure A call to a stored procedure with appropriate input parameters
CommandType.TableDirect A correct Table or View name in the database
3. Create the DataReader Object
Create a DataReader referece
Use one of the Executexxx() methods of the DataReader object to create the Datareader.
Method What it Returns
comObj.ExecuteReader() A Reader that containing a group of records (ResultSet)
comObj.ExecuteSecalar() A Reader that returns a single value(in case the SQL text returns only one
value – aggregate values for example – Sum ,Count,… )
Example:
The following example code connects to a sample Microsoft Access Database named NWIND.MDB hypothetically
stored in the root folder of drive D. You must modify it if to the correct path in your case.
Class DataRead
Public conn As New OleDbConnection()
Public Ds As New DataSet
Public com As New OleDbCommand
Public Dr As OleDbDataReader
P a g e | 37
conn.Open()
' Create The Command Object
com.CommandType = CommandType.Text
com.Connection = conn
com.CommandText = _
"Select EmployeeID,FirstName,LastName From Employees"
'then create the datareader
Dr = com.ExecuteReader() ' this is the only method that creates a
datareader containing many records
End Sub
End Class
Other Classes can be created as users of the above class so that they can use the Dr Public field of the
object to navigate through the records. Below is one such class.
The following example shows a form that displays data retrieved by an object of the above class on a form
Eg. 5.1.
Imports System.Data.OleDb
myDr = dbObj.Dr
If myDr.Read() Then
txtID.Text = myDr.GetInt32(0).ToString
txtFName.Text = myDr.GetString(1) Only next is used (Why??)
txtLName.Text = myDr.GetString(2)
End If
End Sub
P a g e | 38
Working with ADO (Disconnected)
Now that you have got the architectural components of ADO.NET. In this section, we will see how we can
actually work with ado. Here are the base steps:
1. Create a connection to the Database
Create an instance of the appropriate Connection (SqlConnection, oledbConnection)
Set the ConnectionString Property of the connection instance
Open the connection ( use Open method)
2. Create a DataAdapter to fetch data from the database
Create an instance of the corresponding data adapter (oledbDataAdapter, oledbDataAdapter)
You must use an open connection instance to create the data adapter
3. Create the Dataset
Create a data set instance
You must use the Fill method of the DataAdapter object to populate the DataSet object
At this point you can close the connection using its Close() method.
4. Use the Dataset to navigate through the data
Use Instances of DataTable class to access a data table in the dataset
Use instances of DataColumn class to access columns of a data table
Use instances of the DataRow class to navigate through each row of a data table
You get access to each table, column or row using their respective collections
The following example code connects to a sample Microsoft Access Database named NWIND.MDB hypothetically
stored in the root folder of drive D. You must modify it if to the correct path in your case. The code connects to the
table named Employees and then displays the records on the screen. Implement it using a console application to test
the code.
Eg. 5.2.
'Imports System.Data.SqlClient
Imports System.Data.OleDb
Class ADOClass
Dim conn As New OleDbConnection()
Dim Ds As New DataSet
Dim Da As OleDbDataAdapter
Dim col As DataColumn
P a g e | 39
Console.Write(col.ColumnName & " ")
Next
Console.WriteLine()
End Sub
End Class
Class Tester
Shared Sub Main()
Console.ReadLine()
End Sub
End Class
P a g e | 40
Windows Forms allow you to bind easily to almost any structure that contains data. This means
that you can use ADO.NET to bind to traditional data stores, such as data stored in a Microsoft
Access or Microsoft SQL Server table or other DBMSs.
After you have bound a form to data, you can then bind controls on the form to specific elements
of the data. The most traditional data binding involves binding the Text property of a text box
control to a column of a datasource. You can also bind the graphic of an Image control, the
background of a control, or any other property of any control on a form.
Simple data binding allows you to bind a control to a single data element. The most common use
of simple data binding involves binding a single data element, such as the value of a column in a
table, to a control on a form. You use this type of data binding for controls that show only one
value. Uses of simple data binding include binding data to text boxes and labels.
Complex data binding allows you to bind more than one data element to a control. Using the
column example, complex data binding involves binding more than one column or row from the
underlying record source. Controls that support complex data binding include data grid controls,
combo boxes, and list boxes.
P a g e | 41
Figure 5.6. The result of creating a simple data-bound Windows Form
The following are the detailed steps required to build the above sample form (fig 5.6).
1. Click File, click New, and then click Project. The New Project dialog box appears.
2. Select the Project Type from the tree-view in the left-hand side of the dialog. For this
example, select Visual Basic Projects.
3. Select Windows Application from the list of templates on the right side of the dialog.
4. Supply a name and location for the project you wish to create. Click OK to create the
project.
5. Right click on the form and select Properties to display the properties for the form.
Change the Name property of the form to frmCustomers.
6. Change the Text property to Customer Information.
Once you create the project and form, you are ready to create and configure the dataset underlying
the form. A dataset is an in-memory cache consisting of tables, relations, and constraints. Each
table in the dataset has a collection of columns and rows. Because datasets are aware of both their
original and current state, they can track the changes that occur. The data in a dataset is considered
updateable.
First, create a Data Adapter that contains the SQL statement that you will use to populate the
dataset. To create the data connection and data adapter:
1. In the Toolbox, on the Data tab, select a oledbDataAdapter. Drag-and-drop it to the form.
The Data Adapter Configuration Wizard appears. Click Next.
P a g e | 42
2. Click New Connection to create a data connection that the data adapter will use.
3. C lick change and S elect “Microsoft Access Database File” then click Ok
4. In the Add New Connection dialog box, click Browse and locate your access database,
then click Open.
5. Click Test Connection to confirm that connection to the database is successful.
Source
Database
Figure 5.7 . The Add Connection dialog box allows you to specify connection information for the
data underlying the bound form
P a g e | 43
Figure 5.8 . Designate the type of query on which the bound form will be based
8. Type a SQL statement or click Query Builder to have the wizard build the SQL statement
for you. For this example, type the following SQL statement:
9. Click Next and then click Finish to complete the process. Notice that an oledbConnection
object named oledbConnection1 and a oledbDataAdapter object named
oledbDataAdapter1 appear in the Tray of the form.
The oledbConnection1 object contains information about how to access the selected
database. The oledbDataAdapter1 object contains a query defining the tables and columns
in the database that you want to access.
Note: We are using the more generic oledbDataAdapter on the Toolbox because
we are using Microsoft Access. If you want to use SQL Server as a data source,
you must select and configure the more specific oledbDataAdapter.
P a g e | 44
The tray of
Activating a a form
smart task
1. Click the Generate Dataset option from the smart task list. The Generate Dataset dialog
box appears as in Figure 4.
Figure 5.10 The Generate Dataset dialog box allows you to specify the name and other attributes
of the dataset that you are generating
2. Enter dsCustomers for the name of the New dataset you are creating. Make sure that you
select the Add This Dataset to the Designer option. Click OK. This generates the dataset.
P a g e | 45
After this step completes, you will see a new control, dsCustomers1, in the Tray for this form. This
new control is a reference to the dsCustomers.xsd file that was also added to your Solution
Explorer window. dsCustomers.xsd is an XML schema definition of the SQL statement that you
typed in earlier. There is a class is shown in the solution Explorer window. Then you can click on
the plus sign that appears behind the dsCustomers.xsd file to see the dsCustomers.vb file, as shown
in Figure 5.11. You can open the XSD file to see what it contains.
Figure 5.11. An XML schema definition (XSD) file has a class module containing the code that loads the
dataset into memory
You are now ready to create a form to display the data contained in the dataset. In this example,
you will add a single data grid control to the form. The data grid control will display the data
contained in the dataset. Here's what's involved:
1. At the top of the window, click the tab to display the frmCustomers form.
2. On the Windows Forms tab of the Toolbox, drag a data grid control onto the form. Size
the control as appropriate.
3. Display the control properties.
4. For the DataSource property, select dsCustomers1.
5. For the DataMember property, select Customers. This is the data table name inside the
dataset whose data will be displayed on the grid.
The steps you just completed have now bound the dataset to the data grid control. There is just one
more step to complete to see the data appear in the data grid control.
Although the data grid control is bound to the dataset, the dataset is not automatically populated
when the form is loaded. Use the form's Load event procedure to populate the data grid control
with data as the form is loaded.
P a g e | 46
oledbDataAdapter1.Fill(DsCustomers1, "Customers")
End Sub
In the Load event procedure, you first clear the dataset and then fill the dataset using the Fill
method of the oledbDataAdapter1 object you created earlier. You need to pass in the name of the
table to the second parameter, as this is used by the data grid control to retrieve the correct
DataMember (Customers) that you specified earlier in the DataMember property.
At this point, you are ready to see the data from the Customers table displayed in the data grid
control. There is one more step to complete before you can run this form. Because you changed the
name of the form, you need to inform the project what the Startup form for this project will be.
A database server is optimized to process large volumes of data, but you should only return small
result sets. The example shown in the previous section would be much more efficient if the user
were to first limit the data by selecting a particular country from a combo box, and then display
only those customers for the selected country. This section shows you how to create the data-
bound combo box. The next section shows you how to use the combo box to limit the data
displayed in the data grid control. The example involves the following basic steps:
Before you add a combo box to the form, first add a second data adapter to the form. You will use
this data adapter to generate a dataset containing a unique list of countries from the Customers
table. To add the second data adapter:
P a g e | 47
1. In the Toolbox, from the Data tab, select a oledbDataAdapter. Drag-and-drop it to the
form. The Data Adapter Configuration Wizard appears. Click Next.
2. Select the connection to the Northwind database that you created in the previous example.
Click Next.
3. Select Use SQL Statements and click Next.
4. Enter the following SQL statement:
There will now be an object named oledbDataAdapter2 added to the Tray of your form.
Figure 5.12. Do not choose Generate Insert, Update and Delete Statement when creating a dataset used
to bind to a combo box
The next step is to generate a dataset class and XSD file for this new oledbDataAdapter containing
the unique list of countries. Here are the steps involved:
1. Right click on the second adapter, and then click Generate Dataset. The Generate
Dataset dialog box appears.
2. Make sure Customers (oledbDataAdapter2) is selected in the list box of tables.
3. Click New, and enter the name dsCountries. Make sure that you select the Add This
Dataset to the Designer option. Click OK. This generates the dataset.
P a g e | 48
You have added a new object to the Tray named dsCountries1, and a new XSD file to the Solution
Explorer named dsCountries.xsd. These two items together create the dataset class and are used to
do the data binding on the combo box you are about to create.
You are now ready to add the combo box to the form. You need to increase the height of the form,
and move the data grid control down to make some room for this new combo box. After doing this,
in the Toolbox, you can drag-and-drop a combo box from the Windows Forms tab onto the form.
Place it above the data grid control, as shown in Figure 5.13.
Figure 5.13. Form containing data grid control and combo box
The combo box that you added is not bound to any data. To bind the combo box to the dsCountries
dataset:
P a g e | 49
Populating the Combo Box With Data
As with the data grid control, you must write some code to populate the combo box with data. The
code is added to the Load event procedure just under the code you used to load the data grid
control.
End Sub
The code shown in bold above is the code you will add to load the combo box. It is very similar to
the code you used to load the data grid control. You are now loading the second DataAdapter
control that you created.
Run the Application
Run this code to see if the countries are being loaded.
1. Press F5 to run this form.
2. Click the Countries drop-down combo box to see if there are countries loaded into the list.
If you have done everything correctly, they should be there and your screen may look
something like Figure 5.14.
Figure 5.14. Using a drill-down combo box to display a lesser amount of data in a data grid can
improve performance
P a g e | 50
1. Remove the code that populates the data grid control as the form is loaded.
2. Modify the oledbDataAdapter1 o bject’s SelectCommand property so that it accepts a
parameter for the country whose data you wish to display.
3. Add code that executes when the user selects an item in the combo box.
Remove the Code That Populates the Control as the Form Is Loaded
Now that the data grid control is populated based on the country selected in the combo box, you no
longer want it to load when the form is loaded. Remove the following code from the Load event
procedure of the form:
DsCustomers1.Clear()
OledbDataAdapter1.Fill(DsCustomers1, "Customers")
P a g e | 51
Figure 5.15. The Query Builder dialog helps you build SQL statements for your data adapters
Add Code That Executes When the User Selects an Item in the Combo Box
The final piece of required code repopulates the data grid control when a country is selected in the
cboCountry combo box. The basic steps to accomplish this are:
1. Respond to the SelectedIndexChanged event.
2. Set the parameter in the dataset with the data retrieved from the selected item in the combo
box.
3. Fill the dataset using this parameter.
Follow these steps to add the code and make this work.
1. Open the form in design mode.
2. Double-click the cboCountry combo box to display the SelectedIndexChanged event
procedure. This is the event that fires when you choose a new item from the combo box.
3. Write the following code within this procedure.
OledbDataAdapter1.SelectCommand.Parameters.Item("@CountryParam").Value _
= cboCountry.SelectedValue
P a g e | 52
End Sub
Y o u need to use the data adapter’s SelectCommand object to retrieve the specified Parameter
object. You can then set the Value property of this parameter to the SelectedValue property of the
combo box. The SelectedValue property is filled in with the Country name selected in the combo
box because you set the ValueMember property of the combo box to use the Country field from
the dataset. Once you fill in this value, you can fill in the customer dataset and it will automatically
repopulate the data grid control with just the customers for that selected country. An olternative for
the SelcetedValue property of a Combo Box is its Text Property.
At this point, you can run the application again to see how this works.
Follow the steps outlined in the sections above, titled Building the Sample Form, Creating and
Configuring the Dataset, and Generating the Dataset Class. These sections create a dataset based
on the Customers table. When adding the oledbDataAdapter to the form, select the existing
connection to the NorthWind database and build a SQL statement that includes the CustomerID,
CompanyName, ContactName, and ContactTitle fields from the Customers table. You are now
ready to add controls to the form and bind them to the dataset.
P a g e | 53
Figure 5.16. A simple data entry form
Add controls to the form and set their properties as designated in Table 1.
P a g e | 54
You must now bind each text box to a column in the dataset. To do this:
Although each field is bound, as with the data grid co ntro l exam p le, do n’t need to w rite the
code to populate such type of binding is made automatically by visual basic.
The final step is to add code that allows the user to navigate from row to row. The code behind the
previous button appears as follows:
The code uses the BindingContext method of the form to decrement the record pointer in the
dataset. The BindingContext tracks the current item for each datasource being used on the form.
The code behind the next button looks like this:
The code behind the next button uses the BindingContext method of the form to increment the
record pointer in the dataset. The resulting form should look like that shown in Figure 5.16.
Note As with the data grid control example, in a production environment you should limit the
data displayed on the form. You could, for example, add a combo box to the top of the form and
allow the user to select only customers in a specific country. The navigation buttons would then
take the user from row to row for the customers in that country.
Exercise: Try to study and use the BindingNavigator Control. It provides another way of
navigating through a datasource of a data bound form.
P a g e | 55
The BindingNavigator
Control
P a g e | 56
Change any of these
An values, and
AutoNumber Click …
field Update Using Command
See Next
Exam ple’s
code for this
button
comm.ExecuteNonQuery()
End Sub
…
P a g e | 57
Note that comm has been at the class level in the F o rm ’s C lass m o du le.
B) Using the dataset Object
The most common and interactive way of database updates is performed using the DataAdapter
object. As described earlier, applications (users) make inserts, updates, and deletes on a on each
DataRow of Dataset object. But these changes must be sent to the database using the
D ataA dapter’s U pdate m etho d. A ll changes o n the dataset w ill be pro pagated to the database using
this method. Any changes made to any of the tables in the dataset will be saved in the database.
Example:
Private Sub btnUpdateDS_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdateDS.Click
End Sub
This code is part of the same form module shown above.
Managing Transactions
Transactions are a feature offered by most databases for ensuring data integrity when data is
modified. A successful transaction must pass the "ACID" test, that is, it must be:
Atomic – All statements in the transaction either completed successfully or they were all rolled
back. The task that the set of operations represents is either accomplished or not, but in any case
not left half-done, to the detriment of your data.
Consistent – All data touched by the transaction is left in a logically consistent state. For example,
if inventory numbers were decremented in one table, there has to be a related order that
consumed that inventory. The inventory can't just disappear.
Isolated – The transaction must affect data without interfering with other concurrent
transactions, or being interfered with by them. This prevents transactions from making changes to
data based on uncommitted information, for example changes to a record that are subsequently
rolled back. Most databases use locking to maintain transaction isolation.
P a g e | 58
Durable – The data changes enacted by the transaction are permanent, and will persist through a
system failure.
The classic example is submitting an order to an order entry system— you have to check the
customer's credit level, create an order record, create order line item records, decrement the order
items from inventory, create a ship request, and more. If one or more of those steps fail but the rest
succeed, you can end up with inconsistent data in the form of orphaned records, unreliable
inventory numbers, and so forth. Using transactions appropriately prevents this kind of thing from
happening.
The ADO.NET data providers offer transaction functionality through the Connection, Command,
and Transaction classes. A typical transaction would follow a process similar to this:
OLE DB Transactions
All provider specific connections have their own transaction handling variations. In this section,
we will see the case of an OLE DB connection. The OLE DB data provider provides transaction
functionality through the following classes and members:
P a g e | 59
The OLE DB data provider has a Begin() method on the OleDbTransaction object. This allows to
perform multiple transactions on a single connection, but you must remember to explicitly commit
or rollback each one.
Example:
The following code snippet shows a sample transaction based on an OLEDB provider. The
complete version of the code is left as an exercise.
Private Sub btnUpdateCommand_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles btnUpdateCommand.Click
Dim tr As OleDbTransaction
Try
' Start a transaction.
tr = OleDbConnection1.BeginTransaction()
comm.CommandType = CommandType.Text
comm.CommandText = sql
comm.ExecuteNonQuery()
'...
End Sub
P a g e | 60
Concurrency control and Conflict Resolution (Data Validation)
Concurrency control
In VB.NET, the basic mechanism by which you control update conflicts is by using Isolation
Levels on transactions.Isolation levels are used by transactions to determine how restrictive the
transaction is in regards to its isolation behavior. The more restrictive the isolation level, the more
stringently the data affected by the transaction is isolated from other transactions. Most databases
enforce isolation by means of locking; you should double-check what method your targeted DBMS
uses. The tradeoff is between performance and concurrency— the more locks the system has to
maintain, the more likely it is that there will be conflicts and slowdowns as different processes try
to access the same resources.
The following is a list of the isolation levels supported in ADO.NET, which are commonly used.
The isolation levels are listed from least restrictive to most restrictive. They are defined in the
IsolatioLevel Enumerated type.
Property Name Description
Unspecified A different isolation level than the one specified is being used, but the
level cannot be determined.
ReadUncommitted A dirty read is possible, meaning that no shared locks are issued and no
exclusive locks are honored.
ReadCommitted Shared locks are held while the data is being read to avoid dirty reads,
but the data can be changed before the end of the transaction, resulting
in non-repeatable reads or phantom data.
RepeatableRead Locks are placed on all data that is used in a query, preventing other
users from updating the data. Prevents non-repeatable reads but
phantom rows are still possible. Phantom rows are new rows added by
other transactions satisfying the query applied by some transaction
previously.
Serializable A range lock is placed on the data set, preventing other users from
updating or inserting rows into the dataset until the transaction is
complete.
The SQL Server, Oracle, and OLE DB data providers all default to the ReadCommitted isolation
level. If you think ReadCommitted will not provide the isolation level you want for a given
transaction, you can use the Transaction.IsolationLevel property to specify a different level. You
should think very carefully about changing this setting, though, and perform adequate testing to
ensure that the change gives you the behavior that you want without negative side effects like data
inconsistency on one hand or concurrency issues on the other.
Dim tr As OleDbTransaction
P a g e | 61
Try
' Start a transaction.
tr = cn.BeginTransaction(IsolationLevel.Serializable)
' Insert here database processing code.
' If we get here, we can confirm all changes.
tr.Commit()
Catch ex As Exception
' Display an error message, and roll back all changes.
tr.Rollback()
MessageBox.Show(ex.Message)
End Try
This default behavior makes little sense because you might end up with some rows (all those preceding
the conflicting one) sent to the database correctly and others (those that follow the conflicting one) that
aren’t sent, even if they w ou ld n’t raise any conflict. In m ost cases, you w ant to try the update operation
on all the rows in the DataTable instead of stopping the operation at the first row that fails to update.
Y ou can d o this b y sim p ly setting the D ataA dapter’s C ontinu eU pdateO nE rror prop erty to T ru e. In this
case, you can test w hether one or m ore row s failed to update b y checking the D ataS et’s HasChanges
property:
da.ContinueUpdateOnError = True
da.Update(ds, "Authors")
If ds.HasChanges() Then
' One or more rows failed to update.
End If
You can get more granular control over what happens when an update is attempted by trapping the
RowUpdated event. This event lets you detect the conflict and decide to continue the update operation
with the remaining rows if possible.
P a g e | 62
StatementType (an enumerated type that specifies the type of command: insert, delete, or
update);
Command (the ADO.NET Command object sent to the database);
Row (the DataRow being updated); TableMapping (the DataTableMapping object used for the
update operation);
RecordsAffected (the number of records affected by the update operation);
Errors (the collection of errors generated by the .NET Data Provider during the update
operation); and
Status (an enumerated value that specified how to handle the current row; can be Continue,
ErrorsOccurred, SkipCurrentRow, or SkipAll- RemainingRows).
The key value to test from inside the handler of the RowUpdated event is the RecordsAffected property.
Any value less than 1 in this property means that the command failed and that there is an update conflict.
This is the usual sequence of operations you perform inside a RowUpdated event handler:
1. If the Status property is equal to Continue and the value of the RecordsAffected property is 1, the
update operation was successful. In most cases, you have little else to do, and you can exit the event
handler.
2. If the Status property is equal to ErrorsOccurred, you can check the Errors property to understand
what went wrong. Frequent causes of errors are violations of database constraints or referential integrity
rules, such as a duplicated valu e in a prim ary key or a uniqu e colu m n or a foreign key that doesn’t point
to any row in the parent table.
3. If you get a System.Data.DBConcurrencyException exception, it means that the WHERE clause in
the SQL command failed to locate the row in the data source. What you do next depends on your
application’s business logic. Typically, you test the StatementType property to determine whether it
was an insert, delete, or update operation; in the last two cases, the conflict is likely caused by another
user w ho deleted or m odified the record you’re trying to delete or update.
4. In all cases, you must decide whether the update operation should continue. You can set the Status
property to Continue or SkipCurrentRow to ignore the conflict for now, or SkipAllRemainingRows
to end the update operation without raising an error in the application. You can also leave the value set
to ErrorsOccurred, in which case the Update method is terminated right away and an exception is
thrown to the main application.
End Sub
Sub CheckConflicts()
' Send changes to the database, exit if no update conflicts.
OleDbDataAdapter1.Update(DsEmployees1, "Employees")
P a g e | 63
If Not DsEmployees1.HasChanges Then Exit Sub
' If we get here, there’s at least one conflicting row.
Dim dt As DataTable = DsEmployees1.Tables("Employees")
' Here’s a simple way to evaluate the number of conflicting rows.
Dim rowCount As Integer = dt.GetChanges().Rows.Count
MessageBox.Show(rowCount & " rows failed to update correctly")
' Mark all conflicting rows with the proper error message.
For Each dr As DataRow In dt.Rows
If dr.RowState = DataRowState.Added Then
dr.RowError = "Failed INSERT operation"
ElseIf dr.RowState = DataRowState.Modified Then
dr.RowError = "Failed UPDATE operation"
ElseIf dr.RowState = DataRowState.Deleted Then
dr.RowError = "Failed DELETE operation"
' Undelete this record, else it wouldn’t show in the table.
dr.RejectChanges() 'by default AcceptChanges is invoked
End If
Next
DataGrid1.DataSource = dt
End Sub
P a g e | 64