Download Week 5 Lab Guide - Computing at Queen`s

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

IMDb wikipedia , lookup

Extensible Storage Engine wikipedia , lookup

Entity–attribute–value model wikipedia , lookup

Database wikipedia , lookup

Microsoft Jet Database Engine wikipedia , lookup

Concurrency control wikipedia , lookup

Microsoft SQL Server wikipedia , lookup

Open Database Connectivity wikipedia , lookup

SQL wikipedia , lookup

ContactPoint wikipedia , lookup

Clusterpoint wikipedia , lookup

Versant Object Database wikipedia , lookup

PL/SQL wikipedia , lookup

Relational model wikipedia , lookup

Database model wikipedia , lookup

Transcript
Databases: C# and SQL
QUEEN’S UNIVERSITY BELFAST
Practical Week 5
Table of Contents
PRACTICAL 5..................................................................................................................................................... 2
EXERCISE 1: Adding a new Form to the GUI ............................................................................................. 2
Task 1: Creating the Database .............................................................................................................. 2
Task 2: Creating the GUI .......................................................................................................................... 3
Task 3: Implementing the functionality of the GUI – the Report object and dbAccess ................ 4
Task 4: Implementing the functionality of the GUI – the generic database utilities ....................... 5
Task 5: Implementing the functionality of the GUI – the InnerJoinForm ........................................... 7
1 | QUEEN’S UNIVERSITY BELFAST
PRACTICAL 5
In this series of practical documents we have been looking at implementing databases within a
Project Management application. In particular being able to query the database for data
already held, update this data and delete what we no longer need. We have also considered
adding new data and realise that for most of these functions we need to be careful when using a
relational database as there are dependencies on the data when manipulating it. In this
practical we will take this a little further and go back to consider the “inner join” query that we
considered in practical 2.
The Project Management application was set up to manage each table as an object – which
makes sense. However this means that when querying the database we should only have
methods in these classes that are specifically relevant to the database table to maintain the
“contract” of object oriented programming. If we do require a join/inner join query then we are
breaking this contract. This practical considers how we manage this given the design of the code
and the database itself.
EXERCISE 1: Adding a new Form to the GUI
To understand how this solution will be developed it is useful to see the interface design. Therefore
this first exercise will take you through the development of the form we will use for an inner join.
Remember before you start that you will need to recreate the connection to the database.
Task 1: Creating the Database
Step 1: Open last week’s practical solution in Visual Studio and add the Database by opening the
Server Explorer, then right click on Data Connections and select Create New SQL Server
Database, see Figure 1.
Figure 1
Step 2: Copy and paste the SQL into a new query window to create the tables of the database
from the Computing At Queen’s website. Remember to Execute the SQL.
Step 3: Copy and paste the SQL to add the content to the tables from the Computing At Queen’s
website. Remember to Execute the SQL.
2 | QUEEN’S UNIVERSITY BELFAST
Task 2: Creating the GUI
We will need to add a button to our main application form and then create a new form for the
inner join.
Step 1: Expand the gui folder and open the MainApp.cs form is Designer view. Create a GUI
similar to Figure 2, remembering to name the new element of the interface e.g. joinBtn.
Figure 2
Step 2: Double click on the Inner Join button which should open the Code View and enter the
empty method for joinBtn_Click. Add the code in Figure 3 to this method.
InnerJoinForm innerJoinForm = new InnerJoinForm (db);
innerJoinForm.Show();
Figure 3
Step 3: We will now create the InnerJoinForm.cs. Right click on the gui folder and select Add ->
New Item… Then in the Add New Item dialog window choose Windows Form, name it
InnerJoinForm and click Add.
Step 4: Create a GUI similar to Figure 4, remembering to name the elements of the interface.
table1CBox
table2CBox
table1NameLbl
table2NameLbl
table1CheckList
table1ColCBox
table2ColCBox
fieldCBox
valueCBox
conditionCBox
table2CheckList
queryTextBox
resultsDataGrid
resultCountLbl
Figure 4
3 | QUEEN’S UNIVERSITY BELFAST
generateBtn
executeBtn
Note: Make sure you choose the correct type of form element:
table1CBox, table2CBox, table1ColCBox, table2ColCBox, fieldCBox and conditionCBox is
of type ComboBox
table1CheckList and table2CheckList are of type CheckedListBox
queryTextBox is of type TextBox
generateBtn and executeBtn are of type Button
resultsDataGrid is of type DataGridView
Step 5: Save your work and test at this stage to ensure that the MainApp window form opens. If
you click on the Inner Join button to check that the new form just created will open.
Task 3: Implementing the functionality of the GUI – the Report object and dbAccess
To implement the functionality of this form we are going to script new objects. The first will be a
Report object which will be set up to manage the column names of the results returned. Take a
look back at the last practical and you will note that we have a create table method for each
table of results created in the AddDelForm.cs. This is also true of the EditForm and SearchForm
classes. Therefore this script will be used to generate reports as part of the data grid view and will
be independent of the column names of each table i.e. it will create the object to manage the
column names.
Step 1: Right click on the objects folder select Add -> Class. In the Add New Item dialog panel
name the class Report. Click Add.
Step 2: Create the Report object as per the class diagram in Figure 5.
Figure 5
Step 3: As with the rest of the objects created as part of this application we will also need a
DBAccess object. Right click on the dbAccess folder select Add -> Class. In the Add New Item
dialog panel name the class ReportDBAccess. Click Add.
Step 4: Create the ReportDBAccess object as per the class diagram in Figure 6.
Figure 6
4 | QUEEN’S UNIVERSITY BELFAST
Step 5: Complete the reportGeneration method as follows:










Assign the CreateCommand method of the Conn property of the Database object
created in this class (i.e. db.Conn) to the Cmd property of the Database object created in
this class (i.e. db.Cmd).
Set the CommandText property of the db.Cmd to the String passed into the method i.e.
sqlString
Set the Rdr property of the Database object to db.Cmd.ExecuteReader().
Create a new Report object called obj and pass to it the selected list passed to the
method as a parameter and a new List of List<String>
Create a while loop that checks the db.Rdr Read() method (this method checks if there
are any more results left in the SqlDataReader Object).
Creates a new List of type String called results
Add each result to the results List using db.Rdr.GetValue(index).ToString.
Add the results as a row to the report object i.e obj.Rows.Add(results)
Once the while loop has finished close the Database member Rdr using the SqlDataReader
Close() method.
Return the Report object.
Task 4: Implementing the functionality of the GUI – the generic database utilities
We will require a further class in the dbAccess folder to manage the generic utilities of database
access, for example to obtain the column names of the table, to get the tables from the
database and also to carry out a select all query.
Step 1: Right click on the dbAccess folder, select Add -> class and name it DBUtilities. Click Add.
Step 2: Create the DBUtilities object as per the class diagram in Figure 7.
Figure 7
Step 3: Complete the methods of this class as follows:
List<String> getColsFromTable(String tableName)
 Assign the CreateCommand method of the Conn property of the Database object
created in this class (i.e. db.Conn) to the Cmd property of the Database object created in
this class (i.e. db.Cmd).
 Set the CommandText property of the db.Cmd to “SELECT TOP 0 * FROM “ + tableName
 Set the Rdr property of the Database object to db.Cmd.ExecuteReader().
 Create a new List of type String, called colNames.
 Call the db.Rdr Read() method (remember that we only need to do this once as there will
only be one return i.e. all column names).
 Loop through for every element returned as part of the reader and add the column name
to the colNames list i.e. db.Rdr.GetName(i).
5 | QUEEN’S UNIVERSITY BELFAST


Once the loop has finished close the Database member Rdr using the SqlDataReader
Close() method.
Return the List of column names.
List<String> getTablesFromDB()
 Create a String called table which holds the db.Conn.Database
 Assign the CreateCommand method of the Conn property of the Database object
created in this class (i.e. db.Conn) to the Cmd property of the Database object created in
this class (i.e. db.Cmd).
 Set the CommandText property of the db.Cmd to “SELECT TABLE_NAME FROM
INFORMATION_SCHEMA.TABLES”
 Set the Rdr property of the Database object to db.Cmd.ExecuteReader().
 Create a new List of type String, called tableNames.
 Create a while loop that checks the db.Rdr Read() method (this method checks if there
are any more results left in the SqlDataReader Object).
 Add the table names as a row to the list i.e tableNames.Rows.Add(db.Rdr.GetString(0))
 Once the while loop has finished close the Database member Rdr using the SqlDataReader
Close() method.
 Return the Report object.
selectAll(String tableName)
 Assign the CreateCommand method of the Conn property of the Database object
created in this class (i.e. db.Conn) to the Cmd property of the Database object created in
this class (i.e. db.Cmd).
 Set the CommandText property of the db.Cmd to “SELECT * FROM “ + tableName
 Set the Rdr property of the Database object to db.Cmd.ExecuteReader().
6 | QUEEN’S UNIVERSITY BELFAST
Task 5: Implementing the functionality of the GUI – the InnerJoinForm
We will now return to the InnerJoinForm.cs and implement the functionality for each of the
elements in the form.
Step 1: Create the DBUtilities object as per the class diagram in Figure 8. The sqlOps variable
should be set to a String array of {"=","<>",">=","<=","<",">"}.
Figure 8
Step 2: The InnerJoinForm constructor should set up the following:







assign the parameter passed in to the db variable
call the InitializeComponent() method
assign dtUtils to a new DBUtilities object passing in the database
assign tables by calling the getTablesFromDB() method on the dbUtils variable.
call the buildConstantDropDowns() method (which will be implemented later in this class)
call the buildTableNameDropDowns() method (which will be implemented later in this
class)
set the enabled property of the executeBtn on the form to false.
7 | QUEEN’S UNIVERSITY BELFAST
Step 3: We will now implement the buildConstantDropDowns() method as part of the
InnerJoinForm class as follows:


Create a for loop to run through each of the elements of the sqlOps array
Add each one as an item to the condtitionCBox combo box on the form
Step 4: We will now implement the buildTableNameDropDowns() method as part of the
InnerJoinForm class as follows:



Create a for loop to run through each of the elements of the tables list
Add each one as an item to the table1CBox combo box on the form
Add each one as an item to the table1CBox combo box on the form
Step 5: Save and test your work. You should be able to open the Inner Join form and the select
first and second table combo boxes should be populated along with the condition combo box.
Step 6: Create the method table1Combo_SelectedIndexChange(object sender, EventArgs e)
and populate it as follows:


If the SelectedIndex of table1CBox is greater than -1 then call the buildCheckedList
method with the following information passed to it:
o table1CBox.Text
o table1CheckList.Items
o table1ColCBox.Items
Set the text of table1NameLbl to the text of table1CBox + “ Columns”
Step 7: Return to the Design view of InnerJoinForm, click on table1CBox combo box and from the
events option in the Properties Panel ensure that the SelectedIndexChanged is set to the new
method
Step 8: Repeat steps 6 and 7 for table2CBox combo box; create the method and attach it as an
event.
Step 9: We will now implement the buildCheckedList method.
accept the following parameters:



This should return nothing but
String tableName
CheckedListBox.ObjectCollection checkedListList
ComboBox.ObjectCollection dropDownList
It should be implemented as follows:





Set up a list of type String called cols which will be assigned the value of the return from the
method call to getColsFromTable on the dbUtils object. This will be passed the tableName.
Call checkedListList.Clear() to clear the checkedListList (initialised at the top of the class).
Call dropDownList.Clear() to clear the dropDownList (initialised at the top of the class).
Call buildFieldCombo() method (to be implemented a little later)
For each of the elements in the cols list add cols.ElementAt(index) to the checkedListList
and also add this to the dropDownList
8 | QUEEN’S UNIVERSITY BELFAST
Step 10: Implementing this methods results in the need for a buildFieldCombo method. You should
now implement this as follows:




There is no return and no parameters
You should clear the fieldCBox i.e. fieldCBox.Items.Clear();
Check if the SelectedIndex for table1CBox combo box is greater than -1 and if it is:
o Set a String named table to tables.ElementAt(table1CBox.SelectedIndex)
o Set a List of type String called cols to the value of the return from the method call to
getColsFromTable on the dbUtils object.
o For each element in cols and the following to the Items of fieldCBox - table + "." +
cols.ElementAt(i))
Check if the SelectedIndex for table2CBox combo box is greater than -1 and if it is:
o Set a String named table to tables.ElementAt(table2CBox.SelectedIndex)
o Set a List of type String called cols to the value of the return from the method call to
getColsFromTable on the dbUtils object.
o For each element in cols and the following to the Items of fieldCBox - table + "." +
cols.ElementAt(i))
At this stage our next task is to take all the information from the combo boxes and text field at the
top of the form to generate an SQL statement. We will now code this method in the
InnerJoinForm.
Step 11: We will now populate the createSqlStringFromGUI method as follows:

Check each of the combo boxes at the top of the form (six in total) along with the text field
to ensure nothing has been left empty (i.e. if the selected index is -1 nothing has been
selected).
o If one of them are empty then inform the user
o If not check if the same table has been selected in table1CBox and table2CBox
 If these are the same then tell the user that the two table must be different
o If all is filled in then:
 Create a String initialised to hold “SELECT “ called sql;
 Set the selected list equal to a new empty list of String
 For each object in table1CheckList.CheckedItems add the following to the
selected list: table1CBox.Text + ".” + itemChecked.ToString()
 For each object in table2CheckList.CheckedItems add the following to the
selected list: table2CBox.Text + ".” + itemChecked.ToString()
 If the count of the selected list is equal to 1 then append to the variable sql
selected.ElementAt(0) + “ FROM ”
 Otherwise loop through the elements of the selected list to count-1 and
append to the variable sql selected.ElementAt(index) + “, ”
 When the loop has finished append to the variable sql
selected.ElementAt(selected.Count - 1) + “ FROM ”
 Append to the variable sql table1CBox.Text + “ INNER JOIN ” + table2CBox + “
ON ”
 Append to the variable sql table1CBox.Text + “.” + table1ColCBox.Text + “ = “
+ table2CBox.Text + “.” + table2ColCBox.Text
 Append to the variable sql “ AND ” + fieldCBox.Text + “ “ +
conditionCBox.Text + “ “
 Try to convert the text from the valueTextBox to an Int32 and append the
result to the sql variable
9 | QUEEN’S UNIVERSITY BELFAST
Otherwise catch the exception and append to the variable sql "\'" +
valueTb.Text + "\'"
 Set the Enabled property of the execute button to true
 Return the sql variable
Otherwise set the Enabled property of the execute button to false
Return a String which tells the user there was an error in SQL statement generation.

o
o
Step 12: The method we have just implemented will be called when we click the Generate SQL
button. Therefore double click on this button on the interface Design view and add the following
code to the generateBtn_Click method:

Set the text of the queryTextBox to call the createSqlStringFromGui() method
Step 13: We will now need to implement the functionality of the executeBtn click event. Therefore
double click on this button on the interface Design view and add the following code to the
executeBtn_Click method:


Set the report variable equal to a new ReportDBAccess and call on it the reportGeneration
method passing queryTextBox.Text and selected
Call the displayReport() method (we will implement this next).
Step 14: Implement the displayReport method in the InnerJoinForm class as follows:





Assign a new DataTable to the table variable
for each element in the report.ColumnNames add to table.Columns
report.ColumnNames.ElementAt(index)
for each element in the report.Rows add to table.Rows
report.Rows.ElementAt(index).ToArray()
Set the DataSource of the resultsDataGrid to the table variable
call the AutoResizeCoulmns method on the resultsDataGrid
Step 15: Save and test your work.
10 | QUEEN’S UNIVERSITY BELFAST