One of the most common services that components are called on to provide is data access. Databases make ideal work for components for several reasons, including the following:
When you create an assembly with data access code, you'll often create two classes for each table. One class is the data package that represents the information your code needs to retrieve. The other class is the service provider that performs tasks such as updates and information retrieval. Depending on your needs, this service provider might provide methods that allow a single matching record to be retrieved and returned as an object and methods that return an entire collection or array of data objects. Listing 2-1 shows a sample component that wraps a single Customers table. I've left out the actual data access details and shown just the skeletal structure for the information package and service provider. This example provides a good template for any data-based service provider. We'll revisit this class over the next few chapters. Listing 2-1 The structure of a sample database component'******************************************************* ' ' CustomerDetails Class ' ' A data component that encapsulates details about ' a particular customer. ' '******************************************************* Public Class CustomerDetails Private _ID As Integer Private _Name As String Private _Email As String Private _Password As String Public Sub New(customerID As Integer, password As String, _ name As String, email As String) ' Note that the constructor assigns to the properties, not the ' private variables. This ensures that any required validation ' is performed in the property procedures, and invalid values ' can't get in through a back door. _ID = customerID _Password = password _Name = name _Email = email End Sub Public Sub New(name As String, email As String, _ password As String) _Name = name _Email = email _Password = password End Sub Public Property ID() As Integer Get Return _ID End Get Set(ByVal Value As Integer) _ID = Value End Set End Property Public Property Name() As String Get Return _Name End Get Set(ByVal Value As String) _Name = Value End Set End Property Public Property Email() As String Get Return _Email End Get Set(ByVal Value As String) _Email = Value End Set End Property Public Property Password() As String Get Return _Password End Get Set(ByVal Value As String) _Password = Value End Set End Property End Class '******************************************************* ' ' CustomerDB Class ' ' A service provider component that encapsulates all data ' logic necessary to retrieve, update, or add a customer. ' '******************************************************* Public Class CustomerDB Private _ConnectionString As String = _ "Data Source=MyServer;Initial Catalog=MyDb;" & _ ""Integrated Security=SSPI" Public Function GetCustomer(ByVal customerID As Integer) _ As CustomerDetails ' (Code omitted.) End Function Public Sub AddCustomer(ByVal customer As CustomerDetails) ' (Code omitted.) End Function Public Sub UpdateCustomer(ByVal customer As CustomerDetails) ' (Code omitted.) End Sub End Class Notice that the service provider class CustomerDB is entirely stateless. It uses a single static member variable to store the database connection string, which is hidden from the application programmer. The CustomerDetails class, on the other hand, is entirely stateful. It provides two constructors that ensure it is preloaded with valid data when it is created. The first constructor, which accepts all three pieces of information, is designed for use with the GetCustomerDetails method and UpdateCustomer method. The other constructor is designed for the client to use with the AddCustomer method. At this point, the client won't know the unique ID value because this is assigned automatically by the database. You also might have noticed that the CustomerDetails class uses full property procedures even though a simpler class with public members would do just as well (as shown here): Public Class CustomerDetails Public ID As Integer Public Name As String Public Email As String Public Password As String End Class Using full property procedures offers a few advantages, however, including the following:
Essentially, it all boils down to one thing: Adding property procedures ensures that your class follows the rules of proper encapsulation.
|