Class Frameworks in VB .NET - Creating Business Objects (Page 3 of 5 )
On the second page of the application, users are presented with editable Name, Price and Number of Units fields for the particular product and read-only Supplier information field. User can then modify and save the data to database.
An obvious approach now would be to use MyDatabase class and execute “select” and “update” statements as required. Yet again – not a great idea from code reusability perspective. Imagine many similar pages across the site, executing validations and database queries that are very much alike. It would be hard to code and maintain. Also, if you were to modify properties of products on the Web and through a client-server interface would require multiple instances of the same code in both applications.
In fact, this trail of thought goes right along with Object-oriented programming paradigm, where “real-life” business objects are mapped into classes with methods and properties. Since our “edit” page displays both product and supplier information, both Product and Supplier business entities are prime candidates for being converted into a class.
Any Product has a Supplier. Because of application requirements, objects of Product class can be modified, while Supplier objects are read-only. Both objects will need to interact with each other and access the database. Therefore, we will put them in same namespace as MyDatabase class.
Let’s define the Supplier class first. Supplier has an ID, Name and Country properties, all read-only, and a one-argument constructor which accepts Supplier ID and initializes member variables based on database query:
Public ReadOnly Property ID() As Int32 Get Return intID End Get End Property
Sub New (p_intID As Int32) '-- Call DB and initialize object variables Dim dtrSupplier As SqlDataReader dtrSupplier = MyDatabase.GetReader("SELECT * FROM Suppliers WHERE SupplierID = " & p_intID)
If dtrSupplier.Read() Then intID = p_intID strName = dtrSupplier("CompanyName") strCountry = dtrSupplier("Country") End If
dtrSupplier.Close() End Sub
The Name and Country properties are very similar to ID property. Once a Supplier object is created, the constructor reads database table and sets up the properties of the new Supplier object based on supplier ID.
Now let’s build the Product class. It also has a read-only ID property, and a one-argument constructor that contains logic very similar to the one in Supplier class. The Name, Price, and NumUnits are all read/write properties, such as:
Public Property NumUnits() As Int32 Get Return intNumUnits End Get
Set (ByVal p_intValue As Int32) intNumUnits = p_intValue blnHasChanged = True End Set End Property
Set methods are very important – this is where you often would implement data validation logic. For example, if someone is calling the Set NumUnits with a value of –10, the code should not update NumUnits property of the product object.
Also, notice blnHasChanged variable. It is set to False in Product class constructor, and is later reset to True when any of the properties is modified. You will see why this is important in a moment.
Product class will also “contain” a supplier, and we’ll expose a Supplier object as a read-only property of Product class:
Public ReadOnly Property Supplier() As Supplier Get Return objSupplier End Get End Property
And here is what one-argument constructor of the Product class looks like:
Sub New (p_intID As Int32) '-- Call DB and initialize object variables Dim dtrProduct As SqlDataReader dtrProduct = MyDatabase.GetReader("SELECT * FROM Products WHERE ProductID = " & p_intID)
If dtrProduct.Read() Then intID = p_intID strName = dtrProduct("ProductName") intNumUnits = CType(dtrProduct("UnitsInStock"), Int32) decPrice = CType(dtrProduct("UnitPrice"), Decimal) objSupplier = New Supplier(dtrProduct("SupplierID")) End If
blnHasChanged = False dtrProduct.Close() End Sub
The most interesting statement in the code above is the following:
objSupplier = New Supplier(dtrProduct("SupplierID"))
Putting object structure to work, not only Product class exposes a read-only Supplier property, but it creates a new Supplier object, which in turn automatically sets its own properties by executing the one-argument constructor of Supplier class.
Since all other product information can be updated, the class also requires a Save() method. This method will accept no parameters, and it’s only function will be to save current properties of the product object back to the database table. We will now use blnHasChanged variable to ensure that we only make a call to database when at least one of the properties of the Product object has been updated:
Public Sub Save() Dim strUpdate As String
If blnHasChanged = True Then '-- Data has been updated, save it to database strUpdate = "UPDATE Products SET " strUpdate += "ProductName = '" & Me.Name & "', " strUpdate += "UnitsInStock = " & Me.NumUnits & ", " strUpdate += "UnitPrice = " & Me.Price & " " strUpdate += "WHERE ProductID = " & Me.ID
MyDatabase.ExecNonQuery(strUpdate) End If End Sub
The Product class really takes advantage of all our prior efforts – it uses both Supplier and MyDatabase classes to access database and encapsulate the data. We’ve now created a class framework we can use in ASP.NET pages, stand-alone client/server or even console .NET applications.
All the code for our namespace is now complete (see file AspnetObjects.vb, or use compiled version – AspnetObjects.dll).