The Constructors
Now that we know what pieces of data our class should contain, it's time to set up that data when we instantiate the class. There are two scenarios: We'll populate the properties with default values, or we'll populate them with values from our database. To do this, we'll create two constructors by way of overloading.
In writing our constructors, we'll have to decide up front how we'll distinguish between default data and data we've entered or retrieved from the database. We could simply allow each property to return a null value, but that wouldn't correspond well to the fact that our database table doesn't allow null values. Instead, we'll make all of our string values equal empty strings, our SignUpDate value will equal January 1, 2000, and our CustomerID will be set to 0.
The CustomerID is perhaps the stickiest point in our class design. Although the chances are that we'll always know exactly what we're doing in our code (I know, you can stop laughing), we need to know and document how we're going to know if the instantiated Customer object actually corresponds to an existing database record or not. Again, we could just keep CustomerID null until we've created a record, but for our case, we'll decide right now that a value of 0 means that either no record exists or we've created a new object with default values. This leaves the potential for populating our object with default values from both constructors, so we'll create a private method just for this purpose in Listing 5.3.
Example 5.3. The private PopulateDefault() method
C#
private void PopulateDefault() { _CustomerID = 0; _LastName = ""; _FirstName = ""; _Address = ""; _City = ""; _State = ""; _Zip = ""; _Phone = ""; _SignUpDate = new DateTime(2000,1,1); }
VB.NET
Private Sub PopulateDefault() _CustomerID = 0 _LastName = "" _FirstName = "" _Address = "" _City = "" _State = "" _Zip = "" _Phone = "" _SignUpDate = New DateTime(2000, 1, 1) End Sub
Now that we have that issue out of the way, our default constructor is a piece of cake, as shown in Listing 5.4.
Example 5.4. The default constructor
C#
public Customer() { PopulateDefault(); }
VB.NET
Public Sub New() PopulateDefault() End Sub
Within our calling code, creating the object and assigning values to its properties is as easy as the first fragment of code we showed you in this chapter.
Our second overload for the constructor, shown in Listing 5.5, has the familiar database code you've been waiting for. It takes a single parameter, the CustomerID, and populates our object's properties based on a match in the database.
Example 5.5. The record-specific constructor
C#
private string _ConnectionString = "server=(local);database=test;Integrated Security=SSPI"; public Customer(int CustomerID) { SqlConnection connection = new SqlConnection(_ConnectionString); connection.Open(); SqlCommand command = new SqlCommand("SELECT CustomerID, " + "LastName, FirstName, Address, City, State, Zip, Phone, " + "SignUpDate WHERE CustomerID = @CustomerID", connection); command.Parameters.AddWithValue("@CustomerID", CustomerID); SqlDataReader reader = command.ExecuteReader(); if (reader.Read()) { _CustomerID = reader.GetInt32(0); _LastName = reader.GetString(1); _FirstName = reader.GetString(2); _Address = reader.GetString(3); _City = reader.GetString(4); _State = reader.GetString(5); _Zip = reader.GetString(6); _Phone = reader.GetString(7); _SignUpDate = reader.GetDateTime(8); } else PopulateDefault(); reader.Close(); connection.Close(); }
VB.NET
Private _ConnectionString As String = _ "server=(local);database=test;Integrated Security=SSPI" Public Sub New(CustomerID As Integer) Dim connection As New SqlConnection(_ConnectionString) connection.Open() Dim command As New SqlCommand("SELECT CustomerID, LastName, "_ & "FirstName, Address, City, State, Zip, Phone, SignUpDate "_ & "WHERE CustomerID = @CustomerID", connection) command.Parameters.AddWithValue("@CustomerID", CustomerID) Dim reader As SqlDataReader = command.ExecuteReader() If reader.Read() Then _CustomerID = reader.GetInt32(0) _LastName = reader.GetString(1) _FirstName = reader.GetString(2) _Address = reader.GetString(3) _City = reader.GetString(4) _State = reader.GetString(5) _Zip = reader.GetString(6) _Phone = reader.GetString(7) _SignUpDate = reader.GetDateTime(8) Else PopulateDefault() End If reader.Close() connection.Close() End Sub
The methods we're using to populate our properties from the SqlDataReader might seem strange to you now, but we'll explain why this is the best way to do it in terms of performance in a later chapter (and because you're crafting this nifty data class, you only have to do it once).
First we create our connection object using a connection string we've added to the class. (In real life, you would probably store your connection string in web.config, but we include it here for simplicity.) When open, we create a command object that has our SQL query, including the parameter in the WHERE clause that we'll use to choose the record. In the next line, we add a parameter to our command object, setting its value from the parameter of the constructor. We create a SqlDataReader, and if it can read, we populate our properties with the values from the database. If no record is found, we populate our object with the default values, using the standalone method we created earlier.
So far, we've got all of our properties and a means to create a Customer object with default values or values from an existing database record. Next we need ways to create, update, and delete that data.