Dissecting a Sample Component

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:

  • Databases require extraneous details.

    This information (connection strings, field names, and so on) can complicate application logic. A well-written component encapsulates these details.

  • Databases are always in demand.

    A typical application might call a database several times for different pieces of information. Placing this code in a database component ensures that the connection and querying details are handled in a consistent manner rather than copied to every corner of your code.

  • Relational databases aren't object-oriented.

    However, components are. By placing a component between the database and the application, you gain the best of both worlds. The application programmer can work with the database using an object interface (and not worry about whether the retrieved information is being joined from multiple tables). The database, on the other hand, gets the SQL (or stored procedure calls) it requires.

  • Databases often change.

    If new fields are added or stored procedure names are changed after the application is deployed, it's easier to change a single component rather than the entire application.

  • Database access code often changes.

    This is a natural progression as you develop the fine-tuned code that ensures optimum performance. After profiling your database or modifying the set of indexes, you might need to modify a query. Or, you might develop a database component during development that uses straightforward queries and then modify it to use better-performing stored procedures later on.

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:

  • It enables you to perform some basic data checking and refuse invalid information. Don't take this approach too far, however, because rules are often better placed in a different location (such as at the user interface level or in a service provider method).

  • It enables you to use data binding with arrays or collections of this class in Windows Forms and ASP.NET Web pages, which comes in handy.

  • It provides a better level of design-time support. Property procedure settings can be configured through the Properties window in Visual Studio .NET; public variables cannot.

Essentially, it all boils down to one thing: Adding property procedures ensures that your class follows the rules of proper encapsulation.

Classes vs. Structures

Instead of using classes for your information packages, you can use structures. Structures are similar to classes, with some limitations. (For example, they don't support inheritance, although they do support interfaces, property procedures, and methods.) The key difference between a structure and a class is in how they are allocated in memory. Structures are value types, which means they behave differently for assignment and comparison operations than classes, which are reference types.

To get a better grasp of the difference, consider the following code, which manipulates two structure variables:

[View full width]

StructureA = StructureB ' StructureA now has a copy of the contents of StructureB. ' There are two duplicate structures in memory. If StructureA.Equals(StructureB) Then     ' This is True as long as the structures have the same content. graphics/ccc.gif     ' This performs a full binary comparison that will be slow for graphics/ccc.gif     ' large structures.  End If

Compare this with the behavior for two class instances:

[View full width]

ObjectA = ObjectB ' ObjectA and ObjectB now both point to the same thing. ' There is one object in memory, and two ways to access it. If ObjectA Is ObjectB Then     ' This is True if both ObjectA and ObjectB point to the same thing. graphics/ccc.gif     ' This is False if they are separate, yet identical objects. End If

Generally, structures provide the best performance for small objects (ones that store fewer than 16 bytes), whereas classes are more efficient for larger objects. Classes are also more common in Microsoft Visual Basic code because pre-.NET versions didn't include structures (although user-defined types provided similar but reduced functionality). To define a structure, you use the Structure keyword instead of the Class keyword:

 Public Structure CustomerDetails     Private _ID As Integer     Private _Name As String     Private _Email As String     Private _Password As String     ' (Property procedure and constructor code omitted.) End Structure 

Note that if you require value-type semantics and the ability to copy or compare the contents of class instances, you don't necessarily need to create a structure. Instead, you can implement interfaces such as ICloneable and IComparable when you create your class to support these features.



Microsoft. NET Distributed Applications(c) Integrating XML Web Services and. NET Remoting
MicrosoftВ® .NET Distributed Applications: Integrating XML Web Services and .NET Remoting (Pro-Developer)
ISBN: 0735619336
EAN: 2147483647
Year: 2005
Pages: 174

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net