3.After you specify a connection, it will be saved as an application setting in the application configuration file.
When the application is later deployed, the connection string can be modified to point to the production database. This process can often take longer than expected to ensure that various security permissions line up. Because the connection string is stored in the configuration file as a string without any schema, it is quite easy to make a mistake when making changes to it.
A little-known utility within Windows can be used to create connection strings, even if Visual Studio is not installed. Known as the Data Link Properties dialog, you can use it to edit Universal Data Link files, files that end in .udl. When you need to create or test a connection string, you can simply create a new text document, rename it to something.udl and then double-click it. This opens the Data Link Properties dialog, which enables you to create and test connection strings for a variety of providers. Once you have selected the appropriate connection, this information will be written to the UDL file as a connection string, which can be retrieved by opening the same file in Notepad. This can be particularly useful if you need to test security permissions and resolve other data connectivity issues.
4.After specifying the connection, the next stage is to specify the data to be extracted. At this stage you will be presented with a list of tables, views, stored procedures, and functions from which you can select what to include in the DataSet. Figure 30-3 shows the final stage of the Data Source Configuration Wizard with a selection of columns from the Contact table in the AdventureWorks database.
You will probably want to constrain the DataSet so it doesn’t return all the records for a particular table. You can do this after creating the DataSet, so for the time being simply select the information you want to return. The editor’s design makes it is easier to select more information here and then delete it from the designer, rather than create it afterwards.
Figure 30-3
Strongly Typed DataSets
5.Click Finish to add the new DataSet to the Data Sources window, shown in Figure 30-4, where you can view all the information to be retrieved for the DataSet. Each column is identified with an icon that reflects the type of data. For example, the Contact ID and EmailPromotion fields are numeric, whereas the Name fields are clearly text.
Figure 30-4
DataSet Designer
The Data Source Configuration Wizard uses the database schema to guess the appropriate .NET type to use for the DataTable columns. In cases where the wizard gets information wrong, it can be useful to edit the DataSet without the wizard. To edit without the wizard, right-click the DataSet in the Data Sources window and select Edit DataSet with Designer from the context menu. Alternatively, you can open the Data Sources window by double-clicking on the XSD file in the Solution Explorer window. This will open the DataSet editor in the main window, as shown in the example in Figure 30-5.
Figure 30-5
Chapter 30
Here you start to see some of the power of using strongly typed DataSets. Not only has a strongly typed table (Contact) been added to the DataSet, you also have a ContactTableAdapter. This TableAdapter is used for selecting from and updating the database for the DataTable to which it is attached. If you have multiple tables included in the DataSet, you will have a TableAdapter for each. Although a single TableAdapter can easily handle returning information from multiple tables in the database, it becomes difficult to update, insert, and delete records.
As you can see in Figure 30-5, the strongly typed TableAdapter also has Fill and GetData methods, which are called to extract data from the database. The following code shows how you can use the Fill method to populate an existing strongly typed DataTable, perhaps within a DataSet. Alternatively, the GetData method creates a new instance of a strongly typed DataTable:
Dim ta As New AdventureWorksDataSetTableAdapters.ContactTableAdapter Dim contacts1 As New AdventureWorksDataSet.ContactDataTable ta.Fill(contacts1)
Dim contacts2 As AdventureWorksDataSet.ContactDataTable = ta.GetData
In Figure 30-5, the Fill and GetData methods appear as a pair because they make use of the same query. The Properties window can be used to configure this query. A query can return data in one of three ways: using a text command (as the example illustrates), a stored procedure, or tabledirect (where the contents of the table name specified in the CommandText are retrieved). This is specified in the CommandType field. Although the CommandText can be edited directly in the Properties window, it is difficult to see the whole query and easy to make mistakes. Clicking the ellipses button (at the top-right of Figure 30-5) opens the Query Builder window, shown in Figure 30-6.
Strongly Typed DataSets
The Query Builder dialog is divided into four panes. In the top pane is a diagram of the tables involved in the query, and the selected columns. The second pane shows a list of columns related to the query. These columns are either output columns, such as FirstName and LastName, or a condition, such as the EmailPromotion field, or both. The third pane is, of course, the SQL command that is to be executed. The final pane includes sample data that can be retrieved by clicking the Execute Query button (in the bottomleft corner of Figure 30-6). If there are parameters to the SQL statement (in this case, @Promotion), a dialog will be displayed, prompting for values to use when executing the statement (see Figure 30-7).
Figure 30-7
To change the query, you can make changes in any of the first three panes. As you move between panes, changes in one field are reflected in the others. You can hide any of the panes by unchecking that pane from the Panes item of the right-click context menu. Conditions can be added using the Filter column. These can include parameters (such as @Promotion), which must start with the at (@) symbol.
Returning to the DataSet designer, and the properties window associated with the Fill method, click the ellipses to examine the list of parameters. This shows the Parameters Collection Editor, as shown in Figure 30-8. Occasionally, the Query Builder doesn’t get the data type correct for a parameter, and you may need to modify it using this dialog.
Figure 30-8
Chapter 30
Also from the properties window for the query, you can specify whether the Fill and/or GetData methods are created, using the GenerateMethods property. You can also specify the names of the generated methods.
The other window that is occasionally useful when working with the DataSet designer is the Preview Data window. This is similar to the fourth pane in the Query Builder where parameters can be supplied and a query executed to preview the results, as shown in Figure 30-9. Open the Preview Data window by selecting Preview Data from the right-click context menu on any of the DataTables or TableAdapters on the DataSet designer.
Figure 30-9
Working with Data Sources
So far you have created a strongly typed DataSet that contains a number of rows from the Contact table, based on a Promotion parameter. The DataSet is contained within a class library that you are going to expose to your application via a web service. To do this, you need to add a Windows application and an ASP.NET web service application to your solution.
Strongly Typed DataSets
In the Web Service project, you will add a reference to the class library. You also need to modify the Service class file so it has two methods, in place of the default HelloWorld web method:
Imports System.Web
Imports System.Web.Services
Imports System.Web.Services.Protocols
Imports DataTierLibrary
<WebService(Namespace:=”http://tempuri.org/”)> _ <WebServiceBinding(ConformsTo:=WsiProfiles.BasicProfile1_1)> _ <Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _ Public Class Service
Inherits System.Web.Services.WebService
<WebMethod()> _
Public Function RetrieveContacts(ByVal PromotionalCategory As Integer) _
As DataTierLibrary.AdventureWorksDataSet.ContactDataTable Dim ta As New AdventureWorksDataSetTableAdapters.ContactTableAdapter return ta.GetData(promotionalcategory)
End Function
<WebMethod()> _
Public Sub SaveContacts(ByVal changes As Data.DataSet) Dim changesTable as Data.DataTable = changes.Tables(0)
Dim ta As New AdventureWorksDataSetTableAdapters.ContactTableAdapter ta.Update(changesTable.Select)
End Sub End Class
The first web method, as the name suggests, retrieves the list of contacts based on the promotionalcategory that is passed in. In this method, you create a new instance of the strongly typed TableAdapter and return the DataTable retrieved by the GetData method. The second web method is used to save changes to a DataTable, again using the strongly typed TableAdapter. As you will notice, the DataSet that is passed in as a parameter to this method is not strongly typed. Unfortunately, the generated strongly typed DataSet doesn’t provide a strongly typed GetChanges method, which will be used later to generate a DataSet containing only data that has changed. This new DataSet is passed into the SaveContacts method so that only changed data needs to be sent to the web service.
Web Service Data Source
These changes to the web service complete the server side of the process, but your application still doesn’t have access to this data. To access the data from your application, you need to add a Data Source to the application. Again, use the Add New Data Source Wizard, but this time select a web service from the Data Source Type screen. To add a Web Service Data Source, you need to specify a URL from which the Web Service schema can be deduced. Add the Web Service Data Source via the Add Web Reference dialog that is displayed after you select the web service Data Source type, as shown in Figure 30-10.
Chapter 30
Clicking the “Web services in this solution” link displays a list of web services available in your solution. The web service that you have just been working on should appear in this list. When you click the hyperlink for that web service, the Add Reference button is enabled. Clicking the Add Reference button will add an AdventureWorksDataSet to the Data Sources window under the localhost node (which you should rename via the Properties window, as it is not a very practical namespace). Expanding this node, you will see that the Data Source is very similar to the Data Source you had in the class library.
Figure 30-10
Browsing Data
To actually view the data being returned via the web service, you need to add some controls to your form. Open the form so the designer appears in the main window. In the Data Sources window, click the Contact node and select Details from the drop-down. This indicates that when you drag the Contact node onto the Form, Visual Studio 2005 will create controls to display the details of the Contact table (for example, the row contents), instead of the default DataGridView. Next, select the attributes you want to display by clicking on them and selecting the control type to use. For this scenario, select None for NameStyle, Suffix, and Phone. When you drag the Contact node onto the Form, you should end up with the layout shown in Figure 30-11.
In addition to adding controls for the information to be displayed and edited, a navigator control has also been added to the top of the form (this isn’t generated if a DataGridView is selected), and an Adventure WorksDataSet and a ContactBindingSource have been added to the nonvisual area of the form.
Strongly Typed DataSets
Figure 30-11
The final stage is to wire up the Load event of the form to retrieve data from the web service, and to add the Save button on the navigator to save changes. Right-click on the save icon and select Enabled to enable the Save button on the navigator control, and then double-click on the save icon to generate the stub event handler. Add the following code to load data and save changes via the web service you created earlier:
Public Class Form1
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load Me.ContactBindingSource.DataSource = _
My.WebServices.Service.RetrieveContacts(2)
End Sub
Private Sub ContactBindingNavigatorSaveItem_Click _
(ByVal sender As System.Object, ByVal e As System.EventArgs) _
Handles ContactBindingNavigatorSaveItem.Click Me.ContactBindingSource.EndEdit()
Dim ds As DataTier.AdventureWorksDataSet.ContactDataTable = _ CType(Me.ContactBindingSource.DataSource, _
DataTier.AdventureWorksDataSet.ContactDataTable) Dim changesTable As DataTable = ds.GetChanges()
Dim changes as New DataSet changes.Tables.Add(changesTable) My.WebServices.Service.SaveContacts(changes)
End Sub End Class
Chapter 30
To retrieve the list of contacts from the web service, all you need to do is call the appropriate web method — in this case, RetrieveContacts. Pass in a parameter of 2, which indicates that only contacts with a promotional code of 2 should be returned. The Save method is slightly more complex, as you have to end the current edit (to make sure all changes are saved), retrieve the DataTable, and then extract the changes as a new DataTable. Although it would be simpler to pass a DataTable to the SaveContacts web service, only DataSets can be specified as parameters or return values to a web service. As such, you can create a new DataSet and add the changes DataTable to the list of tables. The new DataSet is then passed into the SaveContacts method. As mentioned previously, the GetChanges method returns a raw DataTable, which is unfortunate because it limits the strongly typed data scenario.
This completes the chapter’s coverage of the strongly typed DataSet scenario, and provides you with a two-tiered solution for accessing and editing data from a database via a web service interface.
Summar y
This chapter provided an introduction to working with strongly typed DataSets. Support within Visual Studio 2005 for creating and working with strongly typed DataSets simplifies the rapid building of applications. This is clearly the first step in the process of bridging the gap between the object-oriented programming world and the relational world in which the data is stored.
The following chapter looks in more detail at some of the controls this chapter merely introduced, such as the bindingsource and navigator controls. In addition, it explains how you can use the third type of Data Source — Objects — to persist and work with data.
Data Binding and Object
Data Sources
Chapter 30 looked at strongly typed DataSets as an introduction to working with data in Visual Studio 2005. This chapter examines the data-binding controls in more detail, showing how they interact and how you can use the designers to control how data is displayed.
Data Binding
Data binding has often been the bane of a developer’s existence. Most developers at some stage or another have resorted to writing their own wrappers to ensure that data is correctly bound to the controls on the screen. Visual Studio 2005 dramatically reduces the pain of getting two-way data binding to work. The examples used in the following sections work with the AdventureWorks sample database, and as in the previous chapter you will add this as a Data Source to your application. For simplicity, you’ll work with a single Windows application, but the concepts discussed here can be extended over multiple tiers.
In this example, you build an application to assist you in managing the customers for AdventureWorks. To begin, you need to ensure that the AdventureWorksDataSet contains the Customer, SalesTerritory, Individual, Contact, and SalesOrderHeader tables. With the form designer and Data Sources window open, set the mode for the Customer table to Details using the drop-down list. Before creating the editing controls, tweak the list of columns for the Customer table. You’re not that interested in the CustomerID or rowguid fields, so set them to None (again using the drop-down list for those nodes in the Data Sources window). AccountNumber is a generated field, and ModifiedDate should be automatically set when changes are made, so both of these fields should appear as labels, preventing them from being edited.