Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Microsoft CSharp Programming For The Absolute Beginner (2002) [eng]-1.pdf
Скачиваний:
46
Добавлен:
16.08.2013
Размер:
15.71 Mб
Скачать

}// end agentID if

}// end something selected if

}// end getWhere

In most situations it is very easy to build the WHERE clause, because it’s simply a matter of extracting the list box text (which indicates the currently selected field) and the text from the text box (which indicates the value the user is trying to find). However, there are two special cases. If the selectedIndex property of the list box is zero (indicating no WHERE clause) the rest of the method is skipped, because the user doesn’t want to include a condition. If the user selected "AgentID" things are slightly more complicated because the text box returns a text value and AgentID requires an integer. The query is still a string, but you do not need single quotes around integer values. For example, "SELECT * from Agents WHERE AgentID = '0'" will not work, but "SELECT * from Agents WHERE AgentID = 0" will. There are two problems to solve. First, the text box value will not be surrounded by single quotes (this one is easy to fix). The second problem is what to do if the user chooses the AgentID field while a non−numeric value is in the text box. I used some exception handling sleight−of−hand to fix this. I try to convert the text from the text box into an integer and store it in a temporary variable. I’ll then convert that integer back into a string and add it to the query. If there was an exception (which happens if the original value of the text box cannot easily be converted into an integer), I simply add the value 0 to the query, which is guaranteed to be legal.

Running the Query

The buildQuery() method (and its offspring getSelect() and getWhere()) do a good job of generating a legal SQL query in theQuery. The runQuery() method simply updates the data set and data grid based on the new query.

private void runQuery(){ //runs the current query

DataSet qDS = new DataSet("results"); myAdapter.SelectCommand.CommandText = lblQuery.Text; myAdapter.Fill(qDS, "results"); dgSpies.SetDataBinding(qDS, "results");

} // end runQuery

The first task is to create a new data set called qDS with one table called results. I then set up the Select command to the text of lblQuery. I then use the Fill() method of the adapter to fill the data set from the adapter, and bind the data grid to the new data set.

Working with Relational Databases

The simple spy database does the job, but it is incomplete. Any self−respecting spymaster would keep the following information on each agent:

CodeName

Specialty (each spy could have several specialties)

Assignment

Assignment description

Location

It might be tempting to build a slightly bigger table to hold this information. Figure 11.27 illustrates such a table.

345

Figure 11.27: This version of the spy database has more information, but it also introduces a number of problems.

When you carefully analyze this version of the spy database, you’ll notice a couple of problems that crop up frequently in real databases. First, many of the spies have multiple talents (my personal favorite is explosives and flower arranging). It will be difficult to write a query that finds an agent with a flower arranging skill, because the only agent with that skill also has explosives listed in the same field. (You know, flower arranging can be a deadly art in the hands of a master practitioner…) There are other problems. The description and location fields tend to be closely related to the assignment field. That makes sense, because it is supposed to be a description of the assignment, and each assignment has only one location. However, there are some inconsistencies. Does Operation Dancing Elephant take place in a circus or a zoo? Because the description of the assignment was typed in two different places in the database, there is conflicting information about the operation. Likewise, Operation Enduring Angst might be in Lower Volta, or it might be in Lower Votla. Although these examples are deliberately outlandish, the problems they point out are real. Many databases have variations of these same weaknesses. The answer to better−behaved databases is a practice called data normalization.

Improving Your Data with Normalization

Data normalization can (and does) take up entire books, but it can be summarized by a list of simple rules:

Break your data into multiple tables

No field can have a list of entries

Do not duplicate data

Each table describes only one entity

Each table has a single primary key field

As an example of data normalization in action, I built one more version of the spy database. It retains the ability to return all the data needed, but it avoids some of the pitfalls of the single−table database.

First, take a look at the improved version of the Agents table, featured in Figure 11.28.

Figure 11.28: The Agents table is quite a bit simpler than it was before.

You might be surprised how little information remains in the Agents table. The Assignment, Specialty, Description, and Location fields have totally disappeared from the table. (Don’t worry, they’ll reappear shortly.) The only remaining fields are AgentID, CodeName, and AssignmentID. The Assignment ID field contains only numeric values. The number in the AssignmentID field is

346

used to look up a record in another table, illustrated in Figure 11.29.

Figure 11.29: The Assignments table describes all the information related to a specific operation.

I built the Assignments table by taking a careful look at the data in my original expanded database. In a properly normalized database, all of the information in a table describes one type of entity. On closer examination Figure 11.27 (the bad spy table) has fields that describe two different kinds of information. The AgentID, CodeName, and Specialty fields describe an Agent, but the Assignment, Description, and Location fields refer to the Operation the agent is assigned to. (Specialties are an entirely different problem, and I’ll describe them later on.) The Agents table still needs a way to determine which operation an agent is on, but it is redundant to describe each operation’s details for each agent on the assignment. For the purpose of this example, each operation has one name, one assignment, and one location. The information that pertains to the Assignment is placed in the separate Assignments table. The Assignments table also has a primary key, so each assignment has a unique key. The Agents table has an AssignmentID field, which contains only a reference to the key field of the Assignments table.

Hint A field that contains the primary key of another table is called a foreign key reference in most database applications.

Note that the AssignmentID field appears in both the Agents table and the Assignments table. It isn’t necessary to give these two fields the same name, but it makes the next step easier.

Using a Join to Connect Two Tables

SQL Server (even the simplified version included with Visual Studio) includes a visual tool to help connect two tables. Each Database in the SQL Server list in the server explorer has a Data Diagrams option. Right−click on the Data Diagrams element and choose New Data Diagram in the same way you created new tables. You see a screen that lets you add tables. Choose both the Agents and Assignments tables. You see a graphic representation of the tables that looks like Figure 11.30.

347

Figure 11.30: The data diagram tool shows the tables in your database.

It’s important to indicate there is a relationship between the AssignmentID fields in the two tables. This is easily done in the data diagram window by simply dragging the mouse from the box to the left of AssignmentID in Agents, and the similar box of AssignmentID in the Assignments table. The dialog shown in Figure 11.31 appears.

348

Figure 11.31: You can leave the default values of the Create Relationship dialog.

The Create Relationship Dialog helps you to define the relationship between the two tables. Relationships always involve the primary key of one table and a foreign key in another table. The Create Relationship dialog usually guesses correctly which table has the indicated key as its primary key.

Trap The two fields must have the same type, or the relationship will not be established.

After the relationship has been created, the data diagram looks something like Figure 11.32.

349

Соседние файлы в предмете Программирование на C++