Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
Extensible Storage Engine wikipedia , lookup
Entity–attribute–value model wikipedia , lookup
Microsoft Jet Database Engine wikipedia , lookup
Concurrency control wikipedia , lookup
Microsoft SQL Server wikipedia , lookup
Open Database Connectivity wikipedia , lookup
ContactPoint wikipedia , lookup
Clusterpoint wikipedia , lookup
Versant Object Database wikipedia , lookup
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