Sams Data base Programming With VB Dot Net And A DO Dot Net

Description

Submitted By: M.Umair Sheikh (Umee)
Email: umair_sheikh2002@hotmail.com

Reviews
Shared by: Umair Sheikh
Stats
views:
233
rating:
not rated
reviews:
0
posted:
10/1/2009
language:
English
pages:
0
ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] • • Table of C ontents Index Database Programming with Visual Basic® .NET and ADO.NET: Tips, Tutorials, and Code By F. Scott Barker Publisher Pub Date ISBN Pages : Sams Publishing : September 12, 2002 : 0-672-32247-1 : 544 The topic combination of VB .NET and ADO.NET is unbeatable. VB .NET is the most popular language in which to code. And, every developer needs to understand ADO.NET to allow data to be accessed from a Web site. In this book Developers will be shown numerouse code examples that will illustr4ate how to program database driven applications within the .NET Framework. The book is aimed at both established and new VB Developers. Important topics covered include: Visual Studio development environment, ASP.NET applications, Windows Forms application, using VB .NET with ADO.NET, complex queries, security, COM interop., and application deployment. [ Team LiB ] Page 1 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] • • Table of C ontents Index Database Programming with Visual Basic® .NET and ADO.NET: Tips, Tutorials, and Code By F. Scott Barker Publisher Pub Date ISBN Pages : Sams Publishing : September 12, 2002 : 0-672-32247-1 : 544 C opyright About the Author Acknowledgments Tell Us What You Think! Introduction Who Is This Book For? What's C overed in Database Programming with Visual Basic .NET and ADO.NET: Tips, Tutorials, and Code? C hapter 1. Section Section Section Section Section Section Section Section Section Developing Windows Forms Using Bound C ontrols 1.1. C reate a Bound List Box 1.2. Limit the Data Displayed in a Bound List Box 1.3. Bind and View Individual Text Boxes Based Off a Selected List Box Item 1.4. Edit and Update Data Using Bound C ontrols 1.5. Add and Delete Records Using Bound C ontrols 1.6. Take C are of Error Handling with Bound C ontrols 1.7. Put the Finishing Touches on a Data Bound Form 1.8. Bind Data to C omboBox and DataGrid C ontrols 1.9. Drill Down to Data in the DataGrid C ontrol C hapter 2. C reating SQL Server Database Objects From Visual Studio .NET Working with Tables, C olumns, and Rows Utilizing Properties for Tables and C olumns Section 2.1. C reate a New SQL Server Database from Within Visual Studio .NET Section 2.2. Define Tables and Fields Section 2.3. Define a Primary Key and Other Indexes Section 2.4. Define Relations Between Tables Section 2.5. Define Defaults and C onstraints Section 2.6. C reate Views Section 2.7. C reate Stored Procedures Page 2 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html C hapter 3. Viewing Data With ADO.NET Differences Between ADO and ADO.NET Objects That Are Found in ADO.NET Section 3.1. Retrieve Data by Using the DataReader Object Section 3.2. Retrieve Results from SQL Server by Using the DataTable Object Section 3.3. Locate Records with the DataTable Object Section 3.4. Filter and Sort Records Using the DataView Object C hapter 4. Section Section Section Section Manipulating Data With ADO.NET 4.1. Edit Data and Update C hanges That Are Made to an ADO.NET DataSet Object 4.2. Add and Delete Rows in a Dataset with ADO.NET 4.3. Execute Parameterized Stored Procedures in ADO.NET 4.4. C reate and Execute On-the-Fly Batch Updates by Using ADO.NET C hapter 5. Working With Data In Web Forms Dealing with Stateless Programming Section 5.1. Use Bound C ontrols with Web Forms Section 5.2. Validate Data Using Validation C ontrols Section 5.3. Populate DropDown and ListBox C ontrols Section 5.4. Display Data Using the Table C ontrol Section 5.5. Display Data Using the Repeater C ontrol C omments Section 5.6. Display, Sort, and Page Data in the DataGrid C ontrol Section 5.7. Add, Edit, and Delete Data Using the DataGrid C ontrol Section 5.8. Hyperlink from a Row in the Data Grid to a Detail Page C hapter 6. Section Section Section Section Section Section Section Section C reating Transact-SQL C ommands 6.1. Retrieve Unique Records Using Only a Select Query 6.2. Use Variables and Functions in T-SQL 6.3. Use Wildcards and Ranges of Values in a SQL Query 6.4. Find Records in a Table Without C orresponding Entries in a Related Table 6.5. Take Advantage of Using Subqueries 6.6. C reate, Modify, and Delete Tables 6.7. C reate a New Table with Data from Existing Tables 6.8. C reate and C all SQL Server 2000 User-Defined Functions C hapter 7. Performing C ommon Database Tasks Using SQL-DMO Looking at the SQL Server DMF APIs Setting References in .NET for the SQL APIs Section 7.1. C reate a Dialog Box to C onnect to a New Database, Including Listing Available SQL Servers Section 7.2. Section 7.3. Section 7.4. Section 7.5. C hapter 8. Section Section Section Form Section Section Section Section Section C hapter 9. Section Section Section Section and Databases Back Up and Verify a SQL Server Database Restore a SQL Server Database Transfer Tables Between SQL Server Databases C reate a Detach/Attach SQL Server Database Dialog Box Taking Advantage of Data-Driven Techniques 8.1. Work with Data-Bound Multi-Select List Boxes Using Windows Forms 8.2. Use a Single Windows Form to Update Multiple Lookup Tables 8.3. C reate a Point-and-C lick SQL Server Query Tool for Users Using a Windows 8.4. 8.5. 8.6. 8.7. 8.8. Make a Generic Search Form in a Visual Basic .NET Desktop Application Work with Data-Bound Multi-Select List Boxes Using Web Forms Use a Single Web Form to Update Multiple Lookup Tables C reate a Point-and-C lick Query Tool for Users Using a Web Form Make a Generic Search Form in an ASP.NET Web Application Using C lasses With Databases to Make Life Easier 9.1. Define a C lass in Visual Basic .NET 9.2. C reate a C lass That Implements the Interface You Defined 9.3. Use Visual Studio .NET Tools to Speed Up Writing ADO.NET C ode 9.4. C ontrol the C reation and Behavior of C lasses Page 3 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Section 9.5. Implement the Methods That Update the Database Section 9.6. Validate Data Passed to Properties and C ommunicate Errors to Developers Section 9.7. Write Data Validation C ode That C an Be Reused in Other C lasses C hapter 10. C reating Reports Using C rystal Reports Section 10.1. C reate a Report Using C rystal Reports Report Expert Section 10.2. Display a Report That Was C reated Section 10.3. Add C alculated Fields to the C rystal Reports Report Section 10.4. Select Whether the Report Will Be Displayed, Printed, or Exported Using Visual Basic .NET C ode Section 10.5. Determine Which Records Will Be Printed at Runtime Section 10.6. Print Labels and C ontrol the Order in Which Records Will Be Printed Section 10.7. C reate an Onscreen Report That C ontains Hyperlinks C hapter 11. Managing SQL Server Security Section 11.1. C reate Windows NT/2000 Users Section 11.2. C reate Windows NT/2000 Groups Section 11.3. Establish a Windows NT/2000 Authentication Mode Section 11.4. Establish Mixed-Mode Authentication Section 11.5. C reate a Standard Login Section 11.6. C reate a Windows NT/2000 Login Section 11.7. Use a Fixed Server Role Section 11.8. C reate a Database User Account Section 11.9. Use Statement Permissions Section 11.10. Use Object Permissions Section 11.11. Use Fixed Database Roles Section 11.12. C reate C ustom Database Roles Section 11.13. C reate Application Roles C hapter 12. Utilizing XML Data In Your Visual Basic .NET Applications Ways of Utilizing XML in .NET XML Namespaces in .NET Section 12.1. Use XMLWriter to C reate an XML Document Section 12.2. Use XMLReader to Read an XML Document Section 12.3. Work with the XML Document Object Model Section 12.4. Retrieve XML from SQL Server 2000 Section 12.5. Work with Datasets and XML C hapter 13. C reating XML Web Services Overview of the XML Web Services Infrastructure Section 13.1. Get Started with XML Web Services Section 13.2. C reate a Simple XML Web Service Using Parameters Section 13.3. C onsume XML Web Services Section 13.4. Pass a Dataset Back from an XML Web Service Appendix A. Desktop Development With ADO When to Use ADO (Local Database/Single Tier Applications) Looking At the ADO Object Models Referencing the Type Libraries Using the Connection Object Working with the ADO Recordset Object Executing a SQL Server Stored Procedure By Using ActiveX Data Objects Executing Batch Updates with ADO and SQL Server C reating SQL Server Objects with ActiveX Data Objects C onclusion Index [ Tea m LiB ] Page 4 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Page 5 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Copyright Copyright © 2003 by Sams Publishing All rights reserved. No part of this book shall be reproduced, stored in a retrieval system, or transmitted by any means, electronic, mechanical, photocopying, recording, or otherwise, without written permission from the publisher. No patent liability is assumed with respect to the use of the information contained herein. Although every precaution has been taken in the preparation of this book, the publisher and author assume no responsibility for errors or omissions. Nor is any liability assumed for damages resulting from the use of the information contained herein. Library of Congress Catalog Card Number: 2001094459 Printed in the United States of America First Printing: September 2002 05 04 03 02 4 3 2 1 Trademarks All terms mentioned in this book that are known to be trademarks or service marks have been appropriately capitalized. Sams Publishing cannot attest to the accuracy of this information. Use of a term in this book should not be regarded as affecting the validity of any trademark or service mark. Warning and Disclaimer Every effort has been made to make this book as complete and as accurate as possible, but no warranty or fitness is implied. The information provided is on an "as is" basis. The author and the publisher shall have neither liability nor responsibility to any person or entity with respect to any loss or damages arising from the information contained in this book. Credits ASSOCIATE PUBLISHER Michael Stephens ACQUISITIONS EDITOR Neil Rowe DEVELOPMENT EDITOR Kevin Howard MANAGING EDITOR Charlotte Clapp PROJECT EDITORS Matt Purcell Tony Reitz Page 6 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html COPY EDITOR Karen A. Gill INDEXER Sandy Henselmeier PROOFREADER Linda Seifert TECHNICAL EDITOR Shawn Nanto TEAM COORDINATOR Lynne Williams INTERIOR DESIGNER Gary Adair COVER DESIGNER Alan Clements PAGE LAYOUT Stacey Richwine-DeRome Dedication I would like to dedicate this book to the innocent men, women, and children who died in the September 11, 2001 attack in New York, at the Pentagon, and those in the airplanes as well. God bless you, and God bless America! [ Team LiB ] Page 7 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] About the Author F. Scott Barker holds a bachelor of science in computer science and has worked as a developer in the database field for more than 16 years, first with Clipper, and then with Visual Basic, SQL Server, and Microsoft Access for the past 10 years. Scott has already created and deployed a number of ASP.NET Web sites for his clients. Working at Microsoft for two years, Scott was a member of the Microsoft Access and FoxPro teams. Since leaving, he has been a contractor with Microsoft developing in-house tools used throughout Microsoft. With his company, Applications Plus, Scott has also been doing contract development for many Fortune 500 companies, developing in ASP.NET, Visual Basic .NET, C#, Visual Basic/Access/Office, and SQL Server. Scott has trained for Application Developers Training Company and others all around the U.S. and is a frequent speaker at Microsoft conferences throughout the U.S., Canada, South Asia, and Europe. Through his classes and conferences, Scott has trained thousands of developers. Scott is a writer for a number of development magazines and is the author of F. Scott Barker's Microsoft Access 2002 Power Programming, published by Sams, and Access 97 Power Programming, published by Que. Scott can be reached at his Web site at www.appsplus.com, or via e-mail at FSBarker@AppsPlus.com. [ Team LiB ] Page 8 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Acknowledgments To start off, I want to acknowledge Neil Rowe, my acquisitions editor, for putting up with me for another book. Thanks also to Kevin Howard, my development editor. Bud, you had me scared at first. A big thanks goes to my longtime friends Paul Sheriff, Ken Getz, Mike Groh, and Tom Howe, for putting up with me that week at Paul's class, helping me hammer out the outline, and being around for me to bounce ideas off of. A really special thanks goes to Michael O'Neil for his work on the Classes chapter. He is a man who has a lot of class. Good luck with NYU! Another thanks to Mike Groh for his work on the Security chapter, you are a great friend Mike, and know your stuff! Thanks to the students who attended my .NET classes and helped to shape the contents of this book as I was writing it. No, you don't get any of my royalties, but you have my thanks. As usual, I want to thank some people from Microsoft for putting up with my questions, listening to my beefs, and not telling me where to go when I got on their nerves. Ari Bixhorn, you are one of the most enthusiastic guys I know. My thanks to you and Ed Robinson for being so patient with me and letting your excitement for .NET show through so honestly. My thanks to Woodinville #2 Starbucks for putting up with me rearranging their furniture so I could work by both the plug-in and the fireplace while I cranked on this book and for keeping those lattes and cappuccinos coming. Finally, I need to acknowledge those people who put up with me the most: my wife Diana, and my kids Christopher, Kari Anne, Nichole, David, and Joseph. Let's go skiing! [ Team LiB ] Page 9 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Tell Us What You Think! As the reader of this book, you are our most important critic and commentator. We value your opinion and want to know what we're doing right, what we could do better, what areas you'd like to see us publish in, and any other words of wisdom you're willing to pass our way. As an associate publisher for Sams, I welcome your comments. You can fax, e-mail, or write me directly to let me know what you did or didn't like about this book as well as what we can do to make our books stronger. Please note that I cannot help you with technical problems related to the topic of this book, and that due to the high volume of mail I receive, I might not be able to reply to every message. When you write, please be sure to include this book's title and author as well as your name and phone or fax number. I will carefully review your comments and share them with the author and editors who worked on the book. Fax: E-mail: Mail: 317-581-4770 feedback@samspublishing.com Michael Stephens Sams Publishing 201 West 103rd Street Indianapolis, IN 46290 USA [ Team LiB ] Page 10 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Introduction Dear Reader, Here we are on the brink of what feels like another revolution of computing: .NET. Now I know what some people are saying: .NET is merely evolutionary, not revolutionary. I disagree. Here I sit at the San Francisco airport, waiting for my return flight home to Seattle, sipping on my ice quad venti vanilla latte (yes, that is a coffee drink) pondering all wonderful technology I witnessed this week. You see, I spent the past five days sitting in on Paul Sheriff's "Jumpstart Introduction to VB.NET Week." Along with around 20 regular students, Paul had asked a few of his friends who were also interested in presenting the training down for what is called "Train the Trainer." By the time you read this, I will have presented the training myself a few times. I have to admit I have not been as excited about a product like this since my early days of working on the Access team. (No snide remarks about Access, please.) I have been working primarily in Access/Visual Basic/SQL Server for the past 10 years and making a good living at it. The Web daunted me with all that there was to develop for it using products such as ASP and HTML. That has all changed. Now the line between developing for the Web and desktop has become almost invisible. Developing with Visual Basic .NET and databases is more powerful than ever, and you can easily blend creating Windows Forms (Visual Basic .NET) and Web Forms (ASP.NET) into the same solution. One of the most exciting things is that when you know how to work with ADO.NET using Windows Forms, you can use similar techniques and the same objects in Web Forms. I hope that, with this book, you will become as excited as I am about creating database applications using Visual Basic .NET! Sincerely, F. Scott Barker Author, Database Programming with Visual Basic .NET and ADO.NET: Tips, Tutorials, and Code [ Team LiB ] Page 11 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Who Is This Book For? This book is for the serious developer, whether corporate or independent, who wants to create database applications using Visual Basic .NET. If you are looking for a primer on .NET or even a beginner book for Visual Basic .NET, then you would be wise to pick up another book to give you the basics on those topics. This book focuses on the topic I love best: database development. Current Visual Basic developers will get quite a bit out of this book. Although you will find that much of Visual Basic .NET looks familiar, the language has grown up quite a bit and even gets more of the respect it deserves since we can now use the Visual Basic we know and love in Web Forms as well as Windows Forms. Those who are familiar with ADO will appreciate the samples that show how to use ADO.NET. Hopefully, even hard-core Visual Basic developers will appreciate the chapter on wrapping up some of the ADO.NET data access into classes for simplified coding. Those Access developers who are attempting to take the plunge and expand their horizons hopefully will be placed at ease with how similar developing databases between Access and Visual Basic is. If you have already worked with SQL Server and ADO, then you are ahead of the game. Even if you haven't developed in Visual Basic previously, this book will give you some great sample code to get started. Corporate management will find this book useful for getting an idea of what their developers can do with Visual Basic .NET, both on the desktop and Web sides. [ Team LiB ] Page 12 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] What's Covered in Database Programming with Visual Basic .NET and ADO.NET: Tips, Tutorials, and Code? I have laid out this book to logically follow the course of learning how to use the database features of Visual Basic .NET and be as productive as possible, as quickly as possible. Hopefully, you can see this even with the way I have laid out and labeled the chapters:  Chapter 1, "Developing Windows Forms Using Bound Controls," gets you started being productive from the get-go. You will get a great start on creating Windows Forms in Visual Basic .NET that you can use not only to view data, but also to add, edit, and delete data. You will accomplish this quickly by using bound controls that are more robust than what is found in previous versions of Visual Basic.  Chapter 2, "Creating SQL Server Database Objects from Visual Studio .NET," shows you how to use some of the design tools found inside Visual Studio .NET to create and maintain SQL Server databases.  Chapter 3, "Viewing Data with ADO.NET," takes you into using the objects found in ADO.NET, such as the OleDbDataReader and OleDbDataSet. These objects and more are used to view data and load it into various controls such as list boxes and combo boxes.  Chapter 4, "Manipulating Data with ADO.NET," takes you further into using the objects found in ADO.NET. You will see how to use the various objects in ADO.NET to add, edit, and delete records and manipulate data.  Chapter 5, "Working with Data in Web Forms," takes what you learned in the previous chapters and shows you how to create useful Web Forms using ASP.NET, including taking advantage of the DataGrid control.  Chapter 6, "Creating Transact-SQL Commands," brings you deeper into the language that makes SQL Server such a powerful database. It teaches you how to take advantage of the Transact-SQL commands to update and manipulate your SQL Server database from Visual Basic .NET.  Chapter 7, "Performing Common Database Tasks Using SQL-DMO," explains how to perform day-to-day tasks in your Visual Basic .NET application that an administrator would normally have to do. This includes common tasks such as importing/exporting data and backing up/restoring databases.  Chapter 8, "Taking Advantage of Data-Driven Techniques," takes what you have learned in the book so far and puts it to even more practical use. This chapter shows you how to create utilities that perform more tasks with less code. This chapter demonstrates how to create a point-and-click interface for a query tool for your users.  Chapter 9, "Using Classes with Databases to Make Life Easier," shows that even though it can take quite a bit of code to perform data access tasks, you can use classes to wrap that code for accessing data. By taking table definitions up into properties and methods, you can make accessing data in tables more intuitive and simpler to access throughout your applications.  Chapter 10, "Creating Reports Using Crystal Reports," gets into using crystal reports with Visual Basic .NET. Besides learning how to generate standard reports, you will see how to create some of the more advanced features that really take advantage of the engine. Page 13 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html  Chapter 11, "Managing SQL Server Security," discusses the SQL Server security scheme and explains the options available to you as a Visual Basic developer. Authentication modes are discussed, as are the various permissions you might set on SQL Server objects.  Chapter 12, "Utilizing XML Data in Your Visual Basic .NET Applications," shows you just how much you can use XML from within your applications. You are shown how to load and manipulate XML document objects, as well as retrieve XML from SQL Server 2000.  Chapter 13, "Creating XML Web Services," show you how to take advantage of the one of the coolest new features in .NET. You can create a XML Web Service that both Internet and Desktop applications can take advantage of, and even pass ADO datasets.  Appendix A, "Desktop Development with ADO," discusses the use of ADO in your .NET applications. Although .NET uses ADO.NET, you might have a lot invested in ADO development. This Appendix shows how you can create a reference in your .NET application and what objects there are. [ Team LiB ] Page 14 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 1. Developing Windows Forms Using Bound Controls In this chapter you will          Create a bound list box Limit the data displayed in a bound list box Bind and view individual text boxes based off a selected list box item Edit and update data using bound controls Add records using bound controls Take care of error handling with bound controls Put the finishing touches on an add/edit/delete form Bind data to ComboBox and DataGrid controls Drill down to data in the DataGrid control Visual Basic .NET, one of the languages that ships with Visual Studio .NET, is a far more robust language than what was found in Visual Basic 6.0. Now, before you VB 6 developers go off and start cussing me for saying this, read on. As in previous versions of Visual Basic, you can use code to bind controls manually, which takes more work than using bound controls. The other method is to use data bound controls, which in the past were avoided because of not having total control over the way data is handled. In VB .NET, Microsoft has done a better job of not only creating the data bound controls, but because everything is class-based in the .NET languages, you also can see the code that is generated when you place data bound controls onto a form. In the prior versions of Visual Basic, the Microsoft Jet Database Engine was the database flavor of choice for small- to medium-sized databases, as well as books such as this one. Now, Visual Basic ships with the Microsoft SQL Server 2000 Desktop Edition (MSDE). This is a scaled-down version of SQL Server 2000, allowing you to create databases on your local machine and then distribute them for use on a user's individual local version of the MSDE or a larger SQL Server 2000 installation. If this sounds intimidating, don't worry. You will learn how to use SQL Server from within Visual Studio and your application. This includes creating utilities for connecting to new databases, as well as backing up and restoring databases. Although this book uses the MSDE for the database, you only have to adjust the ConnectionString property of the OleDbConnection object on forms and the ConnectionString property of the OleDbConnection object discussed in Chapter 4, "Manipulating Data with ADO.NET." In the code in Chapter 4, you will see a commented line of code that provides an example of using a Jet database version of Northwind. [ Team LiB ] Page 15 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.1 Create a Bound List Box It used to be that when you wanted to create a data entry form, you just assigned a recordset to the data control and allowed the users to scroll through the data, making changes as needed. When you're dealing with Client Server or Web applications, this just doesn't cut it. One of the first things you need to do is provide a method to limit the amount of data so that users can pick which record they want to edit/view, without pulling all the fields of a table over the Net either LAN or Internet. List boxes and combo boxes help with that. In this How-To, you will learn how to set up two data controls: OleDbDataAdapter and DataSet. These controls enable you to populate a list box with one line of code. You want to see a list of customers on your Windows form in a ListBox control. You don't want to write code at this point. You only want to prototype a form, so you just want to use bound data controls. How do you create a list box and bind it using the data controls? Technique To get started with learning about any of the objects used for data in .NET, it's important to talk about what .NET Namespaces are and how to use them. Using .NET Namespaces The .NET Framework contains a big class library. This class library consists of a number of Namespaces. These Namespaces are made up of various classes that allow us to create our objects. All of the objects and classes that make up the .NET objects, such as forms, controls, and the various data objects, can be found in Namespaces. Namespaces also can be made up of other Namespaces. For example, there is a Namespace called System.Data. Although this Namespace has classes in it, such as DataSet and DataTable, it also has Namespaces within it called System.Data.OleDb and System.Data.SQLClient, as well as others. To check out the .NET Namespaces, choose Object Browser from the View menu. You can then expand the System.Data Namespace to see the other Namespaces contained within. If you are positive that the database you are going to be working with is SQL Server, then you would be far better served performance-wise to use the classes found in the System.Data.SQLClient Namespace. However, if you are not sure what database you will be working against, you should use the classes found in System.Data.OleDb. For this book, I am using objects created from the classes in the System.Data.OleDb Namespace. That way, you can use the routines against other databases with less modifications. Tip If you know that the back end that you will be accessing is SQL Server, then use the SQL Server type data controls because they are optimized for it. Eight data controls are available for Windows forms. Table 1.1 lists these controls and their uses. You can find these controls by clicking on the Data group in the toolbox. Page 16 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 1.1. Data Controls Used in Windows Forms Control Name Purpose This control is used in conjunction with the other data controls, storing the results that are returned by commands and the DataAdapters. Unlike the recordset from ADO and DAO, the DataSet actually brings back a hierarchical view of the data. Using properties and collections in the DataSet object, you can get all the way down to individual tables, rows, and columns. DataSet OleDbDataAdapter This control stores and manages the commands you want to use against an OleDb provider such as Jet, Oracle, or SQL Server. The commands for selecting, updating, inserting, and deleting records can be used. The Connection against which to use the commands is also tracked. OleDbConnection This control maintains connection information for an OleDb provider. This control is used with the OleDbDataAdapter. Similar to the ADO command object, this control allows you to execute SQL statements or stored procedures to either run bulk operations or return data. This control is the same as the OleDbDataAdapter except that it is for use only against SQL Server stores. OleDbCommand SqlDataAdapter SqlConnection This control is the same as the OleDbConnection except that it is for use only against SQL Server stores. SqlCommand This control is the same as the OleDbCommand except that it is for use only against SQL Server stores. DataView This control creates multiple views of the same table. This includes looking at data in various states such as deleted, changed, or sorted differently. Creating two types of the data controls just mentioned, OleDbDataAdapter and DataSet, bind them to a list box to display a list of customers. Note that an OleDbConnection control is also created, but Visual Studio .NET creates it. You then add a line of code to fill the dataset. Steps To preview this How-To, open the solution called VB.Net Chapter1 found in the chapter folder. When you run the project, the first form that comes up is the main switchboard with each of the How-Tos listed for this chapter. Click on How-To 1.1 to open the form for How-To 1.1 (see Figure 1.1 ). Figure 1.1. Main form and How-To form 1.1 from the first chapter's solution. Page 17 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Note You can find the source code for all the chapters in the book at www.samspublishing.com. After you are there, just type the book ISBN (0672322471). 1. Create a new Visual Studio .NET project using the Windows Application project template. This creates the initial form called Form1 that you will use. 2. Drag the OleDbDataAdapter control from the Data Controls group located in the toolbox and drop it onto the form. The Data Adapter Configuration Wizard appears. Read the introductory screen, and then click Next to choose your data connection. At this point, if you don't see a data connection to Northwind database in the drop-down list of data connections to use, click the New Connection button. You then see the Data Link Properties dialog box with which you are familiar if you have used other Microsoft products such as Visual Studio 6.0. Type (local) for the server name, select Use Windows NT Integrated Security, and select Northwind for the database (see Figure 1.2.) Click OK. Figure 1.2. From now on, this data connection will show up in Visual Studio .NET's Server Explorer on this machine. Page 18 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Now you will be back on the Choose Your Data Connection page of the Data Adapter Configuration Wizard, with the Northwind database in the Data Connection drop-down list. Click Next. This brings you to the page to select the query type on which the data adapter will be based. Leave the default of Use SQL Statements, and click Next. In the text box that asks What Data Should the Data Adapter Load into the Dataset?, type the following: 4. 5. Select CustomerID, CompanyName From Customers Note By default, the Data Adapter Configuration Wizard creates select statements not only for selecting (viewing) data, but also for inserting, updating, and deleting. If you don't need these other options, click the Advanced Options button at the bottom-left corner of the dialog box. Deselect the check box that reads Generate Insert, Update, and Delete statements. You don't need this because we are just using the data to fill a ListBox control. Click OK to close the Advanced Options dialog box. 6. Click Next to see results of your select statement, as shown in Figure 1.3. If you see something different from Figure 1.3, you either have entered your select statement incorrectly, or you have forgotten to deselect the advanced options. Page 19 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 1.3. Success in creating the data adapter. 7. Click Finished to create a data adapter and connection object. You then see a new data adapter control called OleDbDataAdapter1 and a Connection control called OleDbConnection1. Both controls are in the Components tray below the Form designer. 8. After you have created the first two controls, it is time to create the Dataset object. Right-click on the Data Adapter and choose Generate Dataset from the pop-up menu. This opens the Generate Dataset dialog box. You can keep all the defaults and simply click OK to create a dataset control called DataSet. (The sequential number might vary if you have generated other dataset controls.) 9. Now you are ready to create the ListBox control. Drag the ListBox control from the Windows Forms group in the toolbox and drop it on your form. Stretch the control to the size of your form, and then set the following properties in Table 1.2 on the ListBox control. Table 1.2. ListBox Control Property Settings Needed to Bind a DataSet Control Property Setting DataSource DisplayMember ValueMember DataSet Customers.CompanyName Customers.CustomerID Page 20 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 10. Although you have bound the dataset to the correct properties in the ListBox control, if you run the form at this point, you will still see a blank ListBox control on the form. 11. Now it is time for the one line of code in this sample, in the Load event of the form. Click on the View Code button in the Solution Explorer, or choose Code from the View menu. In the Code Editor, select (Base Class Objects) from the Class Name drop-down list, and then select Load from the Methods drop-down list. Next, type the line of code as displayed here, which tells the data adapter to fill the dataset with data: 12. 13. OleDbDataAdapter1.Fill(DataSet1) Be sure to use the names of the controls you created. Listing 1.1 presents the Load event code for the form called frmHowTo1_1 in the samples. Listing 1.1 frmHowTo1_1.vb: Filling the Data Set on Which ListBox1 Is Based Private Sub frmHowTo1_1_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.OleDbDataAdapter1.Fill(Me.DataSet1) End Sub How It Works When the form called frmHowTo1_1 loads, the Fill method of the OleDbDataAdapter1 is called, with the DataSet1 being passed. Because the DataSource property of ListBox1 was specified as being DataSet1 and the ValueMember and DisplayMember properties are both set appropriately, ListBox1 is populated with the CustomerID and CompanyName from the Customers table in Northwind. Figure 1.4 shows what the final form looks like in Design view, and Figure 1.5 shows what it looks like when running. Figure 1.4. The final design view for your first database how-to. Page 21 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 1.5. This list is based on the Customers table in the Northwind SQL Server database. Comments In the .NET version of Visual Basic, Microsoft went to considerable effort to make the data controls more robust than ever. One cool thing is that most of the tasks that are done for you in Visual Basic .NET are discoverable. Even though you are using the data controls on your form, Visual Studio creates the code under the covers. You can see this code by clicking on the #Region statement that reads like this: #Region " Windows Form Designer generated code " Beware: There is much code here, and you don't want to change it. You can learn a lot from reading it though. As you continue to use the Data Controls shown here, you will become comfortable with changing various properties and getting more power and use out of them. Page 22 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Page 23 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.2 Limit the Data Displayed in a Bound List Box Even populating a list box with a couple of columns from a table full of data can be a big performance hit. This How-To shows you how to create a parameterized SQL statement to limit the items that are displayed in the list box, thus giving you better performance on your forms. You have hundreds of thousands of customers in your database, and you don't want the list box loaded up with the whole customer table. How can you limit the data that is displayed in your list box? Technique You are going to make a copy of the form that you created in How-To 1.1. You will then add a Label and TextBox control that the Select statement contained within the OleDbDataAdapter control will query against to limit the data displayed in the list box. A command button will be added to allow you to call the Fill method of the OleDbDataAdapter control whenever you update the text box, and then you can click the command button (see Figure 1.6). Figure 1.6. You can now limit the amount of data loaded into the list box. Steps To get started with this How-To, right-click the form you created in How-To 1.1, which should be listed in the Solutions Explorer. Choose Copy from the pop-up menu. Next, right-click the project in the Solution Explorer, and choose Paste from the pop-up menu. You will now have a new Class object in the Solutions Explorer called Copy Of whatever the previous name of the form was. Rename the new form that you have created to the name you desire. Then, with that form highlighted, click on the Code button above the Solutions Explorer. Change the first line of code to say this: Public Class You see, VS does not change the line of code automatically for you. It thinks you have a duplicate Class definition. Now you can see that the icon of the form is correct. You can continue with the steps of the How-To. 1. Select the Data Adapter that you created. In the Properties pane, you will see the Page 24 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CommandText property when you click on the SelectCommand property plus sign. Replace the CommandText property with the following command: 2. 3. SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE ? + '%') You will learn more about the Select statement in Chapter 3. However, the WHERE clause used here compares CompanyName to a parameter that will be supplied, as indicated by the ?. This will be performed using code in the final step of this How-To. The % is a wildcard that tells the server to make it a fuzzy search. 4. Resize the ListBox control, and leave room at the top of the form for the Label, TextBox, and Command button. Create these three controls, setting the properties described in Table 1.3. Table 1.3. Label, TextBox, and Command Button Control Property Settings Object Property Setting Label TextBox Text Name Text Customer txtCustLimit A btnLoadList Load List Command Button Name Text 5. Double-click the new command button you just created called btnLoadList. Enter the code in Listing 1.2 in the Click event of the btnLoadList button. This code loads the data entered from txtCustLimit into the parameter of the OleDBDataAdapter1, which was created by using the ? in the Select statement of the data adapter. Then Dataset1 is cleared of its data with the Clear method. Finally, DataSet1 is refilled with data based off the value in txtCustLimit, using the data adapter. Listing 1.2 frmHowTo1_2.vb: Submitting a Parameter to a DataAdapter and Filling the Dataset Private Sub btnLoadList_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnLoadList.Click Me.OleDbDataAdapter1.SelectCommand.Parameters(0).Value = _ Me.txtCustLimit.Text Me.DataSet1.Clear() Me.OleDbDataAdapter1.Fill(Me.DataSet1) End Sub Page 25 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Note There is one big difference here between an OleDbDataAdapter and a SqlDataAdapter. Whereas the OleDbDataAdapter takes a ? to specify a parameter within the Select statement, the SqlDataAdapter requires a named parameter such as @parCustLimit. Therefore, instead of the select statement in step 1 being this: SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE ? + '%') It would be this: SELECT CustomerID, CompanyName FROM Customers WHERE (CompanyName LIKE @parCustLimit + '%') The naming of the actual parameter is up to you. 6. Highlight and delete the Load event for the form because you don't want to just fill the event when the form loads. You want the user to click btnLoadList. How It Works When the form you created for this How-To loads, or when you're using the form called frmHowTo1_2, you will see a blank ListBox control with a text box on top with the letter A in it. If you click the command button called btnLoadList, the list box becomes filled with values based on the letter (or letters) in txtCustLimit and on the code described in step 3. Comments Try entering a few other letters, and then try entering no letters. What happens? You limit the list more by the number of letters you enter, and you get all entries when you don't enter any letters. The method displayed here, although simple, is powerful, and it can be used in a variety of ways. You can continue building on this form for the next few How-Tos. If you want to copy your form and start a new one as described at the beginning of the steps for this one, you have the instructions there. Otherwise, by the time you reach How-To 1.8, you will have a data entry form that you can use. Each step, however, is available in the sample solution for this chapter. [ Team LiB ] Page 26 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.3 Bind and View Individual Text Boxes Based Off a Selected List Box Item Using a list box similar to the one in the previous How-To, in this How-To, you will learn how to create additional OleDbDataAdapters and DataSets and bind them to individual text boxes for viewing data. Although the list box is nice for displaying a couple of fields in my form and limiting the rows displayed, how do you list the detail in individual text boxes by clicking on an item in the list box? Technique You are going to enhance the form that you created in How-To 1.2 to use additional data controls, specifically another data adapter and dataset. You will set up the select statement in the new data adapter to take the selected list box item as a parameter. The dataset will then be filled with data, and some text boxes with the dataset set as the data source will display the current record. You can see an example of this in Figure 1.7. Figure 1.7. You can bind text boxes to datasets as well as list boxes. Steps To go further with the form with which you have been working, you will want to rename the data adapter, dataset, and list box currently on the form to something more meaningful. You can see this in Table 1.4. Table 1.4. Changes to Current Objects on the Form Object Property Old Setting New Setting ListBox OleDbDataAdapter DataSet Tip Name Name Name ListBox1 OleDbDataAdapter1 DataSet1 lstCustomers odaCustomerList dsCustomerList Page 27 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Name your objects at the time you first create them. This is true of your solutions, projects, and forms, as well as controls used on forms. With the .NET languages being so class and code driven, some items take multiple steps to rename. Visual Studio doesn't seem to catch all the places in code that need to be changed. Renaming a form is a good example. Remember that you had to change the Public Class statement in the code to have it match the new name of the form. 1. Drop another Data Adapter control on the form from the Data group of the toolbox. Use the existing data connection, specify that you will use SQL statements, and assign the following select statement that will use a parameter supplied at runtime by using the selected list box item. 2. 3. 4. 5. PostalCode, Country, Phone, Fax FROM Customers WHERE (CustomerID = ?) You can click the Advanced Options button on the select statement page and deselect creating the Insert, Update, and Delete commands. Finish the Data Adapter Wizard and rename the control odaCustomerIndividual. 6. Right-click odaCustomerIndividual and choose Generate Dataset from the pop-up menu. Create a new dataset called dsCustomerIndividual. Click OK. As of this writing, VS places a 1 at the end of name of the dataset you specified. Clean up the name by removing the 1. Now you should have two data adapters: odaCustomerList and SELECT CustomerID, CompanyName, ContactName, ContactTitle, Address, City, Region, odaCustomerIndividual, and two datasets: dsCustomerList and dsCustomerIndividual. 7. Now it's time to add the text boxes. Resize the form so that it allows you to add a column of text boxes with labels beside them. You will then add the labels and text boxes, setting the Text property of the text boxes to the column names in the Customers table as supplied by dsCustomerIndividual. The Text property of text boxes falls under the Data Binding category in the property sheet. Table 1.5 describes the controls and their property settings. Refer to Figure 1.8 for an example of where to place them. Figure 1.8. Letting users know when they can edit data is helpful. Page 28 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 1.5. New Label and TextBox Control Property Settings for the Form frmHowTo1_3 Object Label Property Setting Text Customer ID Label Label Label Label Label Label Label Label Label Text Text Text Text Text Text Text Text Text Company Name Contact Contact Title Address City Region Country Phone Fax txtCustomerID dsCustomerIndividual Customers.CustomerID txtCompanyName dsCustomerIndividual Customers.CompanyName TextBox Name Text TextBox Name Text Page 29 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html TextBox Name Text txtContact dsCustomerIndividual Customers.Contact txtContactTitle dsCustomerIndividual Customers.ContactTitle txtAddress dsCustomerIndividual Customers.Address txtCity dsCustomerIndividual - Customers.City txtRegion dsCustomerIndividual Customers.Region txtPostalCode dsCustomerIndividual Customers.PostalCode txtCountry dsCustomerIndividual Customers.Country txtPhone dsCustomerIndividual - Customers.Phone txtFax dsCustomerIndividual - Customers.Fax TextBox Name Text TextBox Name Text TextBox Name Text TextBox Name Text TextBox Name Text TextBox Name Text TextBox Name Text TextBox Name Text 8. Now it's time for the code. To start off, you will change the Click event code for the button called btnLoadList. The first three lines of code are basically the same as in the last How-To, except that the name was changed as needed, and some lines were added to comment the code. Listing 1.3 frmHowTo1_3.vb: Adding the Call to the RefreshIndividual Subroutine Private Sub btnLoadList_Click(ByVal sender As System.Object, _ Page 30 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal e As System.EventArgs) Handles btnLoadList.Click ' ' Store the text entered to limit the list box to the data adapter's parameter Me.txtCustLimit.Text ' Clear the current data in the dataset Me.dsCustomerList.Clear() ' Fill the customer list dataset Me.odaCustomerList.SelectCommand.Parameters(0).Value = _ Me.odaCustomerList.Fill(Me.dsCustomerList) ' Fill the initial entry's individual dataset RefreshIndividual() End Sub The only new line of code is the one just before the End Sub, which calls the subroutine RefreshIndividual for the first item in the newly populated list box. This subroutine first handles clearing the dataset called dsCustomerIndividual. It ensures that a customer is chosen in the list box and then places the selected item into the parameter value for odaCustomerIndividual. The dataset called dsCustomerIndividual is then filled, displaying the data in the text boxes bound to the dataset. Listing 1.4 frmHowTo1_3.vb: Refreshing the Dataset on Which the Text Boxes Are Based Private Sub RefreshIndividual() ' Clear individual customer dataset Me.dsCustomerIndividual.Clear() ' Check to see if an item was selected If lstCustomers.SelectedIndex <> -1 Then ' ' Store the selected customer ID into the parameter of the SQL data adapter Me.odaCustomerIndividual.SelectCommand.Parameters(0).Value = _ Me.lstCustomers.SelectedItem(0) ' Fill the dataset Me.odaCustomerIndividual.Fill(Me.dsCustomerIndividual) End If End Sub The only other code is required when a new item is selected in the list box. You want to refresh the text boxes with the new data. This code is on the SelectedIndexChanged event for the lstCustomers list box. Listing 1.5 frmHowTo1_3.vb: Call the RefreshIndividual Routine Page 31 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub lstCustomers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstCustomers.SelectedIndexChanged ' Fill the current list item's individual dataset RefreshIndividual() End Sub How It Works After the user types a letter into the txtCustLimit text box and clicks btnLoadList, the list box is populated with the items that match the text in the text box. After lstCustomers is populated, the user sees the details for the first item in the list box that is displayed in the text boxes. This occurs within the routine called RefreshIndividual. The selected item is used for the parameter for the data adapter called odaCustomerIndividual, then filling the dataset called dsCustomerIndividual. As the user selects new items in the list box, the data that corresponds to the selected item is displayed. Tip Always try to break your code into specific routines such as the subroutine RefreshIndividual. That way when someone tries to read the code, the code is easy to read, you don't make mistakes by typing the same code two or more times, and you only have to change the code in one place if necessary. Comments Binding text boxes to datasets saves work when switching from one record to another because you don't have to specifically load each text box with data each time. It also gets easier every time you use a data adapter and dataset in combination when manipulating data on your forms. Bound datasets are particularly useful as you edit, add, and delete data on your forms, as you will see in the following How-Tos. [ Team LiB ] Page 32 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.4 Edit and Update Data Using Bound Controls Although viewing data is fine in some situations, the real power comes in being able to edit the data in the text box and update the data in the server. In this How-To, you learn just that, using some new methods and properties from the various data controls, including autogenerated commands that create update, insert, and delete SQL statements for you. This How-To also introduces you to the BinderContext class, which is used to perform updates with bound controls. The form as created in How-To 1.4 is great if you just want to view data for various records. But what if you want to let users edit and update the data? Technique Continuing with the form you used in the previous How-Tos, you are going to add a few command buttons with code that will perform the following:  Edit. Toggle the look of the text boxes to let the user know that he can edit the data in the controls by giving the controls a sunken look.  Save. Save the changes made to the data back to the server. Then toggle the look of the text boxes back to flat so that the user knows he can't edit them.  Cancel. Toggle the text boxes back to flat so that the user knows he can't edit them anymore, but don't save the data. It is important to let users know when they can edit and when they can't. By toggling the style of the text boxes between flat and sunken and the color between gray and white, users have a definite clue that they can edit the data at certain times (see Figure 1.8). Another useful item to note about this How-To is the introduction of the BindingContext class. This class helps you work with data bound controls. Each control on a Windows form has a BindingContext object as well as BindingContext objects for any controls that are contained within that control. Each form also has a BindingContext object. BindingContext objects manage BindingManagerBase class object(s) for each control. Through the BindingContext object, you can manage editing and updating data back to the server. BindingManagerBase objects help with synchronization of datasets with controls. You are going to use the BindingContext class throughout the rest of this chapter, but only a couple of methods. Steps Open the solution for the chapter called "VB .NET How-To Chapter 1," and run the application. From the main form, click the command button with the caption "How-To 1.4." Click the Load List button. Along with the list being filled with customers whose names start with A, you will see the detail How-To fill in on the right side of the form with the first customer in the list. Click Edit. You will now be able to change the data in the text boxes. After you have changed a couple of fields, click Save. If you select another customer from the list box, select the one you changed. You will see that your changes have in fact been saved. If you click Cancel instead of Save, your changes will not be saved. Note that if you change the name of the customer, you must load the list again to see the changes in the list box. 1. Add the three command buttons to your form as described in Table 1.6 and as displayed in Figure 1.8. Page 33 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 1.6. Command Buttons to Edit, Save, and Cancel Changes to Data Object Property Setting Command Button Name Caption btnEdit &Edit btnSave &Save btnCancel &Cancel Command Button Name Caption Command Button Name Caption 2. Add the code shown in Listing 1.6 to the btnEdit Click event. Listing 1.6 frmHowTo1_4.vb: Calling the ActiveEditing Subroutine from the btnEdit Command Button Private Sub btnEdit_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnEdit.Click ' Enable the editing of the form ActivateEditing(True) End Sub This calls the routine called ActivateEditing, listed here. This code iterates through all the controls on the form and uses the TypeOf condition to check whether the current control is a text box. It also ensures that the control is not the txtCustLimit text box. If the control is a text box and the parameter called bEnable has been passed in as True, then the sunken look is given to the text box using the BorderStyle and the BackColor property is set to white. Otherwise, the BorderStyle is set to FixedSingle, which is flat, and the BackColor is set to the backcolor of the form. The Enabled property of the text box is set to whatever bEnabled is: True or False. Listing 1.7 frmHowTo1_4.vb: Toggling the Enabled Property and Look of Text Boxes Private Sub ActivateEditing(ByVal bEnable As Boolean) Dim oCurr As Object ' Loop through each of the controls on the form For Each oCurr In Me.Controls() ' Check to see if the control is a text box If TypeOf oCurr Is TextBox And oCurr.Name <> "txtCustLimit" Then Page 34 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' If so, toggle the properties If bEnable Then oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.Fixed3D oCurr.BackColor() = System.Drawing.Color.White Else oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.FixedSingle oCurr.BackColor() = Me.BackColor End If oCurr.Enabled = bEnable End If Next End Sub 3. Add the code to the Click event of the btnSave command button. This code calls a new routine called SaveRecord, which performs the actual save. The ActivateEditing is then called, passing False to disable the controls because you are finished editing. Listing 1.8 frmHowTo1_4.vb: Calling the SaveRecord Routine and Disabling the Text Boxes by Calling ActivateEditing Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click ' Save the information SaveRecord() ' Disable the text boxes ActivateEditing(False) End Sub Following is the code for the subroutine called SaveRecord. This routine calls the EndCurrentEdit method of the BindingContext class, passing in the dataset called dsCustomerIndividual, and specifying the Customers table. Then the Update method is called off the data adapter called odaCustomerIndividual, passing the same parameters. This updates the changes back to the dataset. Finally, the dataset changes are sent backto the server. Listing 1.9 frmHowTo1_4.vb: Saving the Data Back to the Server Page 35 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub SaveRecord() ' ' Use the BindingContext class to end current editing so that we can update the server. Me.BindingContext(Me.dsCustomerIndividual, "Customers").EndCurrentEdit() ' ' Perform the requested task at the dataset level using the data adapter Me.odaCustomerIndividual.Update(Me.dsCustomerIndividual, "Customers") ' By accepting the changes, the data gets sent back to the server Me.dsCustomerIndividual.AcceptChanges() End Sub Note If you haven't read about ADO.NET yet, then you might be confused about doing an update to the dataset, accepting changes, and sending the changes back to the server. ADO.NET works using disconnected data. When you create a dataset by using a data adapter, the data is actually created using XML. To see proof of this, take a look at dsCustomerIndividual.xsd, found in the Solutions Explorer. This is all performed under the covers, so the good news is that you don't have to know XML to work with datasets and ADO. More information on this can be found in Chapter 3. 4. The last task is to give you the capibility to cancel the edits. You do this by placing the following code in the Click event on btnCancel. Calling the CancelCurrentEdit method of the BindingContext object for the form, the current edits are cancelled. Next, the text boxes are disabled using the routine ActivateEditing. Listing 1.10 frmHowTo1_4.vb: Canceling Changes to Data and Disabling the Text Boxes Again Private Sub btnCancel_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCancel.Click ' Use the BindingContext class to cancel the current editing. "Customers").CancelCurrentEdit() ActivateEditing(False) Me.BindingContext(Me.dsCustomerIndividual, _ Page 37 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub How It Works When the user clicks the btnEdit button, the ActiveEditing routine alerts the user that he can edit the data in the text boxes. The text boxes are enabled. If the user then clicks the btnSave button, the data is updated to the dataset and then back to the server. If the user clicks the btnCancel button, the edits are canceled. In both cases, the ActivateEditing routine is called to disable the text boxes and let the user know that the text boxes cannot be edited. Comments This How-To showed the bare bones for editing and updating data. It presented a basic technique to get started. As you continue, you will learn methods to add and delete records, as well as handle errors. Using ADO.NET, which you use for bound controls, takes some getting used to if you have worked with other data accessing methods such as ADO and DAO. The BindingContext and BindingManagerBase objects make working with bound objects in code much more manageable. [ Tea m LiB ] Page 38 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.5 Add and Delete Records Using Bound Controls Besides editing data, adding new records and deleting records in a table are obviously important features. This How-To shows you just that, taking advantage of the BinderContext class. Besides being able to edit current records that already exist, users need to be able to add and delete records as well. How do you add and delete records using bound controls? Technique To create the Add New Record feature, you will add a button called btnAddNew that has code behind it. You will use the BindingContext object again to add a new record by using the AddNew method. A module variable will be added to the form to keep track of whether a record is being added or edited. If a new record is being added, then when the update is performed, the application needs to reload the data in the list box in case the new record's CompanyName data falls into the chosen list limit that is specified in the txtCustLimit text box. To create the Delete Record feature, you will add a button called btnDelete. This button will have code behind it that will use the RemoveAt method of the ContextBinding object to remove the record from the dataset. The data will then be posted back to the server. Steps Open the solution for the chapter called "VB .NET How-To Chapter 1," and run the application. From the main form, click on the command button labeled How-To 1.5. Click the Load List button. Click the button labeled New. Enter the text ALF for Customer ID and Alfred's Fried Foods in the Company Name. Then click the button labeled Save, and see the record you just entered added to the list. After the record has been entered, you can test the delete feature by clicking on the button named Delete. The record goes away, and the list is rebuilt. 1. Add a new command button under btnEdit, and then set the Name property to btnNew and the Caption property to &Save. 2. Add a new module-level variable called mbAddNew, which is a Boolean variable to keep track of whether you are adding a new record. This variable will be placed outside of your routines, just under the forms code. You can see this in Figure 1.9. Figure 1.9. By placing this variable just underneath Windows Form Designer Generated Code and declaring it Private, routines inside the Class can see it, but those outside cannot. Page 39 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Tip You can collapse and expand routines that you are working on within modules. This makes it handy when you are working on new routines (which can be expanded) and don't want to mess with old routines (which can be collapsed). 3. Add the following code to the Click event of the new command button btnNew. This code first sets the Boolean variable called mbAddNew to True. It then uses the AddNew method of the form's BindingContext object to add a new record to the dsCustomerIndividual dataset. Finally, the code calls the ActiveEditing routine to enable the text boxes. Listing 1.11 frmHowTo1_5.vb: Adding a New Record to the dsCustomerIndividual Dataset and Toggling Text Boxes Private Sub btnNew_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnNew.Click mbAddNew = True ' Using the BindingContext class add a new record Me.BindingContext(Me.dsCustomerIndividual, "Customers").AddNew() ActivateEditing(True) End Sub 4. Modify the Click event of the btnSave to test whether the mbAddNew flag has been set to Page 40 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html True, meaning that a new record is being added. If True, then after saving the record by calling the SaveRecord and ActivateEditing routines, the LoadList and RefreshIndividual are called to load the new record's data. Note that the SaveRecord, ActiveEditing, and RefreshIndividual routines have not changed from How-To 1.4. The mbAddNew variable is then set to False. Listing 1.12 frmHowTo1_5.vb: Saving the Changed Data, Toggling Text Boxes, and Reloading the List Box and First Record in the List Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click ' Save the information SaveRecord() ' Disable the text boxes ActivateEditing(False) If mbAddNew Then LoadList() RefreshIndividual() mbAddNew = False End If End Sub 5. Modify the Click event for the btnCancel button to reset the mbAddNew variable to False, as seen in Listing 1.13. Listing 1.13 frmHowTo1_5.vb: Canceling the Edit and Resetting the mbAddNew Variable Private Sub btnCancel_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCancel.Click ' Use the BindingContext class to cancel the current editing. Me.BindingContext(Me.dsCustomerIndividual, "Customers").CancelCurrentEdit() ActivateEditing(False) mbAddNew = False End Sub 6. Now it is time to add the delete functionality. To do this, add the following code to the Click event of the new button called btnDelete. The first line of the code you added begins by introducing a new method called RemoveAt and a new property called Position, both used with the BindingContext object. You will work from the inside out. The Position property tracks the current position in the dataset, in this case dsCustomerIndividual. The RemoveAt method marks the record that is at the position passed to it for deletion. Next, the Update method of the odaCustomerIndividual adapter is used to call the Page 41 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DELETE SQL statement command against the dataset, deleting the actual rows in the data set. The AcceptChanges method is called to send the changes to the dataset, a delete in this case, back to the server. Finally, the LoadList, RefreshIndividual, and ActivateEditing subroutines are called to refresh the list, refresh the first record in the list for the text boxes, and toggle the text boxes so that the user knows he can't edit them. Listing 1.14 frmHowTo1_5.vb: Deleting the Selected Record and Reloading the List Box Private Sub btnDelete_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDelete.Click ' Mark the row for deletion using the RemoveAt method of the BindingContext "Customers").RemoveAt(Me.BindingContext(Me.dsCustomerIndividual, "Customers").Position) ' ' Perform the requested task at the dataset level using the data adapter Me.BindingContext(Me.dsCustomerIndividual, _ odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") ' By accepting the changes, the data gets sent back to the server dsCustomerIndividual.AcceptChanges() ' Reload the list LoadList() ' Display the first record RefreshIndividual() ' Disable the text boxes ActivateEditing(False) End Sub How It Works When the user clicks the btnNew button, a flag (mbAddNew) is set to True, the dataset is set for adding a record with the AddNew method of the BindingContext, and the text boxes are enabled for editing. If the user then clicks the btnSave button, the data is updated to the dataset and then back to the server. If the user clicks the btnCancel button, the edits are canceled. In both cases, the mbAddNew variable is set to False and the ActivateEditing routine is called to disable the text boxes and let the user know that the text boxes are not available for editing. Finally, if the btnSave button was clicked and the mbAddNew was set to True, the LoadList and RefreshIndividual routines are called. When the user clicks the btnDelete button, the record is deleted from the recordset and then from the server. The list box is reloaded and the first record in the list is displayed in the text boxes. The text boxes are then disabled. Page 42 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Here you have the basic commands needed to create a full-fledged data entry form. You can add, edit, and delete information from the form. This actually takes less code than if you use Visual Basic 6.0. The BindingContext object really goes a long way to helping you work with bound data. [ Team LiB ] Page 43 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.6 Take Care of Error Handling with Bound Controls When dealing with database tasks, you are going to get runtime errors. In .NET, we call the various types of errors you can get exceptions. This How-To shows examples of what exceptions could occur and how to handle them using the Try, Catch, and Finally statements. Adding and deleting records is fine, but what happens if an error occurs? You tried to delete an existing company, and got the screen that appears in Figure 1.10. Figure 1.10. This is an unhandled error, called an exception in .NET. How do you make it so errors are handled gracefully within the application using bound controls? Technique Error handling is one of the most important aspects of working with data, between when a user is entering data and updating the server. If you don't have proper error handling, your system will, in the best situation, give an ugly error message, and in the worst, blow up and put bad data in your system. In Visual Studio .NET, errors are classes called exceptions. Many different (inherited) types of exceptions exist. Run-time exceptions can occur in just about any part of your application. They can be handled by using Try...Catch...Finally or they can be unhandled, where you will see the error in Figure 1.11. Figure 1.11. This error was thrown up from one subroutine to the one that called it. Take a look at a common way to trap exceptions shown in Listing 1.15. Listing 1.15 Standard Code for Handling Exceptions Private Sub MySub() Try ' Code to be handled here Page 44 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Catch dataException as Exception MessageBox.Show(dataException.Message) Finally ' Code that will occur regardless of if an error occurs. End Try End Sub Following are some basic points to help you when working with exceptions and Try...Catch...Finally blocks:  The name of the exception object can be whatever you want it to be. dataException was just used as an example.  Specific types of exceptions inherit from the base class of System.Exception. OleDbException is one of those classes, and you will see an example of using this class in the following steps.  You can use the Throw statement within a Catch statement to throw the exception back up to a calling subroutine.   You can use the When clause on the Catch statement to trap for specific exceptions. When multiple Catch statements are used, each one is executed unless an End Try or End Sub is placed within a Catch block, as in this How-To.  You can use multiple Catch statements to handle various possible exceptions that can occur. You will see an example of these bullets in the following steps. Steps Taking the form with which you have been working, you are going to modify it to trap exceptions when the record is being saved (either for additions or editing) and when the record is deleted. You will also add some code in the event when closing the form. 1. Modify the code in the Click event of the command button called btnSave. You will surround the SaveRecord routine call with a Try...Catch...End Try block. If an exception occurs, the Show method of the MessageBox class is called, passing the Message property of the Exception object called saveException. Next, the subroutine is exited. If no errors occur, then life goes on, and so does the subroutine. Listing 1.16 frmHowTo1_6.vb: Code Added to btnSave Click Event to Trap Save Exceptions Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click Try Page 45 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' Save the information SaveRecord() Catch saveException As Exception MessageBox.Show("The following error has occurred: " & _ saveException.Message, "Error Saving Record") Exit Sub End Try ' Disable the text boxes ActivateEditing(False) If mbAddNew Then LoadList() RefreshIndividual() mbAddNew = False End If End Sub 2. Modify the SaveRecord routine to "throw" the exception up to the btnSave_Click subroutine, or whatever happens to have called the SaveRecord routine. Following is the SaveRecord subroutine with the new Try...Catch...End Try block added, along with the Throw statement. Listing 1.17 frmHowTo1_6.vb: Pass the Exception Back Up to the Calling Routine Private Sub SaveRecord() Try ' ' Use the BindingContext class to end the current editing so that we can update the server. "Customers").EndCurrentEdit() ' ' Perform the requested task at the dataset level using the data adapter Me.BindingContext(Me.dsCustomerIndividual, _ odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") ' By accepting the changes, the data gets sent back to the server dsCustomerIndividual.AcceptChanges() Catch saveException As Exception Throw saveException End Try Page 46 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 3. Now it's time to deal with adding exception handling to the btnDelete Click event, as seen next. The Try statement is used to wrap the code that performs deletion of the data. The code then uses a Catch statement to check whether the exception that occurs is a specific OleDbException, 3621, which is an error having to do with trying to delete a record when related records exist in another table. Note that you could and in fact should assign this to a constant value. Because delException has been caught as an OleDbException, you can look at the NativeError property of the first error in the Errors collection to get the actual OleDb error number. If the error is not 3621, then the exception is trapped with the next Catch statement, and a messagebox is displayed. If errors occur, then the subroutine is exited before the final lines of code are executed. Listing 1.18 frmHowTo1_6.vb: Catching Exceptions When You're Deleting a Record Private Sub btnDelete_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDelete.Click Try ' Mark the row for deletion using the RemoveAt ' method of the BindingContext Me.BindingContext(Me.dsCustomerIndividual, "Customers").RemoveAt(Me.BindingContext(Me.dsCustomerIndividual, "Customers").Position) ' ' Perform the requested task at the dataset level using the data adapter odaCustomerIndividual.Update(dsCustomerIndividual, "Customers") ' By accepting the changes, the data gets sent back to the server dsCustomerIndividual.AcceptChanges() Catch delException As System.Data.OleDb.OleDbException _ When delException.Errors(0).NativeError = 3621 MessageBox.Show("An error occurred because of related order records.", "Error Deleting Customer", _ MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Exit Sub Catch delException As Exception MessageBox.Show(delException.Message, "Error Deleting Customer", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Exit Sub End Try ' Reload the list LoadList() Page 47 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' Display the first record RefreshIndividual() ' Disable the text boxes ActivateEditing(False) End Sub How It Works When an exception occurs within the Try...Catch...End Try block, the Catch statements are compared when a When clause is used or when the code is simply executed. If a Throw statement is used, then an execution is thrown back up a level to the Try...Catch...End Try block containing the call to the routine where the Throw statement occurred. You can see an example of this in Figure 1.11. Comments Microsoft has gone to great length to let you control how you handle exceptions in .NET with the various languages. You can be as creative as you need to by using the Try...Catch...End Try block with all the clauses available. Exceptions bring back plenty of information so that you can create pretty slick error handling. You can use exceptions to create a centralized routine that logs errors, or even one that e-mails exception information to you from your applications. [ Team LiB ] Page 48 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.7 Put the Finishing Touches on a Data Bound Form Besides handling the basics, you need to add some finishing touches to a data entry form, such as enabling/disabling controls based on whether you're on a record. This How-To shows you how to use the Enabled properties on controls to give the user more direction when using a Windows form (see Figure 1.12). Figure 1.12. You will create this complete form by How-To 1.7, with all the bells and whistles that users expect from a good data entry form. Although the majority of the major issues are taken care of for the form you created so far in the chapter, your users become confused about when to push some of the buttons. How do you get the buttons to reflect when the users can click them, and what other finishing touches might help the form? Technique An important part of user interfaces is letting the user know when he has access to certain features on the form. In this case, you will see how to do the following:  Toggle the enabled property of the btnSave, btnCancel, btnNew, and btnDelete at the appropriate moments, such as when a record is highlighted in the list box.   Add a command button to close the form. Add code to the Closing event of the form that tests whether you have made changes to the current record, and if so, whether you want to save the changes. You can see an example of particular command buttons being enabled based on the current action being performed in the form in Figure 1.13. Figure 1.13. This form allows users to access command buttons only when the functionality is available. Page 49 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Steps Continuing on with the form that you have been using, you are going to make the changes just mentioned in the previous bulleted list. 1. Start by modifying two routines already created: RefreshIndividual and ActivateEditing subroutines. Then check whether a customer has been selected in lstCustomers. If not, then the two buttons, btnEdit and btnDelete, are disabled. If a customer hasn't been selected, the two buttons are enabled, and the dsCustomerIndividual dataset control is refreshed. Listing 1.19 frmHowTo1_7.vb: Toggling the Enabled Property of the btnEdit and btnDelete Buttons Private Sub RefreshIndividual() ' Clear individual customer dataset Me.dsCustomerIndividual.Clear() If lstCustomers.SelectedIndex = -1 Then btnEdit.Enabled = False btnDelete.Enabled = False Else btnEdit.Enabled = True btnDelete.Enabled = True Me.odaCustomerIndividual.SelectCommand.Parameters(0).Value = lstCustomers.SelectedItem(0) ' Fill the dataset Me.odaCustomerIndividual.Fill(Me.dsCustomerIndividual, "Customers") End If End Sub Similarly, you will add code to the ActivateEditing subroutine to toggle the Enable Page 50 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html property of the various command buttons, depending on their purpose. Listing 1.20 shows the entire routine. Listing 1.20 frmHowTo1_7.vb: Toggling the Enabled Property of btnEdit and btnDelete Buttons Private Sub ActivateEditing(ByVal bEnable As Boolean) Dim oCurr As Object ' Loop through each of the controls on the form For Each oCurr In Me.Controls() ' Check to see if the control is a text box If TypeOf oCurr Is TextBox And oCurr.Name <> "txtCustLimit" Then ' If so, toggle the properties If bEnable Then oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.Fixed3D oCurr.BackColor() = System.Drawing.Color.White Else oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.FixedSingle oCurr.BackColor() = Me.BackColor End If oCurr.Enabled = bEnable End If Next ' Enable/Disable the appropriate buttons btnEdit.Enabled = Not bEnable btnNew.Enabled = Not bEnable btnDelete.Enabled = Not bEnable btnCancel.Enabled = bEnable btnSave.Enabled = bEnable ' Set the focus to the CustomerID text box Me.txtCustomerID.Focus() If bEnable Then Page 51 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End If End Sub The specific lines of code added are shown here: ' Enable/Disable the appropriate buttons btnEdit.Enabled = Not bEnable btnNew.Enabled = Not bEnable btnDelete.Enabled = Not bEnable btnCancel.Enabled = bEnable btnSave.Enabled = bEnable These buttons are handled as the other buttons are by taking the opposite value to which bEnable is currently set, and using it to toggle the Enabled property. Finally, if the bEnable flag is True, then focus is moved to the txtCustomerID text box using the following lines of code: ' Set the focus to the CustomerID text box If bEnable Then Me.txtCustomerID.Focus() End If End Sub 2. Add a new command button, with the properties Name and Text set to btnClose and &Close, respectively. Place the code in Listing 1.21 for the Click event. Listing 1.21 frmHowTo1_7.vb: Close the Form Private Sub btnClose_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnClose.Click Me.Close() End Sub 3. Add some code to the Closing event of the form. Listing 1.22 tests whether the btnSave button is enabled. If it is, the MessageBox method is evoked, asking the user if he wants to save changes that were made. If so, then the SaveRecord is called within a Try...Catch...End Try block. Listing 1.22 frmHowTo1_7.vb: Checking Whether the User Wants to Save a Record Before Closing Private Sub frmHowTo1_7_Closing(ByVal sender As Object, _ ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing ' ' If an edit or add has been requested, enabling the Save button, then prompt to save the record If btnSave.Enabled Then Page 52 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html If MessageBox.Show("Would you like to save the current record?", _ "Save Record?", MessageBoxButtons.YesNo) = _ DialogResult.Yes Then Try ' Save the information SaveRecord() Catch saveException As Exception If MessageBox.Show("The following error has occurred: " & saveException.Message & vbCrLf & vbCrLf & _ "Continue with closing the form?", "Error Saving Record", MessageBoxButtons.YesNo) = DialogResult.No Then e.Cancel = True End If End Try End If End If End Sub How It Works In the modifications made to the form in this How-To, many things happen depending on what is occurring. When the user clicks the btnEdit button, btnEdit, btnNew, and btnDelete are disabled, and btnCancel and btnSave are enabled. The opposite is true when btnCancel and btnSave are pressed. If bEnable is True, then the focus is moved to the txtCustomerID text box. When the txtClosed button is clicked, the application then checks whether the btnSave command button has been enabled, meaning data is being edited. If so, then the user is asked whether he wants to save the current record. If the user does, the system then saves the current information back to the server. Comments The tasks displayed in this How-To are just a few of the tasks you can do to make your forms look and feel more professional. They are also what users come to expect from database applications. Play with the form a bit more. You're sure to come up with a few more ideas. [ Team LiB ] Page 53 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.8 Bind Data to ComboBox and DataGrid Controls Sometimes you might want to use a ComboBox control instead of a ListBox control to display a list of choices. You also might want to display information in a grid style based on the item chosen in that combo box. This How-To describes how to bind data to both ComboBox and DataGrid controls. Instead of using a ListBox control to display customers, you would like to use a ComboBox control to display them. After you choose a customer, you would like to display information about the orders that belong to that customer. How do you bind data to the ComboBox and then bind the DataGrid control as well? Technique To bind both the ComboBox and the DataGrid controls, you will use the same properties and coding techniques that you have used for the ListBox control. You will first create DataAdapter and DataSet controls to which to set the DataSource properties. The DataAdapter for the DataGrid will include a parameter that will use the value selected in the ComboBox control. You will set the DataSource properties of the controls to the DataSet created. That is all you really have to set for the DataGrid control. For the ComboBox control, you will also set the ValueMember and DisplayMember properties. You will then add code to fill the DataSet control to which the DataSource property is set for the ComboBox control. Finally, you will create a subroutine to store the selected value in the ComboBox in the DataAdapter that was created for filling the DataSet on which the DataGrid control is based. After the user has selected a value in the ComboBox that contains the customers, the DataGrid control displays the orders for that customer, as can be seen in Figure 1.14. Figure 1.14. Users can display the header information for customer orders using these two controls. Steps Page 54 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You will be starting with a fresh form. 1. 2. Add a new Windows Form called frmHowTo1_8. Add the OleDbDataAdapter and DataSet controls with the properties set forth in Table 1.7 . Table 1.7. OleDataAdapter and DataSet Controls Object Property Setting OleDataAdapter Name odaCustomerList SelectCommand OleDbSelectCommand1 CommandText SELECT CustomerID, CompanyName FROM Customers dsCustomerList dsCustomerList odaOrdersForCustomer DataSet Name DataSetName OleDataAdapter Name SelectCommand OleDbSelectCommand2 CommandText SELECT OrderID, OrderDate, RequiredDate, ShippedDate FROM Orders WHERE (CustomerID = ?) ORDER BY OrderDate dsOrdersForCustomer dsOrdersForCustomer DataSet Name DataSetName 3. Tip You will want to create the OleDbDataAdapter controls using the Data Adapter Configuration Wizard, and then set the name after the DataAdapter has been created. You will want to create the DataSet controls by right-clicking on the appropriate OleDbDataAdapter and choosing Generate Dataset. If you have questions about creating these controls, reread How-To 1.1. Page 55 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Also, remember that when generating the DataSet, VS always changes the name by adding a 1 on the end and capitalizing the first letter. You might want to change it to what you really want in the properties directly. 4. Add the ComboBox and DataGrid controls, as well as the Label for the ComboBox, setting the properties as shown in Table 1.8. Table 1.8. Label, ComboBox, and DataGrid Controls Property Settings Object Property Setting Label Name Text Label1 "Customers to List Orders For:" cboCustomers dsCustomerList.Customers CompanyName CustomerID dgOrders dgOrdersForCustomer.Orders ComboBox Name DataSource DisplayMember ValueMember DataGrid Name DataSource 5. Add code shown in Listing 1.23 to the Load event of the form. This code fills the dsCustomerList DataSet control based off the select statement used in the odaCustomerList OleDbDataAdapter control. After this occurs, the RefreshOrders subroutine is called, displayed in Listing 1.24. Listing 1.23 frmHowTo1_8.vb: Filling the Dataset Used by the ComboBox Control Private Sub frmHowTo1_8_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Me.odaCustomerList.Fill(Me.dsCustomerList) RefreshOrders() End Sub Listing 1.24 frmHowTo1_8.vb: Filling the Dataset Used by the DataGrid Control, Based on the Item Selected in the ComboBox Control Private Sub RefreshOrders() Page 56 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' Clear Orders for customer dataset Me.dsOrdersForCustomer.Clear() ' Check to see if an item was selected If Me.cboCustomers.SelectedIndex <> -1 Then ' ' Store the selected customer ID into the parameter the SQL data adapter Me.odaOrdersForCustomer.SelectCommand.Parameters(0).Value = _ Me.cboCustomers.SelectedItem(0) ' Fill the dataset Me.odaOrdersForCustomer.Fill(Me.dsOrdersForCustomer) End If End Sub 6. Add the code in Listing 1.25 to the SelectedIndexChanged event of the cboCustomers ComboBox controls. Listing 1.25 frmHowTo1_8.vb: Refreshing the DataGrid Control Based on Selected Item Private Sub cboCustomers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCustomers.SelectedIndexChanged RefreshOrders() End Sub How It Works When the form is first loaded or a new item is selected in the ComboBox control, the DataGrid control is filled with order information for the selected customer. Comments As you can see from this How-To, using the ComboBox control and DataGrid controls are not much tougher than using the ListBox control. The DataGrid control does offer quite a bit more power to let you create Main/Subform type forms such as invoices. You will see an example of this in the next How-To. The DataGrid control also lets you edit data. [ Team LiB ] Page 57 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 1.9 Drill Down to Data in the DataGrid Control The DataGrid control in Visual Basic .NET is an effective way to display multiple records related to a base table, such as Customer and Orders tables. You can then drill down into individual orders to see the details. This How-To explains how to open an additional form with another DataGrid control and drill down to the order details. Although it is nice to see what orders a customer has, you would like to display more information about the orders. How do you drill down into the details of the orders displayed in the DataGrid control? Technique Using the form you started in How-To 1.8, you are going to allow the user to highlight a specific order. You are going to drill down to it by opening a new form and having that form's text boxes display order header information. Then you will use another DataGrid control to display order details. You can see this example in Figure 1.15. Figure 1.15. Drilling down to an order's detail. Besides adding a new form, you will also create a new module to be used to declare a public variable for tracking the calling form. In the previous examples, the sample form was opened by declaring a variable in the Click event of the individual Button controls on frmMain. For this How-To, the declaration of the variable pointing to that specific form has been moved to a public module. You can see the code for the Click event for btnHowTo1_ 8 and btnHowTo_9 in Listing 1.26. Listing 1.26 frmMain.vb: Opening a New Form to Display Order Information Private Sub btnHowTo1_8_Click(ByVal sender As System.Object, ByVal e As Page 58 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html System.EventArgs) _ Handles btnHowTo1_8.Click Dim frm1_8 As frmHowTo1_8 frm1_8 = New frmHowTo1_8() frm1_8.Show() End Sub Private Sub btnHowTo1_9_Click(ByVal sender As _ System.Object, ByVal e As System.EventArgs) _ Handles btnHowTo1_9.Click frm1_9a = New frmHowTo1_9a() frm1_9a.Show() End Sub Listing 1.27 presents the code for the module created, called modPublicVariables. Listing 1.27 modPublicVariables.vb: Declaring a Public Variable for a Form Module modPublicVariables Public frm1_9a As frmHowTo1_9a End Module Steps You will want to create a module as described in the "Technique" section of this How-To to open the form that you created in How-To 1.8. After you have created that module and added the Public variable declaration as shown in Listing 1.27, open the form from How-To 1.8 in Design. 1. Add a button control to the bottom-right side of the form, under the DataGrid control. Set the Name property to btnOrderDetail and the Text property to &Order Detail. 2. In the Click event of the btnOrderDetail, add the code shown in Listing 1.28. Listing 1.28 frmHowTo1_9.vb: Opening a New Form to Display Order Information Private Sub btnOrderDetail_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOrderDetail.Click Dim frm As New frmHowTo1_9b() frm.Show() End Sub 3. Create a new form and name it frmHowTo1_9b (or whatever you called it when following Listing 1.28). 4. Add some OleDataAdapters and DataSets to the form, as laid out in Table 1.9. Page 59 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 1.9. OleDataAdapter and DataSet Controls for the frmHowTo1_9b Form Object Property Setting OleDataAdapter Name odaIndividualOrder SelectCommand OleDbSelectCommand1 CommandText SELECT OrderID, CustomerID, EmployeeID, OrderDate, RequiredDate, ShippedDate, ShipVia, Freight, ShipName, ShipAddress, ShipCity, ShipRegion, ShipPostalCode, ShipCountry FROM Orders WHERE (OrderID = ?) dsIndividualOrder dsIndividualOrder odaEmployees DataSet Name DataSetName OleDataAdapter Name SelectCommand OleDbSelectCommand2 CommandText SELECT EmployeeID, RTRIM(LastName) + ', ' + RTRIM(FirstName) AS FullName FROM Employees dsEmployees dsEmployees odaOrderDetails DataSet Name DataSetName OleDataAdapter Name SelectCommand OleDbSelectCommand3 CommandText SELECT OrderID, ProductID, UnitPrice, Quantity, Discount FROM [Order Details] WHERE (OrderID = ?) dsOrderDetails DataSet Name Page 60 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataSetName 5. dsOrderDetails Add the controls that will use these data controls for data sources, found in Table 1.10. Table 1.10. Controls to Display Order Information, Including Order Details Object Property Setting Label Name Text Label1 "Order ID" Label2 "Order Date" Label3 "Employee" txtOrderID FixedSingle dsIndividualOrder - Orders .OrderID Label Name Text Label Name Text TextBox Name BorderStyle Text DateTimePicker Name DateTimePicker1 DataBindings dsIndividualOrder - Orders. - Value OrderDate Format ComboBox Name DataSource Short cboEmployees dsEmployees.Employees DisplayMember FullName ValueMember EmployeeID SelectedValue dsIndividualOrder - Orders. EmployeeID DataGrid Name DataSource dgOrderDetails DsOrderDetails.Order_Details Page 61 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. Add the code in Listing 1.29 to the Load event of the new form you have created. The first thing that this code does is fill the DataSet control use by cboEmployees. Next, using the CurrentCell.RowNumber property of the DataGrid control used on the frmHowTo1_9a form, the OrderID column is read in the specified row of the DataSet control called dsOrdersForCustomer. The OrderID, which is stored in lngOrderID, is supplied to odaIndividualOrder and odaOrderDetails. Then the OleDbDataAdapters are used to fill the datasets. Listing 1.29 frmHowTo1_9b.vb: Loading the Appropriate Datasets Private Sub frmHowTo1_9b_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim lngOrderID As Long ' Fill the dataset used for the Employee combo box. Me.odaEmployees.Fill(Me.dsEmployees) ' ' Get the OrderID from the currently select order in the DataGrid control on the calling form. lngOrderID = frm1_9a.dsOrdersForCustomer. _ Orders.Rows(frm1_9a.dgOrders.CurrentCell. _ RowNumber).Item("OrderID") ' Update the caption of the form with the order ID and customer " For " & frm1_9a.cboCustomers.Text ' Load the parameter for the order header with the InvoiceID Me.Text = "Order #" & CStr(lngOrderID) & _ Me.odaIndividualOrder.SelectCommand.Parameters(0).Value = lngOrderID ' Fill the order header dataset Me.odaIndividualOrder.Fill(Me.dsIndividualOrder) ' Load the parameter for the order detail with the InvoiceID Me.odaOrderDetails.SelectCommand.Parameters(0).Value = lngOrderID ' Fill the order detail dataset Me.odaOrderDetails.Fill(Me.DsOrderDetails) End Sub How It Works The user highlights one of the Orders in the dgOrders on the first form and then clicks the btnOrderDetail button to open the second form. The second form is used to display the details of the order. When the second form is opened, the cboEmployee ComboBox control is loaded, and the OrderID is retrieved from dsOrdersForCustomer via dgOrders, located on the first form. The DataSets controls dsIndividualOrder and dsOrderDetails are then filled. Page 62 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments This is just a start of what can be done using the DataGrid control. You will see this control used in quite a few chapters, including Chapter 3 and 4. As you can see from the way the OrderID was retrieved from the first form, it can be a little confusing when you need to get to the data programmatically. [ Team LiB ] Page 63 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 2. Creating SQL Server Database Objects From Visual Studio .NET You will learn about the following in this chapter:        Create a new SQL Server database from within Visual Studio .NET Define tables and fields Define a primary key and other indexes Define relations between tables Define defaults and constraints Create views Create stored procedures When starting out with working with databases, it's a good thing to know how to create them. This example shows how to create a SQL Server database using Visual Studio .NET and also talks about servers and security. [ Team LiB ] Page 64 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Working with Tables, Columns, and Rows The basic entity that holds data in your database is a table, which is analogous to the manila folder of customers. A table is made up of columns (also referred to as fields.) Picture a page of information that you keep on a customer. The information would have Last Name, First Name, Address, and so on. These would be columns in a table. The filled out page of information would be a row (or record) in your table, and it would be made up of columns. The database would be the filing cabinet, which would be made up of multiple tables (manila folders) with different subjects besides customers, such as invoices, parts information, and so on. Double-click on the Northwind node in the server explorer, you will then see a list of tables that are part of the database. If you open the Customers table in Design mode, you will see the various columns in the table. Then when you open your table to see the data, you will see the columns for each row or record in your table. [ Team LiB ] Page 65 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Utilizing Properties for Tables and Columns Tables and columns, like other objects in your database, have properties that allow you to control the data that is going into your tables. For example, in the Customers table, you can see the properties for the first column, called CustomerID. The extent to which you use the properties depends on what your needs are. At the table level, you also have properties that you can utilize that help you create and enforce business rules, which are discussed later in this chapter. You will create your tables by breaking down your data into logical entities. When you do so, you need to keep in mind how you break them down, and you need to break them down so that they are created in what is called normalization. SQL Server has come a long way over the years. For every version, Microsoft works hard not only to make SQL Server more powerful, but also easier to work with. This includes tools that come with the product and from other applications. Visual Studio .NET is a good example of tools for working with SQL Server from another product. If you are not familiar with databases, here's a quick overview. Databases allow you to work with data in a manner that reflects the real world on the computer. You can take a real subject, such as Customers, and store that information in tables. A file cabinet is analogous to a database. Within the file cabinet you may have your client folders. Other folders might contain information on Orders or Invoices. One of these folders could be compared to a table of customers. Within the Customers folder, you might have individual pages of information on a customer. Each page that you have on an individual customer would be a row, or a record within a table. On each page, you would have pieces of information such as Customer Name, Address, Phone, and so on. These would be fields, or columns, within each row. In a database, you will also have objects that allow you to query information within tables and update information. In SQL Server, you will use Views, Stored Procedures, and Functions to view and update data within the database. To use these objects, you need to be able to create them. To create a database along with its tables in SQL Server, you can use code or tools that came with SQL, such as the Enterprise Manager, if you have installed one of the versions that include these tools. Fortunately, you can use tools that are built within Visual Studio .NET to create and modify your databases. The primary tool you will use is called the Server Explorer, as shown in Figure 2.1. Figure 2.1. From the Server Explorer within Visual Studio .NET, you can perform most of the tasks that are necessary to maintain a database. Page 66 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Page 67 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.1 Create a New SQL Server Database from Within Visual Studio .NET Before working with a database, you have to be able to create it. Although you could use code to do this, you would rather do it right from Visual Studio. How do you create a new SQL Server database from within VS .NET? Technique As mentioned in the Introduction of this chapter, databases are basically file cabinets in computers. That sounds pretty simplistic, but if you take the information that you store in your file cabinets and transfer it over to the computer, you will end up with the same elements. You can physically create a new SQL Server database in several ways:   Use SQL Server's Enterprise Manager to create the database. Programmatically create the database. You can do this by using T-SQL and SQL-DMO, which are discussed in Chapters 6, "Creating Transact-SQL Commands," and 7, "Performing Common Database Tasks Using SQL-DMO," respectively.  Use a menu in the Server Explorer of Visual Studio .NET to perform this task. You will use the last option to complete the task presented in this How-To. Steps To get started with this How-To, leave Visual Studio at the Start Page when you open it. Then place the cursor on the Server Explorer icon on the left side of the screen. Note The way that the Server Explorer and toolbox icons are laid out on the side of the screen varies according to how you set the Profile option in the My Profile settings on the Start Page either Visual Studio Developer or Visual Basic Developer. After the Server Explorer has expanded, click on the plus symbol next to the Servers node. Then you can follow down the tree by clicking on your computer's name (SHADRACH2 in Figure 2.1) and then SQL Servers. Clicking on the name of the computer again, you will see the list of current databases that are set up by default in the Microsoft SQL Server Desktop Edition (MSDE). Although doing this was not necessary to create a new database, it does give you an idea of where you can see various databases in your system. Now you will learn how to create a database in VS .NET. 1. You can open the Create Database dialog box from within the Server Explorer in two ways. The first way is to right-click on the Data Connections node and choose Create New SQL Server Database. The second way is to right-click on the SQL Server instance to which you want to add the database in this case, SHADRACH2 and then choose New Database. Although both methods open the Create Database dialog box, the second method fills in the server name for you. 2. Fill in the name of the database you want to create in this case, Chapter2. Page 68 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Choose the type of security that you want to use with this database. If your network is strictly a Windows 2000 network, you can leave this as the default User Windows NT Integrated Security; otherwise, choose the option. Your Create Database dialog box should look like Figure 2.2. Figure 2.2. This is all the information you need to create a new database. 4. Click OK to complete the dialog box and create the new database. How It Works Now you when you click on the plus sign for the new database, you will see branches in the tree view of the Server Explorer for the different database objects, described in this chapter's introduction. Comments The Microsoft Visual Studio and SQL Server teams have gone to a lot of effort to make VS .NET the only design tool you need to use to create databases and their objects. Sometimes you will need to perform tasks that are beyond what you can accomplish in the Server Explorer, but this chapter will stick to VS .NET. Now it's time to see how to create some of the objects that actually make a database useful. [ Team LiB ] Page 69 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.2 Define Tables and Fields A SQL Server database doesn't do much good unless you have tables in it. This tutorial not only gives you information on how to create tables and fields, but also teaches you how to name them and what to look out for when creating them. Databases by themselves don't do much for you, but you need to be able to store data in them at the very least. To do this, you need to be able to create tables, which are made up of fields. How do you go about defining tables and fields in VS .NET? Technique Using the Server Explorer and accessing the Table designer, you are going to create a table called tblCustomers in the database that you created in the previous How-To. You will then add columns to the database that will store various pieces of information having to do with individual customers. Last, you will create another table called tblPhones and also create the necessary columns that will contain information about phone information for your customers. Steps After Visual Studio .NET is opened, expand the Server Explorer and locate your new database called Chapter2, created in How-To 2.1. Click on the plus sign by the database names so that the database object categories are listed. 1. Right-click on the Tables node under the Chapter2 database and choose New Table. You will then be presented with the Table Designer. Now you are ready to add the columns. 2. To add a column, you need to set four immediate properties: o Column Name. This is the name of the column. Don't use spaces or special characters, but do use proper case, and make sure that the name you give the column makes sense for what it contains. For instance, if the column is for the last name of a customer, put LastName for the Name property of the column. o Data Type. Depending on the type of data that will be entered into the column, this will be one of the many valid data types for SQL Server, shown here in Table 2.1. Table 2.1. SQL Server Data Types Data Type Description Integer (whole number) data from up6 2 63 63 bigint ( 9,223,372,036,854,775,808) through 2 \ 1\up6 (9,223,372,036,854,775,807). 2^31 ( int Integer (whole number) data from 2,147,483,648) through 2 (2,147,483,647). 31 1 smallint Integer data from 2 15 15 ( 32,768) through 2 1 (32,767). Page 70 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html tinyint bit decimal Integer data from 0 through 255. Integer data with either a 1 or 0 value. Fixed precision and scale numeric data from 10 38 + 1 through 10 38 1. numeric money Functionally equivalent to decimal. Monetary data values from 2 63 ( 63 922,337,203,685,477.5808) through 2 1 (+922,337,203,685,477.5807), with accuracy to a ten-thousandth of a monetary unit. smallmoney Monetary data values from 214,748.3648 through +214,748.3647, with accuracy to a ten-thousandth of a monetary unit. Floating precision number data from 1.79E + 308 through 1.79E + 308. Floating precision number data from 3.40E + 38 through 3.40E + 38. Date and time data from January 1, 1753, through December 31, 9999, with an accuracy of three-hundredths of a second, or 3.33 milliseconds. Date and time data from January 1, 1900, through June 6, 2079, with an accuracy of one minute. Fixed-length non-Unicode character data with a maximum length of 8,000 characters. Variable-length non-Unicode data with a maximum length of 8,000 characters. Variable-length non-Unicode data with a maximum length of 2 1 (2,147,483,647) characters. 31 float real datetime smalldatetime char varchar text nchar Fixed-length Unicode data with a maximum length of 4,000 characters. Page 71 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html nvarchar ntext Variable-length Unicode data with a maximum length of 4,000 characters. Variable-length Unicode data with a maximum length of 2 1 (1,073,741,823) characters. 30 binary Varbinary image Fixed-length binary data with a maximum length of 8,000 bytes. Variable-length binary data with a maximum length of 8,000 bytes. Variable-length binary data with a maximum length of 2 (2,147,483,647) bytes. 31 1 cursor sql_variant A reference to a cursor. A data type that stores values of various SQL Server-supported data types, except text, ntext, timestamp, and sql_variant. A special data type that stores a result set for later processing. A database-wide unique number that is updated every time a row is updated. table timestamp uniqueidentifier A globally unique identifier (GUID). o Tip Unicode is a character-encoding standard that uses 16-bit code values. This standard is used worldwide to represent all the characters that are used in modern computing. Traditional character sets are the previous character-encoding standards such as the Windows ANSI character set that use 8-bit code values or combinations of 8-bit values to represent the characters used in a specific language or geographical region. It is recommended that you use Unicode data types nchar, nvarchar, and ntext rather than their non-Unicode counterparts. Page 72 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Also, use the variant length type data types whenever possible. Doing so will save disk space and save you from having to trim your values when you want to display the data in the fields. o Length. This varies depending on which data type you choose. For text data types, this will be the maximum length you expect to be entered into the column. o Allow Nulls. This specifies whether you will allow null values to be saved in the record for the column. This means that the user doesn't have to enter a value at all. This is sometimes a bad idea, such as when you have specific data that has to be entered, like Social Security Numbers. For the first few columns in the table, enter the following data. You can see how the table will look in Figure 2.3. Figure 2.3. Fields for your first table. Column Name LastName FirstName Address City State ZipCode Data Type Length 50 50 50 50 2 9 Allow Nulls Unchecked Unchecked Checked Checked Checked Checked nvarchar nvarchar nvarchar nvarchar nvarchar nvarchar Page 73 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BirthDate MailingList EstimatedSales 3. datetime bit money 8 1 8 Checked Checked Checked Save the table by clicking on the X in the top-right corner of the Table Designer, and name the table tblCustomers when prompted. After you click the X, you are asked if you want to save the table. Then you are prompted for the name to save the table as. How It Works By entering the information in the various properties for each column, you are specifying how you want the data in your database to be treated. Generally, your users won't create tables; you will create the tables for the users, and they will fill the data into the tables using your applications. When the user fills in the data, the application and SQL Server control what type of data goes into the table, starting with what the data type of the data is and what the allowed length is. The Allow Nulls property determines whether the user even has to enter data. Comments Creating the tables, made up of columns and rows, is the basis for the database's purpose: storing information. Making sure that you use logical, descriptive names for columns, along with data types that help control how the data gets entered into the database, is key to a successful database. Plan out your tables ahead of time, examining each real-world object, and transfer those properties to the columns that make up the tables that represent your objects. [ Team LiB ] Page 74 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.3 Define a Primary Key and Other Indexes Indexes are used to improve performance when querying data, such as searching on fields and sorting information. The primary key is an index that ensures that you have at least one unique value in each record, such as a Customer ID. This How-To discusses what the best candidates are for primary keys, as well as how to create them and other indexes. You have created a base table and have even entered data into it. How do you make sure that you have a way of finding specific records? LastName and FirstName fields won't work because you can have duplicates of those. You also want to make sure that when you search on fields, you get the best possible performance from SQL Server. Indexes can be created to help performance. How do you define a primary key field to make sure that you have unique records and can create other indexes as well? Technique Within the Server Explorer, you can use a field, such as a Social Security Number, and make that into a primary key field. By making a field the primary key field, you will need to make that field unique and prohibit null values there. The alternative to a current unique field is to create a field that is automatically incremented, called an identity field. This identity field can also be set as the primary key field, again so that the record is made unique. The primary key field will also be indexed. Besides creating the special primary key field, you can create indexes that perform two main functions:  Performance. Used to increase performance when the column is used for search criteria and sorting and when you're loading ranges of records.  Constraints. This is one of the jobs that the primary key field performs data that users can put into the table. constraining the Note When creating indexes for performance purposes only, take care that you don't go overboard. Although indexes help performance when searching and sorting, they can hurt performance when adding and updating data. This is mainly true when importing or adding large amounts of data. The other point is that when the table is small, you can over-index as well. While you're in the table designer, you can get to Indexes, located on the Property Pages dialog box, by choosing Indexes/Keys from the View menu. You can see the Property Pages dialog box in Figure 2.4. Figure 2.4. You can create all the necessary indexes using this dialog box. Page 75 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Within Indexes, you have some options to specify, such as whether you would like to have the values in the index be unique You will want to have tables where you have a lot of data and you will be deleting or updating large amounts of records at a time. You also will use a field in a range situation, such as using BETWEEN, >, >=, <, and <= for operators. Steps Using the Server Explorer, open the Chapter2 database and right-click on the tblCustomers that you created in the last How-To. Then select Design Table from the right-click menu. 1. Place the cursor in the first row, if it isn't already there. Click the right mouse button, and choose Insert Column from the menu. Next, fill in the properties of the field as follows: Property Value Column Name DataType Length Allow Nulls Identity CustomerID int 4 Unchecked Yes Page 76 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 2. When you specify that you want to make this an identity field, the next two properties will be used. The first, Identity Seed, is what the column's values will be started at. The next property, Identity Increment, will be how records that are added will be incremented. 3. Right-click in the Column Name property of the CustomerID column, and then choose Set Primary Key from the menu. You have now set the CustomerID to be the primary key, and the screen should look similar to Figure 2.5. The index that you just created when you specified CustomerID to be the primary key falls into the constraint category of indexes. Figure 2.5. You need to have one primary key field per table. 4. To create other indexes that will help performance, choose Indexes/Keys from the View menu to open the Property Pages dialog box. 5. On the Indexes page, click the New button, and then fill in the following properties to add an index for the LastName field: Index Name with "IX_LastName" and Column Name with "LastName." Tip If you sort on multiple columns such as LastName and FirstName together, which is quite common, you could add the FirstName column underneath the LastName column in the last step. This is called a compound index. How It Works When you create tables, you create your primary key columns and indexes at the same time. You can come up with indexes at a later date as well. Page 77 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Be sure to create a primary key column for each of your tables, and use identity columns for primary columns whenever possible. SQL Server will take advantage of indexes you have created, but just be careful not to over-index. Remember to examine what columns you will be sorting and querying on. With particularly large tables, indexes become more important than ever. [ Team LiB ] Page 78 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.4 Define Relations Between Tables Relationships define how your information needs to "relate" between tables in your database. For example, perhaps you have tables in your database called Customers, Orders, and Order Details as the sample Northwind database does. You would want to create relationships between these tables to make sure that data integrity is maintained as users enter data into the database. Taking this further, you need to make sure that each invoice has an existing customer for every invoice. This is called referential integrity. This How-To shows you how to create relationships as well how to view the relationships by using database diagrams. You have created a couple of tables where one relies on another to have data in it. In database terms, they are related. How do you create relationships between tables? Technique Referential integrity tells the database how tables are to relate to one another. You can use referential integrity to help control what data goes in each of tables, based on data in other tables. To maintain referential integrity, you need to create relationships between tables. An example of referential integrity from Northwind is that to have a record entered into the Orders table, you have to have a record entered into the Customers table. The two tables are related by the CustomerID field, which is found in both two tables. In the Customer table, the CustomerID field is the primary key, which means that it will be unique. In the Orders table, the CustomerID field is a foreign key, which means it points to a primary key in another table. You can see this displayed in the database diagram in Figure 2.6. Figure 2.6. The column CustomerID is the primary key in Customers and a foreign key in Orders. Note Database diagrams are the main graphical way to view, edit, and print Page 79 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html relationships. You will find them listed under the database you are working on in the Server Explorer. You can also get the Property Pages for tables from this dialog box and perform the majority of work with regard to interaction between tables, other than structure changes on tables. Another purpose of referential integrity and relations is that you also can specify to do the following:  Prohibit a parent record (from table Customers, for example) from being deleted or the key field from being edited if a record exists in the child records (Orders).  If the column relating the tables is updateable, have the system allow the key column to be updated in the parent record, and have the child records reflect the change in the key columns. This is called cascade updates.  Have the child records be deleted if the parent record is deleted. This is called cascade deletes. Three different types of relationships exist when you're creating the relations between tables:  One-to-many. Used when you have one record in the parent table, with many records in the child table. The Customers/Orders relationship that is displayed in Figure 2.6 is an example of this type of relationship. This is the most common type of relationship. If you look at the join line between the tables in Figure 2.6, you will see a key on the Customers end. This represents the one side, and the infinity symbol by the Orders table represents the many side.  One-to-one. One record in the parent table will have one related record in the child table. An example of this could be if you had private information for customers that you wanted to keep in a separate table. These two tables would have the same primary key column. This relation type is not used often because developers can use views to limit the data to which users have access.  Many-to-many. Records in the parent table can have many related records in the child table, and records in the child table can belong to many records in the parent table. An example of this can also be found in the Northwind database. Customers can have demographics tracked for them. Customers can have many demographic types, and demographic types can be assigned to many customers. This relationship is displayed in Figure 2.7. Figure 2.7. The Customers, CustomerCustomerDemo, and CustomerDemographics table make up this many-to-many relationship. Page 80 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Steps Using the Server Explorer, expand the Chapter2 database to see how to create a relationship. It helps to have more than one table. Because you have already created the table called tblCustomers, create the new table called tblCustomerPhones, with the following columns. Column Name PhoneID CustomerID PhoneType PhoneNumber Data Type Length 4 4 50 10 Allow Nulls Unchecked Unchecked Unchecked Unchecked Identity Yes No No No int int nvarchar nvarchar Set the PhoneID as the primary key and save the table as tblCustomerPhones. This table will contain the various phone numbers and types that an individual customer can have. This is an easy way to check out how to create a one-to-many relationship. 1. Right-click on Database Diagrams in the Chapter2 database tree in the Server Explorer. Choose New Diagram from the menu. The Add Table dialog box will appear. 2. Hold down the Shift Key and select both tblCustomers and tblCustomerPhones. Click the Add button to add the tables to the diagram, and then click the Close button. You will now see the two tables in the new database diagram. 3. Place the cursor on the primary key symbol in the CustomerID column of tblCustomers. Hold down the left mouse button and drag and drop the cursor over to the CustomerID column in tblCustomerPhones. The Create Relationships dialog box will be displayed, with the pertinent information filled in for you. Page 81 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Select the Cascade Delete Related Records; that way, when a customer is deleted, the phone records that have been assigned will also be removed. You can see the final relationship in Figure 2.8. Click OK to accept this relationship. Figure 2.8. You have complete control over relationships from this dialog box. How It Works Creating proper relationships in your database controls how good your data is going to be. The old term "Garbage In, Garbage Out" has meaning in this case. When a user adds information to tables that have relationships set up, he has to enter the data in a certain order. In this case, a user needs to add customers before adding phone information. If customers are deleted, then the phones that have been assigned to them will be deleted as well. Comments You will set up your forms in a logical manner based on the way that relationships are set up. For instance, a good way to set up adding your phone numbers to the form would be to use the grid control to display your many phones for one customer. Another way to enhance this example would be to add another table to hold the phone types and then to link this new table to tblCustomerPhones via a link called PhoneTypeID. For more examples of relationships, check out the tables and their relationships in Northwind. Create a database diagram, add a table in which you are interested, and then view the related tables. [ Team LiB ] Page 82 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.5 Define Defaults and Constraints One of the main concepts to keep in mind when you're creating databases is that you need to provide a means to keep garbage (bad data) out of your tables. Default values make sure that each new record begins with valid data. An example of this is if you want to make sure that a date is entered for the order date of an invoice. You could set up a default value of today's date for new records. Constraints allow you to specify what business rules you want to use with your tables, such as if you want to allow dates that are entered into the Order Date field to come after today's date. This How-To explains how to use defaults and constraints to their full potential and how to create them in Visual Studio .NET. You have started down the path of handling your business rules by creating tables and setting the data types of the columns in the tables. You have even set up relationships between tables. Now you want to make life easier for your users and suggest what values they could use, and more importantly, what values are acceptable. How do you do this by defining defaults and constraints? Technique By using default values, you can guide your users and save them time. For example, perhaps you have a mailing list application, and the user is entering addresses. If the majority of the entries are from Washington (or WA), then you could set the default property of the State field to be WA. Check constraints, not to be confused with the constraint type of index, allow you to create validation clauses that can control data that goes into the tables. An example of this would be if you didn't want someone from California (CA) entered into the addresses table from the last paragraph. You could then enter a constraint check that would read something like State <> 'CA'. Note The rest of this chapter will use the Northwind database because it has a great structure that makes it easy to show how to use necessary techniques. For this How-To, in Northwind's Orders table, you are going to add a default value to the OrderDate column and a check constraint that validates the ShipDate to make sure it occurs on or after the OrderDate. Steps Using the Server Explorer, expand the tables branch in the Northwind database, right-click on the Orders table, and choose Design Table. 1. 2. Place the cursor in the OrderDate column. Type GetDate() in the Default Value property. The GetDate() function returns the current system date and time. This squares away the default value. 3. To enter the check constraint, open the Property Pages dialog box by right-clicking on the Page 83 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html column and choosing Check Contraints from the menu. 4. 5. Click New on the Property Page dialog box. Enter ([ShippedDate] >= [OrderDate]) into the Constraint Expression. You can see the completed constraint in Figure 2.9. Notice that you can also specify when the constraint will be checked by selecting the options located at the bottom of the Check Constraints page. Figure 2.9. Constraints can be used to verify that data falls within business rules that you specify. 6. Click OK to accept the new constraint. How It Works When a new record is saved to the Orders table, if no OrderDate is added, then the GetDate() will add the system date. After that, the constraint that was added will check to see that the ShippedDate entered falls on or after the OrderDate. If this is the case, then an error message will be displayed. Comments Default values make users' lives easier when they can be used. You can also use default values so that users will be less tempted to leave values blank, or NULL. Check constraints allow you to further control how data is entered into your database. They can be Page 84 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html used both when modifying data and when adding new records. Be sure to set up what you need for constraints when you are creating the database. [ Team LiB ] Page 85 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.6 Create Views After you figure out you want to use a view, the trick is to create it by using the designer. This How-To explains how to do this from within Visual Studio .NET, including specifying sort order and criteria. Now that you have your tables created, with relationships in place, you can add data by double-clicking the table name in the Server Explorer. I also know how to bind forms and controls to data using data binding from the last chapter. How do you create views, using VS .NET? Technique Within SQL Server, you can view and manipulate data using one of three ways:  Views. These allow you to display different views of your data, including joining tables, sorting (SQL Server 200x), and using criteria. Views are limited to using the SELECT statement, and they can be used as the base for updating as well displaying data. Views are great when you need to filter your data but want to be able to update like you would a single table.  Stored procedures. Perform bulk operations such as updating, inserting, and deleting records. You can also create select queries that can be sorted. Another difference from Views is that you can use multiple SQL and control-of-flow statements within a stored procedure. You can also use parameters with stored procedures.  User-defined functions. User-defined functions are one of three types: Scalar, Table, and In-Line. These types combine the best features of views and stored procedures into a single query that you can nest, pass parameters to, sort, and return values. You can find more on stored procedures in How-To 2.7. When you want to have various views of your data that you will want to use throughout your application(s), you can create views to do so. You can then use the view to populate forms, controls, and reports. Note In versions of SQL Server prior to 2000, use of views was frowned upon because of performance and sorting limitations, among other reasons. This has changed with 2000, where views are more flexible and offer better performance. Within Visual Studio .NET, you can create, update, and delete SQL Server views all from within the Server Explorer, within the desired database. To work with views, you will use the Views Designer. For new views, you will choose New View while right-clicking on the Views node in the database. If you're editing, choose Design View while right-clicking on the desired view. You will then be taken into the View Designer, as shown in Figure 2.10, with the view called Current Product List. Figure 2.10. Using the View Designer, you can see the tables you want to include, the fields you are using, the SQL Statement created, and even the data that will be returned. Page 86 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html As you can see from Figure 2.9, the View Designer has the four main areas mentioned:  Diagram pane. This area allows you to display the table or tables(s) that you will be using in your view. This could also contain the following: other views, user-defined functions, sub queries (in FROM clause, and linked views. You will also see check boxes (or other objects) flowing down the left side of the tables. These allow you to choose fields that you want to include. You can also see some other icons along the right side of the tables, when grouping and sorting fields or when using criteria. You will see examples of these if you look through the existing views in Northwind. You can also join tables so that you can view data using multiple record sources.  Grid Pane. This is where you will specify how you want individual columns to be handled within the view. The following table describes each property: Column Description Column Display of either the name of a data column used for the query or the expression for a computed column. The name you want to use in the result set. This allows you to either rename an existing column or name a new computed column. You might want to rename an existing column if you have the same column used in two different tables. The name of the table where the column is from. Whether to display the column in the results set. Whether you want to sort the column in ascending or descending order. If you don't want to sort on the column, leave it blank. Here you will specify where in the sorted columns you want to include this column. You can place a number that corresponds with the column order that Alias Table Output Sort Type Sort Order Page 87 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html you want this column included in. Group By This is where you specify that you want to use the current column for aggregating information. To get this column to show, you need to choose Group By from the Query menu. Besides Grouping data on this column, you can also specify functions such as Min, Max, Count, and more. This column allows you to specify to which value you would like to compare the column to narrow down and return specific records. If you specify values in multiple columns, you will create a Boolean (AND) expression. Placing values in these columns will cause Boolean (OR) expressions to be created . Criteria Or  SQL Pane. You will see the SQL Select statement that is created by filling in the two previous panes mentioned.  Results Pane. As the title suggests, this pane will display the results of the view created when you click the Run Query toolbar button, which is the exclamation. Steps To learn how to create a view in Visual Studio .NET, you will create a view that displays all the orders for a given date, including the owners of each of the orders. You will also have the view sorted by CompanyName, then OrderID. Open the Server Explorer and expand the Northwind database. 1. Right-click on the icon on the Views node and select New View from the menu. The Add Table dialog box will then be opened. From the menu, you will select the tables, views, or functions that you want to include in the view. 2. Select Customers. Then, holding down the Ctrl key, select the Orders table. Click Add and then click Close. The tables will then be dropped into the Diagram pane, and you will be presented with the View Designer. One thing to notice is the symbol shown between the two tables, displayed in Figure 2.11. The symbol chosen by default in this case represents an inner join. An inner join is when values in the first table must match values from the second table, using the join column which, in this case, is CustomerID. Figure 2.11. Using this menu, you can specify how you want the tables to be joined. Page 88 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You can see the symbols for the other two types of joins displayed in the right-click menu. These types of joins include Left Outer Join (Select All Rows From Customers) and Right Outer Join (Select All Rows From Orders.) Using the various types of joins, you can alter the data results that are returned. 3. Place checkmarks in the CompanyName column, from the Customers table, and then the OrderID and OrderDate columns, located in the Orders table. When you place the checkmark in the columns, you will see both the Grid pane and the SQL pane fill out, provided you have them showing. 4. Next, type the expression = '7/19/1996' into the Criteria column of OrderDate, located in the Grid pane. If you just type the date, VS will place the other values around it. You have now added criteria. Only those orders with this date will be returned. 5. Pick Ascending for the Sort Type of the CompanyName and OrderID columns. Notice that Sort Order will be filled in automatically, depending on the order in which you pick the Sort Type. How It Works When you click on the Run Query command, which is an icon on the toolbar, you will see two records displayed in the Results pane. Comments After a view has been created, you can use it in various ways throughout your applications. In the next chapter, you will see examples of using views with ADO.NET to populate various controls. You can also use view within views, store procedures, and user-defined functions. This is handy when you have a set of results that you want to use consistently in your applications and they rely on more than one table. [ Team LiB ] Page 89 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 2.7 Create Stored Procedures Stored procedures allow you to perform bulk operations on records, such as updating, inserting, and deleting data as needed. This tutorial shows you how to create stored procedures as well as how to test them from within the Server Explorer. Viewing data is great, but you need to perform bulk operations such as adding, updating, and deleting records. You know that you will be using a stored procedure to perform these tasks, and you will be using them more than once in your application. How do you create stored procedures from VS? Technique Stored procedures are the way to go when you want add, delete, or update records or when you want to use a parameter. When you have a task that requires multiple actions, including temporary tables, stored procedures give you this ability. Stored procedures are powerful to use and easy to create. Note To create stored procedures, you will use what is called Transact-SQL (T-SQL). Although this chapter will present some simple commands to show the interface used to create stored procedures from VS .NET, Chapter 6, "Creating Transact-SQL Commands," goes into more detail on the commands of the language. As with views, you will use a designer within Visual Studio. Unlike the Views designer, the stored procedure designer is not visual initially, but more text oriented. However, you can pull up a visual designer after you are in the text designer. When you're creating a new stored procedure, you will right-click on the Stored Procedures node in the database to which you want to add the stored procedure, and then you will choose New Stored Procedure. To edit existing stored procedures, you will highlight the stored procedure, right-click, and choose Edit Stored Procedure. After the stored procedure is open, you will see a select statement or a number of T-SQL statements. If it is a new stored procedure, you can right-click and choose Insert SQL. You will be taken to the Query Builder, which happens to look like the View designer. If it is an existing stored procedure, you can place the cursor within a block of SQL code, which is outlined with a blue line, and choose Design SQL Block from the right-click menu, as shown in Figure 2.12. Figure 2.12. You can also set break points in your stored procedures using this menu. Page 90 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You will then see the SQL block displayed once again in the Query Builder. When specifying parameters that can be used as criteria in stored procedures, you will use the @ symbol in front of the parameter name, and declare them at the top of your stored procedure. Again, you can see this in Figure 2.12. Steps For this How-To, you are going to create a simple Select statement with a parameter, listing customers for a given city. If you're not already there, open the Server Explorer and expand the Northwind database. 1. Right-click on the Stored Procedures node, and then choose New Stored Procedure. You will be taken into a new page that is a template for stored procedure text. You will see the following listed: 2. 3. 4. 5. 6. 7. 8. 9. 11. */ /* SET NOCOUNT ON */ 10. AS 12. RETURN 13. Replace all the text displayed with the following: 14. 15. CREATE PROCEDURE dbo.spListCustomersForCountry 16. @parCountry char ) CREATE PROCEDURE dbo.StoredProcedure1 /* ( @parameter1 datatype = default value, @parameter2 datatype OUTPUT Page 91 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 17. AS 18. 19. Select * From Customers where Country = @parCountry RETURN With this, you can see the use of the parameter. 20. Save the stored procedure. How It Works To test the stored procedure that you just created, you can right-click on the block of code and choose Design SQL Block from the menu. You can then click on the Run Query toolbar button and fill in the parCity parameter with USA when the dialog box is presented. You will then see the information displayed in the Results pane. You will see examples of using stored procedures in the next chapter, which discusses using ADO.NET with SQL Server objects. Comments Although you can create stored procedures on-the-fly and not save them in the database, it is sometimes necessary and desirable to save them permanently so that you can use the same code in different places in your application. [ Team LiB ] Page 92 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 3. Viewing Data With ADO.NET In this chapter you will     Retrieve data using the DataReader object Retrieve results from SQL Server by using the DataTable object Locate records with the DataTable object Filter and sort records by using the DataView object ActiveX Data Objects (ADO) was introduced a few years ago as a solution to accessing data that can be found in various forms, not only over a local area network (LAN), but over the Internet as well. ADO was the new generation of data access that replaced Remote Data Objects (RDO) and Data Access Objects (DAO), originally created for the JET database engine. JET was originally created for Microsoft Access, and was later used as a choice of databases for small- and medium-sized single- and two-tier database solutions. Then along came ADO.NET. [ Team LiB ] Page 93 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Differences Between ADO and ADO.NET ADO and ADO.NET are different in several ways:  ADO works with connected data. This means that when you access data, such as viewing and updating data, it is real-time, with a connection being used all the time. This is barring, of course, you programming special routines to pull all your data into temporary tables. ADO.NET uses data in a disconnected fashion. When you access data, ADO.NET makes a copy of the data using XML. ADO.NET only holds the connection open long enough to either pull down the data or to make any requested updates. This makes ADO.NET efficient to use for Web applications. It's also decent for desktop applications.  ADO has one main object that is used to reference data, called the Recordset object. This object basically gives you a single table view of your data, although you can join tables to create a new set of records. With ADO.NET, you have various objects that allow you to access data in various ways. The DataSet object will actually allow you to store the relational model of your database. This allows you to pull up customers and their orders, accessing/updating the data in each related table individually.  ADO allows you to create client-side cursors only, whereas ADO.NET gives you the choice of either using client-side or server-side cursors. In ADO.NET, classes actually handle the work of cursors. This allows the developer to decide which is best. For Internet development, this is crucial in creating efficient applications.  Whereas ADO allows you to persist records in XML format, ADO.NET allows you to manipulate your data using XML as the primary means. This is nice when you are working with other business applications and also helps when you are working with firewalls because data is passed as HTML and XML. [ Team LiB ] Page 94 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Objects That Are Found in ADO.NET As mentioned previously, the main object that is used with ADO.NET is the DataSet object. You can see the DataSet object and its properties, methods, and additional objects in Figure 3.1. Figure 3.1. ADO.NET has several more objects than ADO does. Take a look at Table 3.1 to see a brief description of some of the objects that you will be using during this How-To. Table 3.1. ADO.NET Data Objects That Are Used to Manipulate Data Object Purpose This object is used in conjunction with the other data controls, storing the results that are returned by commands and the data adapters. Unlike the recordset from ADO and DAO, the data set actually brings back a hierarchical view of the data. Using properties and collections in the DataSet object, you can get overall relations, individual tables, rows, and columns. DataSet DataTable One of the objects off of the data set, the DataTable object enables you to manipulate an individual table's worth of data. The data table is similar to the recordset object that is found in ADO. Page 95 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataView Using this object, you can filter and sort your data, keeping various views of the data. Each data table has a default view, which is the starting data view that can be modified and stored in a separate data view. This object enables you to manipulate the rows of data in your data tables. This can be thought of as a cache of data that you can manipulate by adding, deleting, and modifying records. You can then accept the changes back to the recordset, where you will then run SQL statements to update data back at the server. DataRow DataColumn As the name suggests, you can get information at the column level by using the DataColumn object. You can get schema information as well as data using this object. For example, if you want to create a list box of names of fields, you could iterate through the DataColumn collection off a data row and retrieve all the names of the fields. PrimaryKey This object allows you to specify a primary key for a data table. That way, when you use the Find method of the data table, it knows which column to use . .NET also provides classes, called data providers, to work with ADO.NET objects to provide access to data. You can see some of those objects in Figure 3.2. Figure 3.2. You can use either OleDb classes or SQLClient classes for better performance. Note Your Visual Studio .NET applications are made up of one or more assemblies. Each assembly contains one or more Namespaces. Namespaces are then made up of one or more classes (objects). Therefore, the Namespace for your OleDb objects is System.Data.OleDb. You can find these objects using the Object browser. In Table 3.2, you can see a brief description of some of the objects that you will be using during this How-To. Page 96 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 3.2. .NET Data Provider Classes That Are Used to Manipulate Data Object Purpose Similar to the ADO Command object, this allows you to execute stored procedures in code. Unlike the ADO version, however, you can create a DataReader object using the ExecuteReader method. Command Connection This object opens a connection to the server and database with which you want to work. Unlike the ADO Connection object, the way that the connection remains open depends on the object with which you are working, such as a DataReader or DataSet object. DataAdapter A real workhorse, the DataAdapter object allows you to create SQL statements and fill datasets with the data. It also creates other necessary action queries, such as Insert, Update, and Delete ADO.NET command objects. DataReader This object creates a read-only, forward-only stream of data that allows you to quickly populate controls, such as ListBox and ComboBox controls. This object allows you to specify the parameter (or parameters if you use more than one) that DataAdapter objects can specify and use. Parameter Tip Chapter 1, "Developing Windows Forms Using Bound Controls," mentioned that the OleDb data controls are the ones that you will want to use for various types of backends, whereas the SQLClient data controls work strictly with SQL Server. The same is true of using these objects as well. If you know that you will just be using a SQL Server backend, you will get better performance by using the SQLClient objects because a layer is cut out. You will get a chance to see all of the items listed in the previous two tables throughout the following How-Tos. Tip If you have to stick with ADO or just want to be stubborn, check out using ADO with .NET by reading Appendix A, "Desktop Development with ADO." Although ADO.NET does take more work sometimes to accomplish a task that you could do using ADO, the power and flexibility of ADO.NET is well worth the learning curve. Note Although this chapter was written using Windows Forms, the majority of the objects can also be used in Web Forms as well as by using ADO.NET with ASP.NET. You will see this in Chapter 5, "Working with Date in Web Forms." You will learn various methods for achieving the same goal. When and Page 97 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html how you use these methods will depend on the scenario. All of the examples in this chapter can be found in the Solution called VB.NET Web site. Chapter 3 on the [ Team LiB ] Page 98 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 3.1 Retrieve Data by Using the DataReader Object In Chapter 1, you learned how to use bound controls to OleDb controls that could be included on the forms. Some developers prefer to use unbound controls to perform the same task. The DataReader object allows you to add items to a list box in a more efficient manner because it is only a read-and-forward-only type object. This How-To tells you how to generate a limited ListBox control by using a DataReader object. You want to create a limited list of customers. You don't want to use bound controls because you are a cool VB developer who knows better than that. You heard that the DataReader object is a fast way to get data. How do you retrieve data using the DataReader object to perform this task? Technique For this How-To, you will be using the ListBox control and loading items into it by using the DataReader object. To get to the DataReader object, you need to look at the Command object. The Command object in .NET works similarly to the ADO Command in that you will assign the stored procedure name or SQL statement to the CommandText property as well as the connection to use. One difference is that you will use the Open method of the Command object, and then the ExecuteReader method, to create the DataReader object. You will then use the Read method off of the DataReader object to perform two tasks. The first task is that when used in a loop, you can test for datareader.Read() to check whether to terminate the loop and also to iterate through the rows that the DataReader object returns. After you have the DataReader populated and you are iterating through the rows, you will load the data into the ListBox control. You will be using the Clear and Add methods, which were used in VB 6. In addition, you will use the BeginEdit and EndEdit methods, which speed up loading ListBox controls when you are loading a large amount of data. To view this example in design view, open the form called frmHowTo3_1.vb in the chapter's solution. Steps Open and run the VB.NET Chapter 3 solution. From the main form, click on the command button with the caption How-To 3.1. When the form loads, click on the Load List command button. You will see the list below fill with all the company names that start with A. You will be creating a form similar to one that was created in Chapter 1. Instead of using bound controls, however, you will use code along with ADO.NET to populate the ListBox control. 1. Create a Windows Form. Then place a Label, TextBox, ListBox, and Command button on the form with the properties that are listed in Table 3.3 set. Table 3.3. Label, TextBox, ListBox, and Command Button Control Property Settings Object Property Setting Label Name Label1 Page 99 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Caption TextBox Name Text ListBox Command Button Name Name Caption 2. Customer txtCustLimit A lstCustomers btnLoadList Load List Notice that the list box does not have the DataBindings properties set. That is because you will be using the ListBox control unbound. Look at Figure 3.3 to see what the form should look like. 3. Figure 3.3. Arrange the controls on the form that you created to look like this form. 4. 5. Before creating the code that will be attached to the Click event of the btnLoadList command button, you need to devise a support routine to create the connection string. Called BuildCnnStr, the function can been seen in Listing 3.1. This function takes a server and database names that are passed to it and creates a connection string. Listing 3.1 modGeneralRoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, _ ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" Page 100 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method is to pass back a string. The reason for this is that for some objects, you are asked for a Connection object, whereas in other objects, you just need a string. You will see BuildCnnStr called in the next step. 6. On the btnLoadList Command button, add the following code from Listing 3.2 to the Click event. In this routine, a SQL string is created and stored in the strSQL string, taking Text property of the txtCustLimit text box and adding it to a literal. Then, within a Try-Catch-End-Try block, a new instance of an OleDbCommand object called ocmdCust is created. The routine then follows the steps that are discussed in the Technique section. Listing 3.2 frmHowTo3_1.vb: Loading a List Box By Using the DataReader Object Private Sub btnLoadList_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnLoadList.Click Dim ocmdCust As OleDb.OleDbCommand Dim odrCust As OleDb.OleDbDataReader Dim strSQL As String '-- Create the SQL String strSQL = "Select CompanyName From Customers Where CustomerID Like '" & Me.txtCustLimit.Text & "%'" '-- Set up the exception catch Try '-- Create an instance of the command ocmdCust = New OleDb.OleDbCommand() With ocmdCust '-- Set up the connection of the command and the command text .Connection = _ New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) .Connection.Open() .CommandText = strSQL '-- Set up the data reader instance odrCust = .ExecuteReader(CommandBehavior.SequentialAccess) End With '-- Add the items to the list box. With lstCustomers .Items.Clear() .BeginUpdate() Do While odrCust.Read Page 101 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html .Items.Add(odrCust.Item("CompanyName")) Loop .EndUpdate() End With Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub Note Something of interest to those VB developers is the fact that the lines of code that read as follows: .Connection = _ New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) actually declare, initialize, and use an OleDBConnection object in the single statement. This is new to .NET and is extremely useful. How It Works When the user clicks the btnLoadList button, the Command object is assigned the necessary properties, the connection is opened, and the ExecuteReader method is called. After the list has been cleared, the DataReader is iterated through, and the ListBox control is loaded. Comments The DataReader object is one of the most efficient ways to get data from the server and load lists into your application. Other options besides CommandBehavior.SequentialAccess are available that make the DataReader convenient to use. Most notable is CommandBehavior.SchemaOnly, which returns information only about the columns, and no data. You can use the Command object in a number of ways besides what was mentioned in this How-To. You will see additional examples of using the Command object with stored procedures to perform batch actions later in the chapter. You have seen how to use the ListBox control in a total unbound technique. In the next How-To, you will see a blend of using the ListBox control in a semibound technique, where you will bind the data at runtime. [ Team LiB ] Page 102 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 3.2 Retrieve Results from SQL Server by Using the DataTable Object The data reader is great when you just want to load data into a ListBox or ComboBox control manually, but you can save some coding by binding the ListBox control to a data table at runtime, as well as providing the ability to get not only the displayed value, but the key column as well. This How-To demonstrates how to bind a limited ListBox control to a data table. Although getting the quick information is great, you need to be able to refer back to the table of information, and you don't want to have to open another connection to get there. You know that the DataTable object should allow you to perform this task. How do you get results from SQL Server by using the DataTable object? Technique Using the Windows Forms controls that were introduced in How-To 3.1, you will use a familiar object from Chapter 1 called the DataAdapter object. This time, instead of using the OleDbDataAdapter data control, you will use the OleDbDataAdapter class from the System.Data.OleDb Namespace. Using a similar technique that was used when filling a DataSet, you will instantiate the data adapter by assigning the SQL string and connection object. Then, instead of filling a DataSet object, you will fill a DataTable object. Because you will only be dealing with a table's worth of data, you just need to use a data table. That way, you will be able to perform lookups more conveniently, as shown in the next How-To. For now, the next step will be to assign the following properties of the list box:   DataSource. This will be set to the DataTable object in this case, dtCust. DisplayMember. This specifies which column from the data table to use for display in the list box.  ValueMember. Here, you will specify which column you want to use for the value that is retrieved when an item is selected from the list box. By programming the ListBox control using this technique, you can access the ValueMember column in the SelectItem property of the list box. Steps Open and run the VB.NET Chapter 3 solution. From the main form, click on the command button with the caption How-To 3.2. When the form loads, click on the Load List command button. You will see the list below fill with all the company names that start with A. 1. To save time, you can make a copy of the form that was created in the first How-To in this chapter. 2. Replace the btnLoadList Click event with the following code listed here in Listing 3.3. That's it. After creating the SQL string that will be used and storing it in strSQL, the data adapter called odaCust is created. The odtCust data table is then filled using odaCust. Last, the DataSource, DisplayMember, and ValueMember properties are set for the lstCustomers list box. This was all accomplished with a Try-Catch-End-Try block of code. Page 103 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 3.3 frmHowTo3_2.vb: Loading a List Box By Using the DataTable Object Private Sub btnLoadList_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadList.Click Dim odaCust As OleDb.OleDbDataAdapter Dim dtCust As DataTable = New DataTable() Dim strSQL As String '-- Create the SQL String strSQL = "Select CustomerID, CompanyName From Customers " & _ "Where CustomerID Like '" & Me.txtCustLimit.Text & "%'" '-- Set up the exception catch Try '-- Create an instance of the data adapter, ' and then fill the data table odaCust = New OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) odaCust.Fill(dtCust) '-- Bind the data to the list box lstCustomers.DataSource = dtCust lstCustomers.DisplayMember = "CompanyName" lstCustomers.ValueMember = "CustomerID" Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub How It Works When the user clicks on the btnLoadList button, the data adapter called odaCust is instantiated. The data adapter is passed strSQL and the connection string that is created by the function called BuildCnnStr, which was introduced in the first How-To in this chapter. The data table is then filled, and then the DataSource, DisplayMember, and ValueMember properties of the ListBox control are assigned. Comments Using the data table sets up the scene for using the list box in retrieving data in the next How-To. Remember: By using the DataTable object, you can assign both the display value and the data item to be tracked. [ Team LiB ] Page 104 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 3.3 Locate Records with the DataTable Object Using the DataTable object, you can use another object called the DataRow object that allows you to locate a specific row in the data table. This is useful when you want to present your users with a search mechanism for your form. This How-To shows you how to locate a specific row within your data table and how to use the same data table for two different purposes. After you have your DataTable object loaded in memory, you want to be able to locate specific records within the DataTable object. How do you locate records in the DataTable object? Technique For this How-To, you are going to use a ComboBox control instead of a ListBox control. You will use the same technique for loading the combo box as you would the list box. The change comes when you select an item from the combo box. When an item is selected in the combo box, the SelectedIndexChanged event is fired off. Within this event, you will take the combo box's SelectedItem, which gives the ValueMember that is located in the selected row, and use that with the Find method off the DataTables Rows collection. With the data row located, the corresponding columns are loaded into text boxes on the form, as shown in Figure 3.4. Figure 3.4. This combo box will point the user to a specific customer. Steps Open and run the VB.NET Chapter 3 solution. From the main form, click on the command button with the caption How-To 3.3. When the form loads, pick a new customer from the list that is presented in the customer ComboBox control. You will see the text boxes below the ComboBox Page 105 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html control display new data that corresponds to the chosen customer. 1. 2. Create a new Windows Form. Add some labels, combo boxes, and text boxes, as listed in Table 3.4. Table 3.4. Label, TextBox, and ComboBox Control Property Settings Object Property Setting Label Name Caption Label1 Customer cboCustomers Label2 Customer ID Label3 Company Name Label4 Address Label5 City txtCustomerID txtCompanyName txtAddress txtCity ComboBox Label Name Name Caption Label Name Caption Label Name Caption Label Name Caption TextBox TextBox TextBox TextBox 3. 4. Name Name Name Name You will also want to make sure that the Text properties in the TextBox controls are blank. In the class module for the form, add the following two Private declarations just below the line of code that reads Windows Form Designer generated code. 5. 6. Private modaCust As OleDb.OleDbDataAdapter Page 106 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 7. Private mdtCust As DataTable = New DataTable() These lines of code declare a data adapter and a data table that will be used throughout the form. Note Adding the m on the front tells you that it is a moduleor member-level variable. Also, remember that although you are declaring this at the form level, the connection that is used for the data adapter is not going to be left open the whole time the form is. When the data table is filled, the connection is opened. Then the data is accessed locally using XML under the covers. It is disconnected from the server. 8. Add the code shown in Listing 3.4 to the Load event of the form. Almost identical to the code in the last How-To to load a ListBox control, this code sets modaCust to a SQL String and the connection string to be used. mdtCust is then filled using the Fill method of modaCust. Next, the first element in the DataColumn array called dc is set to the CustomerID column. mdtCustPrimaryKey is then set to the DataColumn array. Last, the DataSource, DisplayMember, and ValueMember properties are set. Listing 3.4 frmHowTo3_3.vb: Loading a ComboBox by Using the DataTable Object Private Sub frmHowTo3_3_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim strSQL As String Dim dc(1) As DataColumn '-- Set up the exception catch Try '-- Create the data adapter and fill the data table modaCust = New _ OleDb.OleDbDataAdapter("Select * From Customers", _ (BuildCnnStr("(local)", "Northwind"))) modaCust.Fill(mdtCust) '-- Set up the primary key for the data table dc(0) = mdtCust.Columns("CustomerID") mdtCust.PrimaryKey = dc '-- Bind the data to the combo box cboCustomers.DataSource = mdtCust cboCustomers.DisplayMember = "CompanyName" cboCustomers.ValueMember = "CustomerID" Page 107 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub The PrimaryKey property that was set will be used in the code for the next step by the Find method of mdtCust's Rows collection. 9. This last bit of code needs to be added to the SelectedIndexChanged event of the cboCustomers ComboBox control. As with the last step, when a data column was set up for the PrimaryKey property, in this step an array is specified to pass the SelectedItem value to find the Find method. The text boxes' Text properties are then set to the column values by using the ToString method. Listing 3.5 frmHowTo3_3.vb: Locating a Record in the Data Table, and Then Assigning Values to Text Boxes Private Sub cboCustomers_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cboCustomers.SelectedIndexChanged Dim drCurr As DataRow Dim aFindValue(0) As Object '-- Load the item to look up, and use the find method aFindValue(0) = cboCustomers.SelectedItem(0) drCurr = mdtCust.Rows.Find(aFindValue) '-- Load up the fields on the form txtCustomerID.Text = drCurr("CustomerID").ToString txtCompanyName.Text = drCurr("CompanyName").ToString txtAddress.Text = drCurr("Address").ToString txtCity.Text = drCurr("City").ToString End Sub How It Works When a user picks a customer from the cboCustomer ComboBox control, the code then locates the desired value within the mdtCust data Table using the Find method off the rows collection. Text boxes are then loaded from the row that is retrieved. Comments Locating records within a data table and data row is pretty easy when you're using the methods that are supplied. ADO.NET provides the control you need, not only at the overall hierarchical level, but also at the row and column levels. [ Team LiB ] Page 108 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 3.4 Filter and Sort Records Using the DataView Object After your data is loaded into the data table, you will probably want to be able to view your data using different filters and sort orders. To do this, you can use the DataView object. This How-To goes into detail and shows you how to take advantage of the DataView control to manipulate your data. Although you can put data into the DataGrid control and let the users sort data using the columns, you want to display a ComboBox control and let users pick a field from the drop-drown list. How can you filter and sort records using the DataView object to present your data in different ways? Technique This How-To displays a set of command buttons that display a letter and an extra command button that displays all records. A data adapter, data table, and data view are declared at the form level. The data adapter is created and the DataTable is filled when the form is loaded with all customers. Using a DataColumn object, a combo box is filled by getting the names of each column that is in the data table. You can see this form in action in Figure 3.5. Figure 3.5. Selecting a letter here limits the data displayed in the DataGrid control. Using the command buttons, a routine is called that creates a DataView object, sets the RowFilter property, and then assigns the data view to the DataSource property of a DataGrid control. Page 109 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Tip Although the RowFilter allows you to filter data based on a criteria such as CompanyName Like 'A%', you can set another property to display data based on the state of the row in which data occurs. The property is called RowStateFilter. You can set the RowStateFilter to one of the following DataViewRowState values in Table 3.5. Table 3.5. Label, TextBox, and ComboBox Control Property Settings Setting Description New rows Current rows including unchanged, new, and modified rows Deleted rows A current version, which is a modified version of original data (see ModifiedOriginal) Added CurrentRows Deleted ModifiedCurrent ModifiedOriginal The original version (although it has since been modified and is available as ModifiedCurrent) None OriginalRows Unchanged None Original rows including unchanged and deleted rows Unchanged row The Sort property of the DataView object is used when a column name is chosen from the ComboBox. The current setting of the Sort property is compared to the column name that is chosen. If the Name matches, then the expression DESC is added to the value that is assigned to the Sort property. Steps Open and run the VB.NET Chapter 3 solution. From the main form, click on the command button with the caption How-To 3.4. When the form loads, click on different letters that are displayed. You will see the data grid display different customers based on their first letter. If you choose a column name from the Column to Sort On ComboBox control, the data grid will then be sorted based on the column chosen. 1. 2. 3. Create a new Windows Form. Add a GroupBox control with the text property set to Click on a Letter. Now you will be creating buttons that you will place within the GroupBox control you just created. The buttons will have their property set as listed in Table 3.6. Page 110 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 3.6. Buttons Property Settings Object Property Setting Button Name Caption btnA A btnB B btnC C Button Name Caption Button Name Caption ... Button Name Caption Button Name Caption 4. btnZ Z btnAll All Add the DataGrid, the Label, and the ComboBox controls shown in Listing 3.6. Table 3.7. DataGrid, Label, and ComboBox Controls Property Settings Object Property Setting DataGrid Label Label ComboBox 5. Name Name Caption Name dgCustomers Label1 Column to Sort On: cboSortColumns In the class module for the form, add the following three Private declarations just below the line of code that reads Windows Form Designer generated code. These three objects will be used throughout the form. 6. 7. 8. 9. Private modaCust As OleDb.OleDbDataAdapter Private mdtCust As DataTable = New DataTable() Private mdvCust As DataView = New DataView() 10. Add the following code to the Load event of the form as shown in Listing 3.6. This code starts out by setting up the modaCust data adapter to grab all the customers to fill the data Page 111 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html table called mdtCust. Note that at this point, the data grid has not been filled. The next task is to load cboSortColumns with the column headings by iterating through each of the data columns in mdtCust and adding them to the Items collection in cboSortColumns. Last, the SetDataViewFilter routine is called. This routine is discussed in step 8. Listing 3.6 frmHowTo3_4.vb: Loading the Data Table to Be Used in the Form, and Adding Column Names to a ComboBox Control Private Sub frmHowTo3_4_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim strSQL As String Dim dcCurr As DataColumn '-- Set up the exception catch Try '-- Create the data adapter and fill the data table modaCust = New _ OleDb.OleDbDataAdapter("Select * From Customers", _ (BuildCnnStr("(local)", "Northwind"))) modaCust.Fill(mdtCust) '-- Load the column names into the sort ComboBox control For Each dcCurr In mdtCust.Columns Me.cboSortColumns.Items.Add(dcCurr.ColumnName) Next SetDataViewFilter("B") Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub 11. For each of the command buttons that has a single letter, add the first subroutine displayed here in Listing 3.7 to each of its Click events. For the btnAll Button control, add the second subroutine to the Click event. Each Button control will pass the letter that it represents to the subroutine called SetDataViewFilter, discussed in the next step. The btnAll code simply passes the empty string. Listing 3.7 frmHowTo3_4.vb: Click Events for Each of the Button Controls Private Sub btnA_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnA.Click SetDataViewFilter("A") End Sub Private Sub btnAll_Click(ByVal sender As System.Object, _ Page 112 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal e As System.EventArgs) Handles btnAll.Click SetDataViewFilter("") End Sub 12. Add the subroutine that is found in Listing 3.8 to the class module of the form. This routine takes the letter value that is passed in strFilterLetter as a parameter. The first task to perform is assigning the DefaultView of the mdtCust DataTable object to the mdvCust data view. Next, the RowFilter property of mdvCust is set to compare the CompanyName column with the Like expression using the strFilterLetter and the % (wildcard). Note that if "" is passed to strFilterLetter, all the records will be listed. Finally, mdvCust is set as the DataSource for dgCustomers, which is the DataGrid control. Listing 3.8 frmHowTo3_4.vb: Setting the RowFilter Property for a DataView Object Sub SetDataViewFilter(ByVal strFilterLetter As String) mdvCust = mdtCust.DefaultView mdvCust.RowFilter = "CompanyName Like '" & strFilterLetter & "%'" dgCustomers.DataSource = mdvCust End Sub 13. Add the piece of code that is shown in Listing 3.9 to the SelectdIndexChanged event of the cboSortColumns ComboBox control. This routine compares the current setting of mdvCust's Sort property to the current column name chosen in cboSortColumns. If the two are the same, then the column name is assigned to the Sort property with the DESC keyword added on. If not, then the name of the column is assigned to the Sort property. Listing 3.9 frmHowTo3_4.vb: Specifying a Column on Which to Sort Private Sub cboSortColumns_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles cboSortColumns.SelectedIndexChanged '-- Check to see if the column is currently the sorted field. ' ' If it is, sort on the column in descending order. Otherwise, set the sort to the name of column. If mdvCust.Sort = Me.cboSortColumns.Text Then mdvCust.Sort = Me.cboSortColumns.Text & " DESC" Else mdvCust.Sort = Me.cboSortColumns.Text End If End Sub How It Works When the user clicks on a letter, the data view is created, and the data grid reflects the new data. When a field is selected from the ComboBox control, the Sort property of the data view is set and the data grid automatically reflects the new sort order, also showing an arrow in the column heading. If the user chooses the field again, the column will sort in descending order. Page 113 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Using the DataView object, you can keep track of multiple views of your data and display them for the users' use. You can also access all of the default views of the data tables in your data set using the DefaultViewManager. Note Some people might think that the sorting combo box that was added to this example is unnecessary. It was added for two reasons. First, it shows how to use the Sort property of a DataView object. Second, it's convenient for the user. The user might not want to have to scroll over to a column that is not displayed in the data grid. By using the combo box, he can sort on fields that are not currently displayed. [ Team LiB ] Page 114 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 4. Manipulating Data With ADO.NET In this chapter you will     Edit data and update changes made to an ADO.NET DataSet object Add and delete rows in a dataset with ADO.NET Execute parameterized stored procedures in ADO.NET Create and execute on-the-fly batch updates by using ADO.NET In Chapter 3, "Viewing Data with ADO.NET," you saw how to use ADO.NET to display data in various forms. However, there is so much more to ADO.NET, such as manipulating your data by modifying current data, as well as inserting and deleting data. ADO.NET gives you the tools you need to accomplish these tasks with some of the objects you were introduced to in Chapter 3 . A few more steps are required to manipulate data using ADO.NET then there were in ADO. The main reason for this is that ADO.NET is disconnected; therefore, after you have saved your changes to the ADO.NET objects, such as a dataset, you need to commit those changes back to the server. You will see how to do this in this chapter. The good news is that after you learn how to have the objects update and commit the data back to the server for one task, such as editing of data, you will use the same basic commands for the other tasks as well. Let's get started. [ Team LiB ] Page 115 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 4.1 Edit Data and Update Changes That Are Made to an ADO.NET DataSet Object Listing and viewing data is easy. What you really need to do is to be able to edit and update data. You know you can use the DataSet object and some of its objects and methods to perform this task. How do you edit and update data using the DataSet object? Technique In this How-To, you will use the DataAdapter, DataSet, DataTable, and DataRow objects. You have experienced some of the properties and methods of each of these objects before. In this chapter, you are going to be using the following properties and methods that are shown in Table 4.1. Table 4.1. DataAdapter, DataSet, DataTable, and DataRow Properties and Methods Object /Method Property Description Fills DataSet and DataTable objects. DataAdapter Fill CommandBuilder GetUpdateCommand Creates an Update command and places it into the data adapter's UpdateCommand property. DataAdapter DataAdapter UpdateCommand Close Holds the SQL statement for the update. Closes the connection off the UpdateCommand. The syntax is dataadapter.UpdateCommand.Connect.Close(). DataAdapter DataSet DataSet Update Tables Rows Performs the update command against the dataset. Represents a collection of tables found within a dataset. Contains a collection of rows within a specified table in a dataset. Sends the changes back to the server. Retrieves the data from the column that is specified in the DataRow and returns it as a string value. Begins the editing of a DataRow, allowing you to replace values in the columns. DataSet DataRow AcceptChanges ToString DataRow BeginEdit DataRow EndEdit Completes the editing of a DataRow. You will see these objects with their properties and methods used in the following steps. Steps Open and run the VB.NET Chapter 4 solution. From the main form, click on the command button with the caption How-To 4.1. When the form loads, click on the Load List button to display the customers that begin with the letter A. Click the Edit button. You will notice that the fields have now taken on a sunken look. Place the cursor into the City field and change the value to Dunkirk. Now Page 116 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html click Save. If you move off the record and move back on, you will notice that the value has been saved. This form looks similar to the form created in Chapter 1. The difference is that this time you will not be using controls that are bound at design time. You can see the form in Figure 4.1. 1. 2. Create a new Windows Form. Add the following controls, setting the properties as listed in Table 4.2. Table 4.2. Controls Property Settings Object Property Setting Label Name Caption Label1 Customer txtCustLimit A btnLoadList Load List lstCustomers Customer ID Company Name Contact Contact Title Address City Region Country Phone Fax txtCustomerID txtCompanyName txtContact TextBox Name Text Button Name Caption ListBox Label Label Label Label Label Label Label Label Label Label TextBox TextBox TextBox Name Caption Caption Caption Caption Caption Caption Caption Caption Caption Caption Name Name Name Page 117 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox Button Name Name Name Name Name Name Name Name Name Caption txtContactTitle txtAddress txtCity txtRegion txtPostalCode txtCountry txtPhone txtFax btnEdit &Edit btnSave &Save btnCancel &Cancel Button Name Caption Button Name Caption 3. Note Notice that the Text property of the text boxes is not being set at design time. In Chapter 1, "Developing Windows Forms Using Bound Controls," they were set to columns of a dataset that was included on the form. In this How-To, they will be set at run-time. 4. In the class module for the form, add the following three Private declarations just below the line of code that reads Windows Form Designer generated code. These three objects will be used throughout the form. 5. 6. 7. 8. 9. 10. 11. Private Sub btnLoadList_Click(ByVal sender As System.Object, _ 12. 13. 14. '-- Move the loading of the list to a subroutine for ByVal e As System.EventArgs) Handles btnLoadList.Click Dim mdsCustIndiv As New DataSet() Dim modaCustIndiv As OleDb.OleDbDataAdapter Dim mdrCustIndiv As DataRow Enter the following code as the Click event for btnLoadList: Page 118 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 15. 16. 17. 18. End Sub ' additional(calls) LoadList() 19. Create the LoadList routine by entering the following code into the form you created for this How-To. This code creates and fills a data table using a data adapter. The string that the data adapter uses creates a Select statement by using the txtCustLimit text box. The DataSource, DisplayMember, and ValueMember properties of the list box are then bound. Last, the LoadIndividual routine is called, which is described in the next step. 20. 21. Private Sub LoadList() 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. table 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. End Sub LoadIndividual() Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try '-- Bind the data to the list box lstCustomers.DataSource = dtCustList lstCustomers.DisplayMember = "CompanyName" lstCustomers.ValueMember = "CustomerID" odaCustList = New OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) odaCustList.Fill(dtCustList) '-- Create an instance of the data adapter; then fill the data '-- Set up the exception catch Try '-- Create the SQL String strSQL = "Select CustomerID, CompanyName " & _ From Customers Where CustomerID Like '" & _ Me.txtCustLimit.Text & "%'" Dim strSQL As String Dim odaCustList As OleDb.OleDbDataAdapter Dim dtCustList As DataTable = New DataTable() 55. Create the LoadIndividual routine by entering the following code in the form you created for this How-To. Taking the SelectedItem from the list box, a data adapter is created, and a dataset is filled. Next, the individual DataRow is created. Last, each of the TextBox Page 119 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html controls is loaded with the value from the column with the corresponding name. Notice the use of the Try-Catch-End-Try to ignore controls that don't have a like column in the DataRow. 56. 57. Private Sub LoadIndividual() 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. '-- By trapping the exception this way, errors are ignored. Try oCtl.text = mdrCustIndiv(strName).ToString Catch oexp As Exception End Try strName = Mid(oCtl.Name, 4) If TypeOf oCtl Is TextBox Then For Each oCtl In Me.Controls '-- Run through the text boxes on the form, and '-- if they match up with a field from the record, ' load them. End Try Exit Sub MessageBox.Show("Error loading individual data: " _ & oexpData.Message) Catch oexpData As OleDb.OleDbException '-- Grab the individual data row mdrCustIndiv = mdsCustIndiv.Tables("Customers").Rows(0) '-- Fill the dataset modaCustIndiv.Fill(mdsCustIndiv, "Customers") Try '-- Load the individual record into the dataset strSQL = "Select * from Customers Where CustomerID = '" & Me.lstCustomers.SelectedItem(0) & "'" modaCustIndiv = New OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) If Me.lstCustomers.SelectedIndex <> -1 Then mdsCustIndiv.Clear() Dim strSQL As String Dim strName As String Dim oCtl As Object Page 120 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 103. 104. 105. 106. 107. 108. 109. End If End Sub Next End If 110. Enter the following code to the Click event for lstCustomers: 111. 112. Private Sub lstCustomers_Click(ByVal sender As Object, 113. 114. 115. 116. 117. 118. End Sub 119. Enter the following code to the Click event for btnEdit: 120. 121. Private Sub btnEdit_Click(ByVal sender As System.Object, 122. 123. 124. 125. 126. 127. End Sub 128. Create the ActivateEditing routine by entering the following code in the form you created for this How-To. Introduced in Chapter 1, this code goes through each of controls on the form, looking for text boxes, then setting the BorderStyle and BackColor properties based on whether the controls are to be enabled or disabled. The Enabled property of each control is then set as well. 129. 130. Private Sub ActivateEditing(ByVal bEnable As Boolean) 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. oCurr.BackColor() = System.Drawing.Color.White oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.Fixed3D '-- If so, toggle the properties If bEnable Then '-- Check to see if the control is a text box If TypeOf oCurr Is TextBox And oCurr.Name <> "txtCustLimit" Then '-- Loop through each of the controls on the form For Each oCurr In Me.Controls() Dim oCurr As Object '-- Enable the editing of the form ActivateEditing(True) ByVal e As System.EventArgs) Handles btnEdit.Click '-- Fill the current list item's individual dataset LoadIndividual() ByVal e As System.EventArgs) Handles lstCustomers.Click Page 121 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 148. 149. 150. 151. 152. 153. 154. 155. 156. 157. 158. 159. 160. 161. 162. 163. 164. End Sub 165. Enter the following code to the Click event btnSave: 166. 167. Private Sub btnSave_Click(ByVal sender As System.Object, _ 168. 169. 170. 171. 172. 173. 174. 175. 176. End Sub '-- Disable the text boxes ActivateEditing(False) '-- Save the information SaveRecord() ByVal e As System.EventArgs) Handles btnSave.Click End If Next oCurr.Enabled = bEnable End If oCurr.BackColor() = Me.BackColor oCurr.BorderStyle() = _ System.Windows.Forms.BorderStyle.FixedSingle Else 177. Create the SaveRecord routine by entering the following code in the form that you created for this How-To. Using a DataRow object, the BeginEdit method is called, and then each of the controls is stored back into the columns of the same names, if they exist. The EndEdit method is then called to complete the editing of the DataRow. A CommandBuilder object is created to create the Update command for the DataAdapter object. The DataAdapter Update method is called to update the dataset with the data changed and then the AcceptChanges of the DataSet object. This accepts all the changes for all the objects and posts the data back to the server. Finally, the connection is closed for the UpdateCommand of the DataAdapter object. 178. 179. Private Sub SaveRecord() 180. 181. 182. 183. 184. 185. 186. 187. 188. '-- Run through the text boxes on the form, and '-- if they match up with a field from the record, '-- Start the editing in the datarow. mdrCustIndiv.BeginEdit() Dim oCtl As Object Dim strName As String Page 122 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 189. 190. 191. 192. 193. 194. 195. 196. 197. 198. 199. 200. 201. 202. 203. 204. 205. 206. 207. 208. 209. 210. 211. 212. 213. 214. 215. 216. 217. 218. 219. 220. 221. 222. 223. 224. 225. 226. 227. 228. End Sub End Try Catch excData As Exception '-- Perform the update SQL command; then close the connection modaCustIndiv.Update(mdsCustIndiv, "Customers") mdsCustIndiv.Tables("Customers").AcceptChanges() modaCustIndiv.UpdateCommand.Connection.Close() '-- Have the command builder create an update SQL command modaCustIndiv.UpdateCommand = ocbCustIndiv.GetUpdateCommand '-- Create an instance of the command builder Dim ocbCustIndiv As OleDb.OleDbCommandBuilder ocbCustIndiv = New OleDb.OleDbCommandBuilder(modaCustIndiv) Try '-- Finish the editing of the data row mdrCustIndiv.EndEdit() Next End If '-- By trapping the exception this way, errors are ignored. Try mdrCustIndiv(strName) = oCtl.text Catch oexp As Exception End Try strName = Mid(oCtl.Name, 4) If TypeOf oCtl Is TextBox Then '-- place the value back in the record. For Each oCtl In Me.Controls 229. Enter the following code to the Click event btnCancel: 230. 231. Private Sub btnCancel_Click(ByVal sender As System.Object, _ 232. 233. 234. 235. 236. 237. 238. End Sub '-- Use the BindingContext class to cancel the current editing. LoadIndividual() ActivateEditing(False) ByVal e As System.EventArgs) Handles btnCancel.Click Page 123 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 4.1. Although this looks like the form created in Chapter 1, you have more control over this version with unbound controls. How It Works When the user clicks on the btnLoadList Button, the lstCustomers list box is loaded via the odaCustList data adapter and dtCustList data table. The first customer's information is then loaded in the text boxes on the right side of the form. When the btnEdit button is clicked, the look of the text boxes is changed to sunken, and they are enabled for editing of the text. After changing the data, when the user clicks on the btnSave button, the data is then stored back into the server, and the text boxes are changed to disabled. If the btnCancel is clicked, the text boxes are changed to disabled. Comments Although it takes a bit more code to handle the editing and updating of data with unbound controls versus bound controls, you might like it better because you can control the code. With bound controls, the code is written for you. The code that is displayed here can be modified to be more generic so that you don't have to write individual routines for each form. [ Team LiB ] Page 124 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 4.2 Add and Delete Rows in a Dataset with ADO.NET Again using the OleDbDataAdapter and OleDbCommandBuilder objects, this How-To shows you how to use unbound controls with the dataset to add and delete rows from SQL Server. As with editing and updating data, you need to be able to add and delete rows using the dataset. How do you perform this task? Technique The main difference between this technique and the previous one will be which action command you will use with the DataAdapter object. You will also be presented with the Add method on the Rows collection. Steps Open and run the VB.NET Chapter 4 solution. From the main form, click on the command button with the caption How-To 4.2. When the form loads, click on the Load List button to display the customers that begin with the letter A. Click the Add button. You will notice that the fields have now taken on a sunken look and that they are cleared. Fill in the Customer ID and Company Name text boxes with AAA1 and Another Example. Now click Save. If you move off the record and move back on, you will notice that the value has been saved. Now select the new record you added, and click the Delete button. The record disappears, and the list box is updated to reflect the deletion. 1. 2. Make a copy of the form you created in the last How-To. Add two buttons for adding and deleting records, setting the properties as listed here in Table 4.3. Table 4.3. Add and Delete Buttons Property Settings Object Property Setting Button Name Caption btnAdd &Add btnDelete &Delete Button Name Text 3. Add the following line of code where you placed the other module-level variable declarations. This variable will be set to True in the btnAdd click event, and it can be used when saving the record. 4. 5. 6. Dim mblnAdd As Boolean Enter the following code to the Click event btnAdd. The first task is to set the mblnAdd variable to True. Then the routine clears the current text in the text boxes. It also enables the text boxes by calling ActiveEditing. 7. Page 125 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. End Sub ActivateEditing(True) Next End If '-- By trapping the exception this way, errors are ignored. Try oCtl.text = "" Catch oexp As Exception End Try strName = Mid(oCtl.Name, 4) If TypeOf oCtl Is TextBox And oCtl.name <> "txtCustLimit" Then '-- Clear the fields For Each oCtl In Me.Controls mblnAdd = True Dim oCtl As Object Dim strName Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click 36. Replace the SaveRecord routine with the following code in the form that you created for this How-To. The first change is to add the lines of code that test mblnAdd; if they're True, call the NewRow method off the dataset's Tables collection, specifying the Customers table. The DataRow returned is assigned to mdrCustIndiv. You can then enter the other changes wherever the blnAdd variable is queried. 37. 38. Private Sub SaveRecord() 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. '-- Run through the text boxes on the form, and '-- if they match up with a field from the record, '-- place the value back in the record. For Each oCtl In Me.Controls '-- Start the editing in the datarow. mdrCustIndiv.BeginEdit() If mblnAdd Then mdrCustIndiv = mdsCustIndiv.Tables("Customers").NewRow End If Dim oCtl As Object Dim strName As String Page 126 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 54. 55. 56. 57. 58. 59. 60. 61. 62. 63. 64. 65. 66. 67. 68. 69. 70. 71. 72. 73. 74. 75. 76. 77. 78. 79. 80. 81. 82. 83. 84. 85. 86. 87. 88. 89. 90. 91. 92. 93. 94. 95. 96. 97. 98. 99. 100. 101. 102. 103. 104. Catch excData As Exception MessageBox.Show("Error Occurred: " & excData.Message) End Try '-- Close the connection If mblnAdd Then modaCustIndiv.InsertCommand.Connection.Close() LoadList() Else modaCustIndiv.UpdateCommand.Connection.Close() End If '-- Perform the specified SQL command; then close the connection modaCustIndiv.Update(mdsCustIndiv, "Customers") mdsCustIndiv.Tables("Customers").AcceptChanges() If mblnAdd Then '-- Have the command builder create an Insert SQL command modaCustIndiv.InsertCommand = ocbCustIndiv.GetInsertCommand Else '-- Have the command builder create an update SQL command modaCustIndiv.UpdateCommand = ocbCustIndiv.GetUpdateCommand End If '-- Create an instance of the command builder Dim ocbCustIndiv As OleDb.OleDbCommandBuilder ocbCustIndiv = New OleDb.OleDbCommandBuilder(modaCustIndiv) If mblnAdd Then mdsCustIndiv.Tables("Customers").Rows.Add(mdrCustIndiv) End If Try '-- Finish the editing of the datarow mdrCustIndiv.EndEdit() Next End If '-- By trapping the exception this way, errors are ignored. Try mdrCustIndiv(strName) = oCtl.text Catch oexp As Exception End Try strName = Mid(oCtl.Name, 4) If TypeOf oCtl Is TextBox Then Page 127 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 105. 106. End Sub 107. Enter the following code to the Click event btnCancel. 108. 109. Private Sub btnCancel_Click(ByVal sender As System.Object, _ 110. 111. 112. 113. 114. 115. 116. 117. 118. 119. 120. 121. End Sub LoadIndividual() ActivateEditing(False) If mblnAdd Then mblnAdd = False End If '-- Cancel the current editing. ByVal e As System.EventArgs) Handles btnCancel.Click 122. Enter the following code to the Click event btnDelete. Follow the comments to see what is happening. 123. 124. Private Sub btnDelete_Click(ByVal sender As System.Object, 125. 126. 127. 128. 129. 130. 131. 132. 133. 134. 135. 136. 137. 138. 139. 140. 141. 142. 143. 144. 145. 146. 147. 148. 149. 150. 151. 152. LoadList() ActivateEditing(False) Catch excData As Exception MessageBox.Show("Error Occurred: " & excData.Message) End Try '-- Close the connection modaCustIndiv.DeleteCommand.Connection.Close() '-- Perform the specified SQL command; then close the connection modaCustIndiv.Update(mdsCustIndiv, "Customers") mdsCustIndiv.Tables("Customers").AcceptChanges() '-- Have the command builder create a Delete SQL command modaCustIndiv.DeleteCommand = ocbCustIndiv.GetDeleteCommand '-- Instantiate the command builder ocbCustIndiv = New OleDb.OleDbCommandBuilder(modaCustIndiv) '-- Delete the record from the datarow object mdrCustIndiv.Delete() Try Dim ocbCustIndiv As OleDb.OleDbCommandBuilder ByVal e As System.EventArgs) Handles btnDelete.Click Page 128 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 153. 154. End Sub How It Works When a user clicks the Add button, the text boxes are all blanked out, and the mblnAdd flag is set as True. Then, after the user adds his information and clicks the Save button, the new record is added back to the server. If the Cancel button is clicked, the individual customer to whom the list is currently pointed is loaded into the text boxes. When the Delete key is pressed, the current record is deleted from the server. Then the customer list is refreshed, and the first customer in the list is displayed in the text boxes. Comments As you can see, adding and deleting a record does not take much more than editing and updating a record using ADO.NET. Using the commands in this How-To and the prior one, you can set it up to handle updating and canceling of multiple records as well. [ Tea m LiB ] Page 129 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 4.3 Execute Parameterized Stored Procedures in ADO.NET To take advantage of stored procedures to their full power, you need to be able to pass parameters so that specific criteria can be used. This How-To describes how to create parameters off the OleDbCommand objects to pass parameters to SQL Server. You need to execute a parameterized stored procedure in your application. How do you do this using Visual Basic .NET and ADO.NET? Technique In ADO, you have a Command object to execute stored procedures, among other tasks. In ADO.NET, you also have a Command object that performs basically the same task. In fact, many of the properties and methods that you use are the same. You can see a list of those in Table 4.4. Table 4.4. Objects That Are Used for This Technique, with Properties and Methods Object Property Description/Method Connection ConnectionString Contains the connection string that is used. Connection Open Opens the connection that the Command object uses. Command cmdText Specifies the SQL statement to use. Can be SQL statement or names of objects such as tables or stored procedures. Uses the Connection object. Specifies the type of command you want to execute. Can be one of the following command types: StoredProcedure, Command Command Connection CommandType DirectTable, or Text. Command Command Parameters ExecuteReader Parameters to pass to the stored procedure. Creates a DataReader object with the data that the command object specifies. DataReader Read Reads the next record in the DataReader, and also tests the end of the data returned. DataReader GetString Returns the current record, getting the column specified, and returns it as string. Returns the current record, getting the column specified, and returns it as 32-bit integer. DataReader GetInt32 You will use these objects and their properties and methods for the following steps. Steps Open and run the VB.NET Chapter 4 solution. From the main form, click on the command button Page 130 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html with the caption How-To 4.3. When the form loads, click on the View button to display the orders for the customer ID that is specified. By default, this is ALKI. A TextBox control is then displayed on the bottom of the form. You can see the form in Figure 4.2. 1. 2. Create a new Windows Form. Add the following controls, setting the properties as listed in Table 4.5. Table 4.5. Controls Property Settings Object Property Setting Label Name Caption Label1 Products and Quantities Ordered By: txtCustID ALFKI btnView &View txtResults TextBox Name Text Button Name Text TextBox Name MultiLine True 3. Enter the following code to the Click event btnView. This code takes the connection and creates the command object. The name of the stored procedure is passed, and the command type is specified, which is CommandType.StoredProcedure. Next, parameters and the DataReader are created. The last task is to iterate through the data and add it to the display text box. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. '-- Specify the parameters. ocmdCustHist.Parameters.Add("@CustomerID", Me.txtCustID.Text) Try '-- Specify the name of the stored procedure ocmdCustHist.CommandType = CommandType.StoredProcedure Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Dim ocmdCustHist As New OleDb.OleDbCommand("CustOrderHist", ocnn) Dim odrCustHist As OleDb.OleDbDataReader Private Sub btnView_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnView.Click Page 131 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. End Try End Sub Catch excpData As Exception MessageBox.Show("Error Occurred: " & excpData.Message) Loop '-- Iterate through the data loaded, building the results string. Do While odrCustHist.Read Me.txtResults.Text &= odrCustHist.GetString(0) & _ ", " & odrCustHist.GetInt32(1) & vbCrLf '-- Establish the DataRead object. odrCustHist = _ ocmdCustHist.ExecuteReader(CommandBehavior.SequentialAccess) '-- Open the connection object. ocnn.Open() Figure 4.2. This form uses the Command object with a stored procedure to populate the TextBox control. How It Works When the user clicks on the View button with Customer ID filled in, the text box below is filled in, displaying order information for that customer. Comments Using the technique presented here, you can pretty well perform the majority of the tasks you need to by using Command objects and stored procedures. [ Team LiB ] Page 132 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 4.4 Create and Execute On-the-Fly Batch Updates by Using ADO.NET Sometimes in database applications, you want to create and execute stored procedures that don't currently exist. When you have a situation in which you need to use highly dynamic stored procedures that might use criteria that is entirely created at runtime, you might need to create those stored procedures on-the-fly. This How-To shows you how to create and execute these stored procedures. It's great that you can execute stored procedures that are already created, but what if you need to generate one at runtime? How do you do this? Technique To perform this How-To, you will be utilizing the OleDBCommand object, and feeding in the CommandText property from a text box. The text box is set to "Update Employees Set City = 'Redmond' Where City = 'Seattle'" to give you something to start with. Steps Open and run the VB.NET Chapter 4 solution. From the main form, click on the command button with the caption How-To 4.4. When the form loads, you will see an example update statement in a text box. Click on the Execute button to execute the update statement. A TextBox control is then displayed on the bottom of the form showing the number of records that are affected. You can the form in Figure 4.3. Figure 4.3. This form uses the Command object with a SQL statement passed to execute the specified action. Note The number of records affected might be different on your system depending on what you have been doing with the Northwind data. 1. 2. Create a new Windows Form. Add the following controls, setting the properties as listed in Table 4.6. Table 4.6. Controls Property Settings Page 133 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Object Property Setting Label Name Caption Label1 Update Statement to Execute: btnExecute txtSQL Update Employees Set City = 'Redmond' Where City = 'Seattle' Button Name TextBox Name Text MultiLine True Label Name Caption TextBox Name 3. Label2 Records Affected: txtRecsAffected Enter the following code to the Click event btnExecute. When the command is instantiated in this case, the string in the txtSQL text box is passed as the CommandText. The CommandType is set as CommandType.Text. The connection is then open. Finally, the command is executed with the ExecuteNonQuery method, with the ToString passing back the number of records that were affected to the Text property of the txtRecsAffected text box. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. End Sub Tip End Try Catch excpData As Exception MessageBox.Show("Error Occurred: " & excpData.Message) Me.txtRecsAffected.Text = ocmdPhoneUp.ExecuteNonQuery.ToString '-- Open the connection object. ocnn.Open() Try '-- Specify the name of the stored procedure ocmdPhoneUp.CommandType = CommandType.Text Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Dim ocmdPhoneUp As New OleDb.OleDbCommand(Me.txtSQL.Text, ocnn) Private Sub btnExecute_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnExecute.Click Page 134 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Use a Try…Catch…End Try block to trap any exceptions that might occur when working with ADO.NET. In this case, the error is trapped and a message box displays the error. Remember that exceptions that are not trapped will cause the application to fail. How It Works When a valid SQL statement is entered into the text box with the label Update Statement to Execute: and the Execute button is clicked, the command entered is executed, and the number of records that were affected is returned. Comments The Command object is a real workhorse when it comes to performing bulk operations, whether working with store procedures already created or when using statements that have been created on-the-fly. [ Team LiB ] Page 135 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 5. Working With Data In Web Forms In this chapter you will:          Dealing with stateless Programming Use bound controls with Web forms Validate data using validation controls Populate DropDown and ListBox controls Display data using the Table control Display data using the Repeater control Display, sort, and page data in the DataGrid control Add, edit, and delete data using the DataGrid control Hyperlink from a row in the data grid to a detail page With .NET, developing for the Web becomes easier than ever. ASP.NET is actually even fun to work with. In the past, ASP proved quite a task to develop applications in. Now, however, you can develop your Web applications in much the same way you do Windows desktop applications, with few major differences. [ Team LiB ] Page 136 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Dealing with Stateless Programming One of the big differences lies in the fact that Web pages are still inherently stateless. This means that when you move from page to page, you tend to lose the data that the pages use. Although this is not a big problem when you are creating simple Web pages that perform easy tasks, when you begin creating real applications, especially dealing with databases or data that users input, this factor can be a big hassle. State Management on the Client In the past, the statelessness of Web pages was dealt with to an extent in a number of ways on the client side:  Cookies. Small files that a Web application creates. Cookies store data on the local machines of those who are accessing the Web application. A couple of problems exist with just using cookies. First, cookies are stored on the local machine, so the machine (or browser) must allow them. Second, the type of data that can be stored in cookies is limited.  Query strings. Information that is appended to the end of a page's URL. You will see examples of this when you're creating hyperlinks and calling new Web pages.  Hidden fields. An HTML field that is hidden to the user. These are not visible to the class module either.  Control.ViewState property. Provides a dictionary object for retaining values between multiple requests for the same page. Note that this is the method that the page uses to preserve page and control property values between round trips. Although some of these management techniques have been used in ASP, they are still valid in .NET, and they are useful given the correct circumstances. When you're developing in ASP.NET, some additional solutions are available for state management. Those solutions are handled on the server side. Server-Side Solution to State Management Depending on the information that you want to retain, .NET has a number of ways to handle state management. Although you could use the methods just mentioned, a few other options are available as well:  Application state. You can save values to this object Application("ItemName") = value by using an instance of the HttpApplicationState class, but all those people who are in the application at that time will be able to see it.  Session state. This option allows you to maintain state for the individual session. This is discussed further in the next section.  Database support. SQL Server helps you to maintain state by adding values to the Temp database on the server. Using the Session Object The Session object is pretty straightforward to work with. When you assign the variable, you will use the following syntax: Page 137 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Session("SessionVariableName") = Value SessionVariableName is in fact used inside the quotes. It can be whatever you want to call it. Value can be any type of variable, including a DataTable object, as you will see in the steps that follow. Sometimes, you can stash the data table and a Boolean variable to the Session object. Following is one of the lines of code that stores the data table: Session("MyLookupData") = mdtLookupData MyLookupData is the name of the entry that is created in the Session object. mdtLookupData is the variable name of the DataTable object, declared at the module level. When you're reading a variable, you will turn the statement around and add a CType() function to convert the value to the desired type. Variable = CType(Session("SessionVariableName",Type) In the instance of a data table, such as the one used in this How-To, you would see something like this: mdtLookupData = CType(Session("MyLookupData"), DataTable) Note that you can use other conversion functions besides CType(). If you don't convert the value, then the Object type will be returned. Another task that is necessary to perform is testing whether the entry in the Session object has been made. You do this by testing the Session entry against the Nothing keyword, as seen here: 'Put user code to initialize the page here If Not (Session("MyLookupData") Is Nothing) Then mdtLookupData = CType(Session("MyLookupData"), DataTable) End If This code is used in the Load event of the page. If the entry has been created in the Session object, then the data is loaded into the variable. You can also use the opposite as well. If the entry in the Session object is Nothing, then create the entry. This is just a quick and simple way of taking advantage of the Session object. There are probably hundreds of other ways to take advantage of the Session object. For more information on this, check out Session State in the .NET Framework Developer's Guide, which is part of the help provided by Visual Studio. Type in "state management in ASP.NET" for the index to locate the Session object topic. You can find all of the examples in this chapter in the Solution called Visual Basic .NET on the Web site. Chapter 5 [ Team LiB ] Page 138 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.1 Use Bound Controls with Web Forms I want to create a Web Form that allows my users to view data much like my Windows Forms and be able to use data bound controls on it. How do I use data bound controls on a Web Form? Technique The data objects that you used in Chapter 1, "Developing Windows Forms Using Bound Controls," including OleDbDataAdapter, datasets, and so on, will be used with Web Forms as they would with Windows Forms. The main difference between Windows Forms and Web Forms in this case is the extra steps needed to handle round trips to the server from the client machines. For discussion on OleDBDataAdapters and datasets, see Chapter 1 . The IsPostBack Property One property that you will be using when you're developing Web forms is the IsPostBack property, which is used in the Load event of the Web Form. That's right Web Forms now have an event model much like Windows Forms. You can now work with the Web Form properties and Web server control properties from the Web page's class module. The IsPostBack property is set to True if the load event is fired on a round trip from the server. Therefore, the first time a Web Form is loaded, IsPostBack is False. Web Server Controls Versus HTML Controls Within ASP.NET Web Forms, you now have the ability to use either your classic HTML controls, which are available for compatibility purposes, or the new Web server controls, which, because they run on the server, have the following advantages:  You can access Web server control properties and methods from the Web Forms class module, but not with HTML controls.  Because Web server controls are rendered from the server side, on the client side they come through as pure HTML, and they are compatible with more browsers and earlier versions.  Web server controls generally have more features than their HTML counterparts, and in some cases, they can be bound to data. Note You can change some of the HTML controls to Web server controls by placing the control on the Web Form, right-clicking on the control, and choosing Run as Web Server Control from the pop-up menu. After choosing this menu option, you can see the object in your code behind your page. Note Although you will be dealing with a ListBox Web server control, it has different properties and methods than the Windows Form ListBox control. These are discussed in the following steps. Page 139 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html The AutoPostBack Property Web server controls have a property called AutoPostBack. This property tells .NET to post back to the server, which is something you need to do if you want to have an event fire off, such as the SelectedIndexChanged event of the lstCustomers list box. This is also true for Button controls that are used. The DataBind Method When you're binding Web server controls in this case, a ListBox control to data such as DataSet or DataTable objects, you need to invoke the DataBind method of the control that is being bound. You need to do this when data changes, as you will see in the following steps. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.1: Using Data Bound Controls with Web Forms. When the Web Form loads, you will see a list box filled with customers, and the details for the first customer will be displayed in the list (see Figure 5.1). Figure 5.1. Arrange the controls on the form you created to look like this form. To start off, you will be creating a Web Form that is similar to a Windows Form that was created in Chapter 1. You will actually be creating the form exactly the way you did in the first chapter with the Windows Form, with the exception of a few commands in the code. Page 140 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 1. Create a Web Form. Then place the controls listed in Table 5.1 with the following properties set. You will be using Northwind for the database to connect to. Table 5.1. Label, TextBox, ListBox, and Command Button Control Property Settings Object Property Setting OleDbDataAdapter ID SelectCommand odaCustomerList Select CustomerID, CompanyName From Customers dsCustomerList odaCustomerIndividual Select * From Customers Where Customer ID = ? DataSet ID OleDbDataAdapter ID SelectCommand ID ID DataSource DataTextField DataSet ListBox dsCustomerIndividual lstCustomers dsCustomerList CompanyName DataValueField CustomerID AutoPostBack Label Label Label Label Label Label Label Label Label Caption Caption Caption Caption Caption Caption Caption Caption Caption True Customer ID Company Name Contact Contact Title Address City Region Country Phone Page 141 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label TextBox Caption ID Text ID Text ID Text ID Text ID Text ID Text ID Text ID Text ID Text ID Fax txtCustomerID dsCustomerIndividual Customers.CustomerID txtCompanyName dsCustomerIndividual Customers.CompanyName txtContactName dsCustomerIndividual Customers.Contact txtContactTitle dsCustomerIndividual Customers.ContactTitle txtAddress dsCustomerIndividual Customers.Address txtCity dsCustomerIndividual Customers.City txtRegion dsCustomerIndividual Customers.Region txtPostalCode dsCustomerIndividual Customers.PostalCode txtCountry dsCustomerIndividual Customers.Country txtPhone TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox Page 142 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text ID Text ID NavigateURL 2. dsCustomerIndividual Customers.Phone txtFax dsCustomerIndividual Customers.Fax hplReturnToMain wfrmMain.aspx TextBox HyperLink Add the code in Listing 5.1 to the Load event of the page. (Double-click on the page to bring up the code.) The first command you see is the if statement, which tests to see whether the page is being loaded for the first time. If it is, then the dsCustomerList dataset is filled using the odaCustomerList OleDbDataAdapter. Next, the DataBind method is called. Last, the first item in lstCustomers is selected, and the RefreshIndividual routine is called, which is described in the next step. Listing 5.1 wfrmHowTo5_1.aspx.vb: Loading the Page Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Perform only the first time the page is loaded If Not Page.IsPostBack Then '-- Fill the customer list box dataset Me.odaCustomerList.Fill(Me.dsCustomerList) '-- Bind the list box to the dataset Me.lstCustomers.DataBind() '-- Pick the first customer in the list and ' display the individual's data Me.lstCustomers.SelectedIndex = 0 RefreshIndividual() End If End Sub 3. Add the code in Listing 5.2 to the class module of the page, creating the RefreshIndividual routine. The routine starts off by clearing the dataset and then tests to make sure a customer is selected. Next, the data adapter parameter is supplied with the item that is selected in lstCustomers, which will be the CustomerID. dsCustomerIndividual is filled, and the DataBind method of each of the text boxes is called. Listing 5.2 wfrmHowTo5_1.aspx.vb: Listing Detail Information About the Customers Page 143 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub RefreshIndividual() '-- Clear individual customer dataset Me.dsCustomerIndividual.Clear() If lstCustomers.SelectedIndex <> -1 Then Me.odaCustomerIndividual.SelectCommand.Parameters(0).Value = _ lstCustomers.SelectedItem.Value '-- Fill the dataset Me.odaCustomerIndividual.Fill(Me.dsCustomerIndividual, "Customers") '-- Call the DataBind method for each of the text boxes Me.txtCustomerID.DataBind() Me.txtCompanyName.DataBind() Me.txtContactName.DataBind() Me.txtContactTitle.DataBind() Me.txtAddress.DataBind() Me.txtCity.DataBind() Me.txtRegion.DataBind() Me.txtCountry.DataBind() Me.txtPostalCode.DataBind() Me.txtPhone.DataBind() Me.txtFax.DataBind() End If End Sub 4. Add the code in Listing 5.3 to the SelectedIndexChanged event of lstCustomers. Listing 5.3 wfrmHowTo5_1.aspx.vb: Calling the RefreshIndividual Routine for Each New Customer Who Is Selected Private Sub lstCustomers_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles lstCustomers.SelectedIndexChanged RefreshIndividual() End Sub Comments Using bound controls on Web Forms or unbound controls, for that matter, such as list boxes does not take much more work than it does in Windows Forms. Except for maintaining the data, binding can take more work with the round trips to the server to deal with, as you will see in How-To 5.7. [ Team LiB ] Page 144 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.2 Validate Data Using Validation Controls I want to be able to validate various types of data entry without having to wait for an error to come back from the server. Can I validate my data on my Web Form? Note A note of caution: Through the writing and tech editing of this chapter, there have been some inconsistencies noted in the reaction of some of the validator controls. The tech editor and I both contend that this area might have some .NET bugs. This is also the reason for the lack of coverage in the CustomValidator. Technique One new feature found in ASP.NET is the inclusion of Validation Web server controls. These validation controls allow you to specify other controls of which you want to validate based on data entered into the controls. You can then do the following:    Have the Validation control display an error message. Test at a page level to see if all controls that are being validated are valid. Display a list of error messages for all the controls that are being validated. Available Validation Web Server Controls You will find the controls for validation in the toolbox, and can see them listed in Table 5.2, with a description of what they validate. Table 5.2. Validation Web Server Controls Control Description Validates whether the specified control has been left blank. Compares the values in two controls and validates whether they are equal. Checks to see if the value entered into a control falls within a range that is specified. RequiredFieldValidator CompareValidator RangeValidator RegularExpressionValidator Compares a value entered into a control to see if it matches an entered mask, such as 999-99-9999, which is the U.S. Social Security Number. CustomValidator Allows you to create custom functions on both the client and server side for validation. Used to consolidate the messages that all validation controls return on a page into a list-like format. ValidationSummary Page 145 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html The main properties you will set on a validation control are FieldToValidate and ErrorMessage. Note The CustomValidator control is different in that you will create functions to perform the validation. Other than these, the validation controls require no coding unless you want to validate the whole page. Testing Page Validation in Code Depending on what is required, you can test for validation at the page level using the Page.Validate method. When you call this method, all the Validation controls are retested, and the Page.IsValid property is set. You can use the IsValid property in a condition statement to perform tasks based on the value of the IsValid property, as shown in the last step of this How-To. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.2: Validate Data Using Validation Controls. When the Web Form loads, you will see a number of text boxes with instructions on how to see the various validation checks. Here is the Web Form in Design view (see Figure 5.2). 1. Create a Web Form. Then place the controls listed in Table 5.3 and shown in Figure 5.2 with the following properties set. Table 5.3. Control Property Settings for Validation Controls Web Form Object Property Setting Required Field Validator Example (Leave Blank to Test) Label Text TextBox ID txtRequiredExampl e Compare Validator Example (Enter Two Different Values in These Text Boxes) Label Text TextBox TextBox ID ID txtCompareFirst txtCompareSecond Page 146 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label Text Range Validator Example (Enter a Number Outside the Range 1 and 10) TextBox Label ID Text txtRangeExample Regular Expression Validator Example (Enter a SSN not matching 999-99-9999) TextBox ID txtRegularExprExa mple Custom Validator Example (Enter a State Other Than WA or CA) Label Text TextBox Button ID ID Text txtCustomExample btnTestValidators Test Validators Page Validation Errors Label Text RequiredFieldValidato ToValidate r Control ErrorMessage txtRequiredExampl e Here is the message for the Required Field Validator CompareValidator ControlToCompare txtCompareFirst ControlToValidat txtCompareSecond e ErrorMessage Here is the message for the Compare Validator RangeValidator ControlToValidat txtRangeExample Page 147 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html e MaximumValue MinimumValue ErrorMessage 10 1 Here is the message for the Range Validator RegularExpressionVali ControlToValidat txtRegularExprExa dator e mple ValidationExpres \d{3}-\d{2}-\d{4} sion ErrorMessage Here is the message for the Regular Expression Validator ValidationSummary HyperLink HeaderText ID NavigateURL Error Summary List hplReturnToMain wfrmMain.aspx 2. Note For the ValidationExpression property of the RegularExpressionValidator, you will want to click the builder button beside the property and choose the SSN from the list of expressions. 3. Add the code in Listing 5.4 to the Click event of btnTestValidator. You can see an example here of how you might use the Validate method for the page, and act based on when the IsValid property is set. Listing 5.4 wfrmHowTo5_2.aspx.vbs Testing to See If All Controls That the Validation Controls Handle Are Valid Private Sub btnTestValidators_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnTestValidators.Click '-- Forces the Validation controls to validate Page.Validate() If Page.IsValid Then '-- Code if all controls are valid Page 148 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Else '-- Code if even one of the controls isn't valid End If End Sub Figure 5.2. These controls aren't seen on your Web forms unless a validation error occurs. Comments You normally wouldn't have the ValidationSummary control on the same page if you were listing the individual error messages using the Validation controls. It is nice to be able to have all the errors show up in a list sometimes. Tip You can affect the way the list looks in the ValidationSummary control by setting the DisplayMode property. You have the choice of using a list, a bulleted list, or a paragraph. You can also display a message box instead of a list by setting the ShowMessageBox property to True and the ShowSummary property to False. Note You can display one message in the individual validation controls and another in the ValidationSummary control. The ErrorMessage property is reflected in the ValidationSummary list, whereas the Text property of Page 149 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html the individual validation controls displays something different if it's set. [ Team LiB ] Page 150 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.3 Populate DropDown and ListBox Controls I saw in this chapter's first How-To how to bind a ListBox control to a dataset that was created in the design. How do I populate DropDown and ListBox controls on a Web Form using code at runtime? Technique ListBoxes and DropDowns, which are equivalent to ComboBoxes on Windows Forms, have different properties that are used for data binding than their Windows counterparts. Besides these properties, displayed in Table 5.4, you also need to use the Databind method and session object to track the data table that is created for products. Table 5.4. Properties Used to Bind Columns to Controls Property Description Column in data source to use for displaying in the DropDown or ListBox control. DataTextField DataValueField Column in data source that is the lookup value. Note You can use a property called DataFormatString to format the DataTextField data for display in the ListBox or DropDown controls. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.3: Populate DropDown and ListBox controls. When the Web Form loads, you will see a Categories dropdown with the Beverages category selected and the products for that category in the list box with the label Products. If you click on a product, the three text boxes are loaded on the right of the page (see Figure 5.3). 1. Create a Web Form. Then place the controls listed in Table 5.5 and seen in Figure 5.3 with the following properties set. Table 5.5. Control Property Settings for Validation Controls Web Form Object Property Setting Label DropDown Text ID AutoPostBack Categories: ddCategories True Page 151 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label ListBox Text ID AutoPostBack Products: lstProducts True Product ID Product Name Unit Price txtProductID Transparent txtProductName Transparent txtUnitPrice Transparent hplReturnToMain wfrmMain.aspx Label Label Label TextBox Text Text Text ID BackColor TextBox ID BackColor TextBox ID BackColor HyperLink ID NavigateURL 2. As with some of the other chapters' projects, a support routine needs to be built to create the Connection string. Called BuildCnnStr, the function can been seen in Listing 5.5. This function takes a server and database name passed to it and creates a connection string. Listing 5.5 modGeneralRoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method would be to pass back a string. The reason for this is that for some objects, you are asked for a Connection object, but for others, you are asked for just a string. 3. In the class module for the Web Form, add the following Private declaration just below the line of code that reads Web Form Designer Generated Code. Page 152 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. 5. Private mdtProducts As New DataTable() This line of code declares a DataTable object that you will use throughout the Web Form. However, in addition to using this variable, you will use the Session object to retain the data between round trips to the server. 6. Add the code in Listing 5.6 to the Load event of the page. This code creates a DataAdapter object and then fills the dtCategories DataTable object. The ddCategories DropDown control is bound to dtCategories. The LoadProducts routine is called to load the products into the lstProducts ListBox control, which is described in the next step. Finally, the Session object is checked to see if the item MyProductsTable has been saved to it, and if so, it is loaded back into the mdtProducts variable. Listing 5.6 wfrmHowTo5_3.aspx.vb: Initializing the Page Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not Me.IsPostBack Then Dim dtCategories As New DataTable() Dim odaCategories As _ New OleDb.OleDbDataAdapter( _ "Select CategoryID, CategoryName From Categories", BuildCnnStr("(local)", "Northwind")) '-- Fill the data table odaCategories.Fill(dtCategories) '-- Assign the properties and bind the dropdown. ddCategories.DataValueField = "CategoryID" ddCategories.DataTextField = "CategoryName" ddCategories.DataSource = dtCategories ddCategories.DataBind() LoadProducts() End If '-- Load the products data table back from the session variable If Not (Session("MyProductsTable") Is Nothing) Then mdtProducts = CType(Session("MyProductsTable"), DataTable) End If End Sub 7. In the class module for the page, create the LoadProducts routine that is displayed in Listing 5.7. This code looks similar to other routines that generate a DataTable object and then assign the properties to bind mdtProducts to the lstProducts ListBox control. mdtProducts is then added to the Session object for round trips to the server. Page 153 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 5.7 wfrmHowTo5_3.aspx.vb: Creating the LoadProducts Routine Private Sub LoadProducts() Dim odaProducts As New OleDb.OleDbDataAdapter( _ "Select * From Products Where CategoryID = " & ddCategories.SelectedItem.Value, _ BuildCnnStr("(local)", "Northwind")) mdtProducts.Clear() odaProducts.Fill(mdtProducts) '-- Assign the properties and bind the list box. lstProducts.DataValueField = "ProductID" lstProducts.DataTextField = "ProductName" lstProducts.DataSource = mdtProducts lstProducts.DataBind() '-- Save the data table out to a session variable for round trips Session.Item("MyProductsTable") = mdtProducts End Sub 8. Add the code in Listing 5.8 to the SelectedIndexChanged event off the ddCategories DropDown control. Listing 5.8 wfrmHowTo5_3.aspx.vb: Calling the LoadProducts Routine When a New Category Is Chosen Private Sub ddCategories_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles ddCategories.SelectedIndexChanged LoadProducts() End Sub 9. Add the code in Listing 5.7 to the SelectedIndexChanged event off of lstProducts. This code takes the SelectedIndex property of the lstProducts ListBox control and helps retrieve the row in the DataTable object. The individual columns are then loaded into the corresponding text boxes on the page. Listing 5.9 wfrmHowTo5_3.aspx.vb: Locating the Row in the mdtProducts DataTable Object Private Sub lstProducts_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles lstProducts.SelectedIndexChanged With mdtProducts.Rows(lstProducts.SelectedIndex) txtProductID.Text = .Item("ProductID") Page 154 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html txtProductName.Text = .Item("ProductName") txtUnitPrice.Text = .Item("UnitPrice") End With End Sub Figure 5.3. DropDown and ListBox controls used to display data on this Web Form. Comments One of the main items to note, besides the use of the Session variables, is the use of the ddCategorie.SelectedItem.Value and lstProducts.SelectedIndex. These are two ways to use items that are selected in the DropDown and ListBox objects, respectively. After you have used the Session object to keep variables during round trips to the server, it becomes more intuitive as you use it. [ Team LiB ] Page 155 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.4 Display Data Using the Table Control .NET has a number of controls available for displaying data. How do I know which control to use to display data, and how do I use the Table control to display data? Technique When you're first deciding to list data on your Web forms, you have a few Web server controls to choose from:  Table. This Web server control allows you to create a read-only table type display of data. This control is not data bound, and it uses the TableColumn and TableRow objects for creation.  Repeater. This control is used to display read-only lists. You can use hyperlinks and program the ItemCommand event so that you can perform actions when items are selected. You must use templates to format the display. Templates are discussed in How-To 5.5, as is the Repeater control. This is a great control for quick lists.  DataList. Using this control, you will use templates not only to display, but also to select and edit data in the list.  DataGrid. By far, this is the most powerful of the controls. In addition, it gives you the most control over manipulating data. You display, sort, edit, and use various types of controls in each column. The last three How-Tos in this chapter thoroughly cover the DataGrid control. Anatomy of the Table Web Server Control You can create the Table Web server control at design time, or as shown in this How-To, at runtime. The control is created by adding the TableRows and TableCells to the Table control. The TableRows and TableCells are controls in their own right. You can see the objects, properties, and methods that you will use to create the Table Web server control in Table 5.6. Table 5.6. Using a Standard Method of Creating Objects Within Objects to Construct a Table Web Server Control Object Property Description TableCell Controls Controls are added to an individual TableCell object using the Add method of the Controls collection. In this example, a LiteralControl object is used to display information. TableRow Cells The Add method of the TableRow.Cells collection adds a new cell to the TableRow. Table Rows The Add method of the Table.Rows adds the TableRow object to the collection of rows for the Table control. You will see these objects and methods used in step 4. Note One of the issues with using the Table control is that it does not persist in trips to the server and back. Therefore, you need to reconstruct the Page 156 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html control in the page Load event, checking with the IsPostBack property. If you are tracking a lot of changes with the Table control, this is another good reason to use one of the other controls listed at the beginning of this technique. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.4: Display Data Using the Table Control. When the Web Form loads, you will see a DropDown control displaying the list of categories. Below the DropDown control, you will see a Table control with the products for the selected category (see Figure 5.4). 1. Create a Web Form. Then place the controls listed in Table 5.7 and seen in Figure 5.4 with the following properties set. Table 5.7. Property Settings for Label, DropDown, and Table Controls Object Property Setting Label DropDown Text ID AutoPostBack Categories: ddCategories True tblProducts Both hplReturnToMain wfrmMain.aspx Table ID GridLines HyperLink ID NavigateURL 2. Add the code in Listing 5.10 to the Load event of the page. If the page is first being loaded, then the dtCategories is filled and bound to the ddCategories dropdown. Last, the LoadProducts routine is called, which is described in the next step. Listing 5.10 wfrmHowTo5_4.aspx.vb: Loading the Categories DropDown and Product Table Controls Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not Me.IsPostBack Then Dim dtCategories As New DataTable() Page 157 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim odaCategories As _ New OleDb.OleDbDataAdapter( _ "Select CategoryID, CategoryName From Categories", BuildCnnStr("(local)", "Northwind")) '-- Fill the data table, and bind it to the dropdown. odaCategories.Fill(dtCategories) ddCategories.DataValueField = "CategoryID" ddCategories.DataTextField = "CategoryName" ddCategories.DataSource = dtCategories ddCategories.DataBind() LoadProducts() End If End Sub 3. In the page's class module, create the LoadProducts routine shown in Listing 5.11. After creating a DataTable object called dtProducts and filling it with a DataAdapter object, the number of columns in the dtProducts is stored in intNumCols. A TableRow object is then created, which will be used for the heading row of the table. It displays the column heads. Then, for each of the columns, a TableCell object called tcHead is created. A LiteralControl is added to it, which is derived from the ColumnName property of the data table for each column. Each TableCell object is then added to the TableRow object. After all the columns have been added, the TableRow object called trHead is added to the tblProducts Table control. After the table headings have been created, the same commands are created for each row in the DataTable object. Listing 5.11 wfrmHowTo5_4.aspx.vb: Loading the Categories DropDown and Product Table Controls Private Sub LoadProducts() Dim dtProducts As New DataTable() Dim drCurr As DataRow Dim intCurrRow As Integer Dim intCurrCell As Integer Dim intNumCols As Integer Dim odaProducts As New OleDb.OleDbDataAdapter( _ "Select * From Products Where CategoryID = " & ddCategories.SelectedItem.Value, _ BuildCnnStr("(local)", "Northwind")) odaProducts.Fill(dtProducts) intNumCols = dtProducts.Columns.Count Page 158 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Create the headings for the displayed table Dim trHead As New TableRow() For intCurrCell = 0 To intNumCols - 1 Dim tcHead As New TableCell() tcHead.Controls.Add(New LiteralControl(dtProducts. _ Columns(intCurrCell).ColumnName)) trHead.Cells.Add(tcHead) Next tblProducts.Rows.Add(trHead) '-- Add the rows and cells For intCurrRow = 0 To dtProducts.Rows.Count - 1 drCurr = dtProducts.Rows(intCurrRow) Dim trNew As New TableRow() For intCurrCell = 0 To intNumCols - 1 Dim tcNew As New TableCell() tcNew.Controls.Add(New LiteralControl(drCurr.Item(intCurrCell))) trNew.Cells.Add(tcNew) Next intCurrCell tblProducts.Rows.Add(trNew) Next intCurrRow End Sub 4. Add the code in Listing 5.12 to the SelectedIndexChanged event of ddCategories. Listing 5.12 wfrmHowTo5_4.aspx.vb: Loading the Categories DropDown and Product Table Control Private Sub ddCategories_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles ddCategories.SelectedIndexChanged LoadProducts() End Sub Figure 5.4. Using the Table control to display tables takes a lot of work. Page 159 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments You can see from this example that using the Table Web server control takes a bit of work, and if you have a lot of data to display, it could take quite a while to build. Also, remember that you can't edit the data that is built into the control. If you have just a small amount of data to display, the Table Web server control could work out nicely. [ Team LiB ] Page 160 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.5 Display Data Using the Repeater Control I have heard that the Repeater control is a great control for displaying a read-only list of values, including hyperlinks. How do I populate a Repeater control and take advantage of templates to display the data the way I want it to look? Technique The Repeater control allows you to list data in various formats, such as bulleted or numbered. It relies on the use of templates to display information in a list format. This How-To shows you how to use the Repeater control not only to display a list, but also to use a couple of different controls a Button and HyperLink to display another list using the Repeater control. The second list will be displayed using the button on the same page as the first list. The hyperlink will take you to another page to display the second list. A main tool in the creation of the Repeater control is the use of templates. Use of Templates Templates are used within HTML and allow you to include controls in your ASP.NET Web server controls. Within a template, you can specify various details about the area for which you are creating a template. Following is a list of the templates:      HeaderTemplate ItemTemplate FooterTemplate AlternatingItemTemplate SeparatorTemplate You can get an idea of what each of the templates is used for by its name. Here is an example of the HeaderTemplate, used in this How-To: List of Regions
These lines are literally used as a template for how you want the section to be laid out, as well as what data to display. For the ItemTemplate in this How-To, two controls are displayed: a button and a hyperlink, shown by this snippet of the HTML: As the name implies, the DataBinder supplies data from the data source that is specified for the Repeater object. You will see how to bind the Repeater object in step 3. Page 161 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Creating URLs On-the-Fly In the NavigateURL of the hyperlink that was created, you can see the column DataItem.RegionURL being used. This is not a column that is found in the Regions table in Northwind. This column is created within the SQL statement that is supplied to a data adapter, by the following line of code: odaRegions = New OleDb.OleDbDataAdapter("Select RegionID, _ 'wfrmHowto5_5b.aspx?RegID=' + Cast(RegionID as Char(2)) As RegionURL, RegionDescription From Region", BuildCnnStr("(local)", "Northwind")) The RegionURL consists of a Web Form name and the statement ?RegID=Cast(RegionID as Char(2)), which ASP.NET loads into the new page and passes to the RegionID of the page, letting the code within the page read the RegionID using the Request object, as displayed here: odaTer = New _ OleDb.OleDbDataAdapter(_ "Select TerritoryDescription From Territories Where RegionID = " & Request.Item("RegID"), _ BuildCnnStr("(local)", "Northwind")) You will see both the creation and utilization of the URL in the steps that follow. Programming Repeater Events by Using ItemCommand When you're using buttons, you can program the response for when the buttons are pressed by using the ItemCommand event. This event is raised for all the controls that are used in the Repeater. You will see an example of this in step 5. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.4: Display Data Using the Repeater Control. You will then see a page open displaying a list of the regions (see Figure 5.5). Figure 5.5. This list includes both a button, displaying the RegionID, and a hyperlink, displaying the region description. Page 162 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html If you click one of the buttons displaying the Region ID, then another list is displayed using the Repeater control. This list is displayed below the regions and contains the territories for the region clicked (see Figure 5.6). Figure 5.6. Another Repeater control is utilized for this list of territories. When you click on the hyperlinks in the list, another page displays, with yet another Repeater control used to display the territories for the region chosen (see Figure 5.7). 1. Create a Web Form. Then place the controls listed in Table 5.8 with the following properties Page 163 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html set. Table 5.8. Property Settings Repeater and HyperLink Controls Object Property Setting Repeater Repeater HyperLink ID ID ID NavigateURL repRegions repTeritories hplReturnToMain wfrmMain.aspx 2. Switch to the HTML tab in the designer. By adding the repeaters and naming the repeaters in step 1, you will see a line of code that looks like this: 3. 4. Replace this line of code with the code displayed in Listing 5.13. This code lays out the templates that were described in the "Technique" section, as well as the button and hyperlink described. Note that the FooterTemplate, listed here, is not really used for anything. It was included so that you could see how to use it. It can be excluded. Listing 5.13 wfrmHowTo5_5a.aspx: HTML for the repRegions Repeater List of Regions

5. Next, replace the HTML code inserted for the repTerritories repeater with the code in Listing 5.14. After the HeaderTemplate is specified, a Label control displays the TerritoryDescription column. Listing 5.14 wfrmHowTo5_5a.aspx: HTML for the repTerritories Repeater Page 164 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
List of Territories

6. Add the code in Listing 5.15 to the Load event of the page. If the page is first being loaded, then the odaRegions DataAdapter fills the data table called dtRegions. dtRegions is set as the data source for repRegions, and DataBind method is called, binding the Repeater to the data table. Listing 5.15 wfrmHowTo5_5a.aspx.vb: Loading the repRegions Repeater Control Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not Me.IsPostBack Then Dim odaRegions As OleDb.OleDbDataAdapter Dim dtRegions As DataTable odaRegions = New OleDb.OleDbDataAdapter("Select RegionID, _ 'wfrmHowto5_5b.aspx?RegID=' + Cast(RegionID as Char(2)) As RegionURL, _ RegionDescription From Region", BuildCnnStr("(local)", "Northwind")) dtRegions = New DataTable() odaRegions.Fill(dtRegions) repRegions.DataSource = dtRegions repRegions.DataBind() End If End Sub 7. Add the code in Listing 5.16 to the ItemCommand event of repRegions. This code takes the Text property of the button, which is the RegionID, and uses it in the SQL string to supply the odaTer data adapter. Next, odaTer fills dtTer, which is then used as the data source for repTerritories. Listing 5.16 wfrmHowTo5_5a.aspx.vb: Loading the Categories DropDown and Product Table Control Page 165 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub repRegions_ItemCommand(ByVal source As Object, _ ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles repRegions.ItemCommand Dim odaTer As OleDb.OleDbDataAdapter Dim dtTer As DataTable odaTer = New _ OleDb.OleDbDataAdapter(_ "Select TerritoryDescription From Territories Where RegionID = " & CType(e.CommandSource, Button).Text(), _ BuildCnnStr("(local)", "Northwind")) dtTer = New DataTable() odaTer.Fill(dtTer) repTerritories.DataSource = dtTer repTerritories.DataBind() End Sub 8. Create another Web Form. Then place a Repeater control on it and set the ID of the Repeater to be repTerritories. Note When you are saving and naming the Web Form created in this step, make sure you name it the same as that used in the code in step 4. Remember that it was the Web Form used in the RegionURL. 9. Switch to the HTML tab in the designer. Replace the line of code that has been created for the repTerritories Repeater control with the code shown in Listing 5.17. Listing 5.17 wfrmHowTo5_5b.aspx: HTML for the repTerritories Repeater on the Second Web Form
List of Terriories

Page 166 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 10. Add the code in Listing 5.18 to the Load event of the page. This code reads the RegionID first from the first Web Form using the Request object. Next, it is used to fill the dtTer data table, which is then assigned as the data source for repTerritories. Listing 5.18 wfrmHowTo5_5b.aspx.vb: Loading the repTerritories Repeater Control on the Second Web Form Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim odaTer As OleDb.OleDbDataAdapter Dim dtTer As DataTable odaTer = New OleDb.OleDbDataAdapter(_ "Select TerritoryDescription From Territories Where RegionID = " & Request.Item("RegID"), _ BuildCnnStr("(local)", "Northwind")) dtTer = New DataTable() odaTer.Fill(dtTer) repTerritories.DataSource = dtTer repTerritories.DataBind() End Sub Figure 5.7. A third Repeater control is utilized for this list of territories on a new page. [ Team LiB ] Page 167 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Comments After you have used DataRepeater a couple of times, it is really quite simple to use. By playing with the templates, you can display fairly attractive lists that are nice and dynamic. [ Team LiB ] Page 168 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.6 Display, Sort, and Page Data in the DataGrid Control The Table controls and DataRepeater are fine when I have small sets of data, but the display just keeps repeating and I have to write a bunch of code to change the sort order of the data. How do I create a table-like display that will show a set number of rows at a time and let me sort the data? Technique The DataGrid control is by far the most flexible and powerful of the controls used in ASP.NET for displaying data on your Web page. It gives you the ability not only to list data, but also to page through it and sort it nicely with headers, and even to edit data. This last feature will be saved for the next How-To. To perform the other tasks, you will use a combination of setting properties at design time and programming some events. In particular for the DataGrid control, you will add code to events raised by sorting and paging. This How-To will use the DataGrid bound at design time. You will also see a simple example of using the DataView object for sorting your data. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.6: Display, Sort, and Page Data in the DataGrid Control. You will then see all the territories loaded into a data grid. You can click the column headings, displayed in blue, to sort the columns, and you can click the arrows at the bottom to page through the data. You can see the Web Form in Design mode in Figure 5.8. 1. Create a Web Form. Then place the controls in Table 5.9 and Figure 5.8 with the following properties set. Table 5.9. Property Settings for the Controls Used in This How-To Object Property Setting OleDbDataAdapt ID er odaTerritory SelectComma SELECT nd Territories.TerritoryID, Territories.TerritoryDescript ion, Region.RegionDescription, Region.RegionID FROM Territories INNER JOIN Region ON Territories.RegionID = Region.RegionID Page 169 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataSet DataView ID ID Table dsTerritory dvTerritory dsTerritory.Territories dgTerritory hplReturnToMain DataGrid HyperLink ID ID NavigateURL wfrmMain.aspx 2. Right-click on the DataGrid control and choose Property Builder. You will then see the General tab of the DataGrid Property Builder. Set the properties as displayed in Figure 5.9. Figure 5.9. Setting the General properties of the DataGrid control. 3. Click on the Columns tab. You can now add the columns TerritoryID, TerritoryDescription, and RegionDescription by clicking on the field in the available columns and then clicking the Add button for each one. You can then set the Header text for each to be TerritoryID, Territory, and Region respectively, by clicking on the column in the Selected Column list and changing the Header text property. When you are finished and you have the Region highlighted, it should look like Figure 5.10. Figure 5.10. Setting the columns for the DataGrid control is easy at design time. Page 170 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Note Be sure to uncheck the Create Columns Automatically at Run Time check box; otherwise, the columns will end up showing up twice once from you specifying them here at design time, and once when the code generates them. 4. Click on the Paging tab. Click on the Allow Paging check box, and type 10 for the Page Size (see Figure 5.11.) You can then close the Property Builder dialog box by clicking OK. Figure 5.11. Setting the Paging properties at design time for the DataGrid control. Page 171 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 5. Create the BindTheGrid routine in Listing 5.19. Note that you are now binding to the DataView, rather than to a dataset. Listing 5.19 wfrmHowTo5_6.aspx.vb: Binding the Data Grid to the DataView Control Sub BindTheGrid() odaTerritory.Fill(dsTerritory) dgTerritory.DataSource = dvTerritory dgTerritory.DataBind() End Sub 6. Add the code in Listing 5.20 to the Load event of the page. Listing 5.20 wfrmHowTo5_6.aspx.vb: Loading the Page Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not Me.IsPostBack Then BindTheGrid() End If Page 172 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 7. Add the code in Listing 5.21 to the PageIndexChanged event of dgTerritory. This routine takes the NewPageIndex and assigns it to the data grid's CurrentPageIndex. Next, if MySort exists in the ViewState object, it is assigned to the DataView control. MySort is stored in the next step. Listing 5.21 wfrmHowTo5_6.aspx.vb: Paging the Data Grid Private Sub dgTerritory_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles dgTerritory.PageIndexChanged '-- Set the current page in the data grid Me.dgTerritory.CurrentPageIndex = e.NewPageIndex If Not (ViewState("MySort") = Nothing) Then dvTerritory.Sort = ViewState("MySort") End If BindTheGrid() End Sub 8. Add the code in Listing 5.22 to the SortCommand event of dgTerritory. When a column heading is clicked and sorting is turned on, this event is raised. This routine assigns the SortExpression to the Sort property of the dgTerritory. The SortExpression property is then stored in the ViewState object for round trips to the server, and then it is used in the code listed in step 6. Listing 5.22 wfrmHowTo5_6.aspx.vb: Sorting the Data Grid Private Sub dgTerritory_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles dgTerritory.SortCommand dvTerritory.Sort = e.SortExpression.ToString ViewState("MySort") = e.SortExpression.ToString BindTheGrid() End Sub Figure 5.8. The DataGrid control is a great way to manipulate data. Page 173 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments The DataView is a great control for seeing different views of your data by using a single dataset. As with the DataRepeater, working with some of the basic features in the data grid is pretty easy. It's when you have to start really manipulating data that it gets more difficult, as you will see in the next How-To. [ Team LiB ] Page 174 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.7 Add, Edit, and Delete Data Using the DataGrid Control The Table controls and DataRepeater are fine when I have small sets of data, but the display just keeps going on and on, and I have to write a bunch of code to change the sort order of the data. How do I create a table-like display that will show a set number of rows at a time and let me sort the data? Technique One of the nice things about the DataGrid control that makes it so much more powerful than the other list controls is its ability to add, edit, and delete directly within the control. This How-To shows you how to create columns to manage your data using the DataGrid control. Adding Buttons to the DataGrid Control You will use the DataGrid control with more code this time so that you can work with data more. You will also be adding a couple of buttons to the DataGrid display to allow you to edit, delete, and update data. You will add buttons to the data grid by right-clicking on the control, choosing Property Builder, and then choosing the Columns tab. You can then select from the list of button types (see Figure 5.12). Figure 5.12. The buttons listed in Selected Columns are being used for this example. Note Be sure to leave the Create Columns Automatically at Run Time check box checked. Unless you specify other columns or have the data loaded at run-time, you will end up with just the buttons, which would be pretty Page 175 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html boring. Using Events with Buttons on the Data Grid After you have selected to include buttons in the data grid, you not only have to add the code to the events for the specific buttons, but you also have to make sure that ASP.NET knows the events to use. You can do this in a couple of ways. One way is to set the AutoEventWireUp attribute of the page to True. You can see this attribute in the first line of the Web page. By default, the attribute is set to False. After you add the buttons to the data grid, you will see the buttons in the DataGrid control. <%@ Page Language="vb" AutoEventWireup="false" Codebehind="wfrmHowTo5_7.aspx.vb" Inherits="VB.NET__Chapter_5.wfrmHowTo5_7"%> However, a couple of disadvantages result from setting the AutoEventWire:   You have to use the required names for your events. Events sometimes end up being called twice on the form. Microsoft recommends not setting the AutoEventWireUp to True. The other alternative is to add the events and HTML tags yourself. You will see the HTML code added in step 3. Loading a Schema into a Data Table Another option that is introduced in this How-To is the fill of a data table by using the FillSchema method of the data adapter. This means that the data table will be smart and know what the constraints and properties of the columns are before you try to save the data back to the server. The big benefit with using the FillSchema method with the DataGrid control is that it will be intelligent, and it won't let a user try to edit an auto increment column, such as an identity column. It will make such a column disabled. When you update the columns from the data grid back into the data table, you can also check to see if the column's AutoIncrement property is True. Unless you use the FillSchema method, the AutoIncrement property will come back False, even if the actual column in the table on the server has it set to True. Additional Objects, Properties, and Methods Used to Handle Data In addition to the FillSchema method of the data adapter, you will also use the Update method, which will call the Update, Delete, or Append statement, depending on the task that is being performed. The CommandBuilder object will generate your SQL statements used to send modifications back to the server. Page 176 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html In addition to the methods mentioned for the data adapter, you will use some properties and methods of the data table to add, edit, and delete data. You can see a list of those objects, properties, and methods in Table 5.10. Table 5.10. Objects, Properties, and Methods of the DataTable Object Object Property/Method Description Deletes a row from the DataTable object (the data is not deleted from the server at this point). DataTable.Rows Delete DataTable.Rows Count Returns the number of rows that are currently in the DataTable object. Creates a new DataRow object. Adds the DataRow object to the DataTable object. Turns off the schema checking that occurs when you're adding the new row to the DataTable object. Resets the DataTable status, including ending edits on DataTable NewRow DataTable.Rows Add DataTable BeginLoadData DataTable AcceptChanges DataRow objects. The DataRowState also changes. All added and modified rows become unchanged, and deleted rows are removed. DataTable RejectChanges Rejects the changes made since the last AcceptChanges was called. Lets you roll back changes if errors occur. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.7: Add, Edit, and Delete Data Using the DataGrid Control. You will then see all the regions loaded into a data grid. You can click on the Edit button to edit data, and so on. You can see the form created in Design view in Figure 5.13. 1. Create a Web Form. Then place the controls in Table 5.11 and Figure 5.13 with the following properties set. Don't worry about the Edit and Delete buttons displayed until the next step. Table 5.11. Property Settings for the Controls Used in This How-To Object Property Setting DataGrid Button Label ID ID ID ForeColor dgRegion btnAdd lblDispExcp #C00000 hplReturnToMain HyperLink ID Page 177 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html NavigateURL 2. wfrmMain.aspx Right-click on dgRegion, and choose Property Builder from the pop-up menu. Click on the Columns tab. You are going to add Edit, Update, Cancel (one button choice), and Delete buttons, as displayed in Figure 5.12. Change the ButtonType of each button to PushButton. After you have selected the buttons, click OK. 3. Now it's time to add the HTML code to connect the buttons to some code you will add in the following steps. In Listing 5.23, you can see the final HTML for the DataGrid control. The lines of code that you will need to add are the ones for OnUpdateCommand, OnCancelCommand, OnEditCommand, and OnDeleteCommand. By entering these lines as they are listed and creating the events as named, your code will work for the buttons in the DataGrid control. You will then add code behind in the following steps that will match these commands. Listing 5.23 wfrmHowTo5_7.aspx: Wiring Up Events for the DataGrid Control 4. Now it's time to add some Visual Basic code. In the class module behind the Web Form, add the following line of code just after the region that says Web Form Designer Generated Code. mdtRegion will be used throughout the form for managing the data and synchronizing with the data grid. mdtRegion will also be saved to the Session object (called RegionDT) for round trips to the server and back. You will see this in the next step. 5. 6. 7. Dim mdtRegion As New DataTable() Add the code in Listing 5.24 to the Load event of the Page. The task that occurs is checking for the existence of RegionDT in the Session object. If it exists, then this is a round trip, and you don't need to reload the data from the server. If it doesn't exist, then the Region table Schema is supplied using the FillSchema method, and then the DataTable object is filled. Next, the RegionDT and IsAdding Session variables are saved. The IsAdding session variable is used to track whether you are adding a record. Last, the data is bound to the DataGrid object using the BindTheGrid routine, which follows the Page_Load event in this listing. Listing 5.24 wfrmHowTo5_7.aspx.vb: Initially Loading the DataGrid Object and Tracking Session Variables Page 178 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If (Session("RegionDT") Is Nothing) Then Dim odaRegion As OleDb.OleDbDataAdapter odaRegion = New _ OleDb.OleDbDataAdapter("Select RegionID as [Region ID], " & "RegionDescription as Region From Region", _ BuildCnnStr("(local)", "Northwind")) odaRegion.FillSchema(mdtRegion, SchemaType.Source) odaRegion.Fill(mdtRegion) Session("RegionDT") = mdtRegion Session("IsAdding") = False BindTheGrid() Else mdtRegion = CType(Session("RegionDT"), DataTable) End If End Sub Sub BindTheGrid() dgRegion.DataSource = mdtRegion dgRegion.DataBind() End Sub Tip To figure out when the page is going back to the server, put a break point in the Page_Load event code. Then you can see the code break whenever you go back to the server. If you note which routine you were in before you went back to the server, you can then place code in it to save any data you need to. 8. Create the dgRegion_EditCommand routine as shown in Listing 5.25. This is one of the events specified in step 3. This code sets the EditItemIndex of the DataGrid object to the selected item and then binds the data. Page 179 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 5.25 wfrmHowTo5_7.aspx.vb: Setting the Data Grid to Edit Mode Sub dgRegion_EditCommand(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) '-- Clear the error display lblDispExcp.Text = "" '-- Turn on the editing by pointing the EditItemIndex ' to the ItemIndex dgRegion.EditItemIndex = e.Item.ItemIndex BindTheGrid() End Sub 9. Add the code in Listing 5.26 to the Click event of btnAdd. The first task is to invoke the BeginLoadData method for mdtLookupData. This turns off constraint checking while you're loading data. You should turn this off so that it doesn't check for required fields until you actually edit the record, which is caused by the line of code setting the EditItemIndex property of the DataGrid object. The Session variables are then updated, with the IsAdding item set to True. Lastly, the EditItemIndex of dgLookupData is then set, and the DataGrid bound to the data table using the BindTheGrid routine. Listing 5.26 wfrmHowTo5_7.aspx.vb: Adding a New Record to the Data Table Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAdd.Click Dim intColCnt As Integer Dim drCurr As DataRow lblDispExcp.Text = "" mdtRegion.BeginLoadData() '-- Add the row to the data table via the data row drCurr = mdtRegion.NewRow mdtRegion.Rows.Add(drCurr) '-- Set the Adding flag. Session("MyLookupData") = mdtRegion Session("IsAdding") = True '-- Set the item index based on the rows on this page only. dgRegion.EditItemIndex = mdtRegion.Rows.Count - 1 BindTheGrid() Page 180 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 10. Create the dgRegion_DeleteCommand routine as shown in Listing 5.27. This is one of the events specified in step 3. This code is a lot like the code in the previous step, when the record was being added. The big difference in this step's code listing is that the deletion is posted back to the server, and in step 7, it wasn't. The deletion wasn't posted in that step because the server never knew anything about the record; it had only been added to the data table and not sent back to the server. You can see the data being updated back to the server for the add and edit in the next step. One other item to note is the RejectChanges method called in the Catch of the exception handling code. This way, if an error occurs, then the change is undone, the message is noted, and life goes on. The rest of this code follows pretty closely what was done in the previous step. Listing 5.27 wfrmHowTo5_7.aspx.vb: Deleting a Row in the Data Grid Sub dgRegion_DeleteCommand(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) Dim intColCnt As Integer Dim cnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) '-- Create the command builder to update (post) the data ' in the data grid back to the server. Dim odaRegion As OleDb.OleDbDataAdapter Try '-- Take the txtSQLString text and create the data table, ' and then set the data source of the data grid. odaRegion = New _ OleDb.OleDbDataAdapter("Select RegionID as [Region ID], " & "RegionDescription as Region From Region", cnn) Dim ocbRegion As OleDb.OleDbCommandBuilder = _ New OleDb.OleDbCommandBuilder(odaRegion) '-- Delete the row from the data table mdtRegion.Rows(e.Item.ItemIndex).Delete() '-- Commands necessary to actually post back to server. cnn.Open() odaRegion.Update(mdtRegion) mdtRegion.AcceptChanges() cnn.Close() Page 181 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Session("MyLookupData") = mdtRegion Session("IsAdding") = False '-- Just in case they were editing and press Delete, Clear. dgRegion.EditItemIndex = -1 Catch excp As Exception lblDispExcp.Text = excp.Message mdtRegion.RejectChanges() End Try BindTheGrid() End Sub 11. Create the dgRegion_UpdateCommand routine as shown in Listing 5.28. This is one of the events specified in step 3. This routine starts off by declaring DataAdapter and CommandBuilder objects to update your data back to the server. Before the actual update, however, the current row that is being edited in the data grid is assigned to a DataRow object. Then each of the items in the row is saved from the data grid cells to the column in the data row. Thanks to using the FillSchema method when you're filling the data table, the AutoIncrement property will reflect whether a column is an Identity column. If the FillSchema method is not used, you have to handle the exception that occurs when you try to write the value to the column. When you're writing the cells into the columns of the data row, the Trim function is used. Because of using the FillSchema method, the values are padded out as SQL Server columns generally are. The rest of the code runs similarly to step 8 in that the changes are accepted, written back to the server, and so forth. Listing 5.28 wfrmHowTo5_7.aspx.vb: Updating Changes Back to the Server Sub dgRegion_UpdateCommand(ByVal sender As Object, ByVal e As DataGridCommandEventArgs) Dim intColCnt As Integer Dim intColCurr As Integer Dim drCurr As DataRow Dim cnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Dim blnAdding As Boolean Dim strCurrValue As String '-- Create the command builder to update (post) ' the data in the data grid back to the server. lblDispExcp.Text = "" Page 182 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim odaTableData As OleDb.OleDbDataAdapter Try '-- Take the txtSQLString text and create data table; then set the ' data source of the data grid. Dim odaRegion As New _ OleDb.OleDbDataAdapter("Select RegionID as [Region ID], " & "RegionDescription as Region From Region", cnn) Dim ocbTableData As OleDb.OleDbCommandBuilder = _ New OleDb.OleDbCommandBuilder(odaRegion) drCurr = mdtRegion.Rows(dgRegion.EditItemIndex) '-- Update the fields in the rows intColCnt = e.Item.Cells.Count For intColCurr = 2 To intColCnt - 1 If mdtRegion.Columns(intColCurr - 2).AutoIncrement = False Then drCurr.Item(intColCurr - 2) = _ Trim(CType(e.Item.Cells(intColCurr).Controls(0), _ TextBox).Text) End If Next '-- Commands necessary to actually post back to server. cnn.Open() odaRegion.Update(mdtRegion) mdtRegion.AcceptChanges() cnn.Close() Session("RegionDT") = mdtRegion Session("IsAdding") = False dgRegion.EditItemIndex = -1 BindTheGrid() Catch excp As Exception lblDispExcp.Text = excp.Message End Try Page 183 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 12. Create the dgRegion_CancelCommand routine as shown in Listing 5.29. This is one of the events specified in step 3. If you're in the middle of adding an entry, this code uses the EditItemIndex of the DataGrid object to the selected item. The value that EditItemIndex returns is used to position the pointer in mdtLookupData so that the Delete method can be called. After the code accepts the changes, it resaves the session variables and cleans up the page index for the DataGrid object by comparing the current page number relative to the pointer of the DataTable position to the CurrentPageIndex property. Regardless of whether the item is being added or edited, the code clears EditItemIndex by setting it to 1 and it rebinds the data grid by calling BindTheData(). Listing 5.29 wfrmHowTo5_7.aspx.vb: Cancelling Edits to the Data Grid Sub dgRegion_CancelCommand(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) Dim blnAdding As Boolean '-- If you cancel while you're adding a record, you need to back the ' ' row out of the data table and data grid. You don't have to send it to the server because it really was never added to it. lblDispExcp.Text = "" If CType(Session("IsAdding"), Boolean) Then mdtRegion.Rows(dgRegion.EditItemIndex).Delete() mdtRegion.AcceptChanges() Session("IsAdding") = False Session("RegionDT") = mdtRegion End If dgRegion.EditItemIndex = -1 BindTheGrid() End Sub Figure 5.13. The DataGrid control is a great way to manipulate data. Page 184 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Whew! This seems like a lot of work! The good news is that after you have created the code, you can cut and paste when you're creating new pages that use the same techniques. Remember that this How-To is a starting part, and it's by no means bullet proof. It is up to you to take this code to the next level. [ Team LiB ] Page 185 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 5.8 Hyperlink from a Row in the Data Grid to a Detail Page Often, I need to zero in and display data based on a record in the DataGrid control. How do I display detail information in a separate page from a DataGrid control? Technique One of the types of columns that you can use in the data grid is the HyperLink column. This column makes it fairly easy to link pages based on data. To see how the HyperLink type column is used in this How-To, take a look at Figure 5.14. Figure 5.14. No code is required for link pages based on data. By your specifying the URL Field to be ProductID and URL Format String to be wfrmHowTo5_8b.aspx?ID={0}, the data grid automatically calls the wfrmHowTo5_8b.aspx and passes the ProductID to the form when you click on a product. Steps Open and run the Visual Basic .NET Chapter 5 solution. From the main page, click on the hyperlink with the caption How-To 5.8: Hyperlink From a Row in the Data Grid to a Detail Page. You then see all the products loaded into a data grid. Notice that the products are actually hyperlinks (see Figure 5.15). Figure 5.15. These hyperlinks require no code to call a detail page. Page 186 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When you click on a product, another page is displayed, with detail information supplied (see Figure 5.16). 1. Create a Web Form. Then place the controls in Table 5.12 and Figure 5.15 with the following properties set. Table 5.12. Property Settings for the Controls Used on the First Page of This How-To Object Property Setting OleDbDataAdapter ID odaProducts SelectCommand SELECT ProductID, ProductName FROM Products DataSet DataGrid ID ID DataSource DataKeyField DataMember HyperLink ID NavigateURL dsProducts dgProducts dsProducts ProductID Products hplReturnToMain wfrmMain.aspx Page 187 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 2. Right-click on the DataGrid control and choose Property Builder. Click on the Columns tab and set the properties as displayed in Figure 5.14. Be sure to note the name of the form you are calling in the URL Format String so that you can name it the same in step 4. 3. Add the code in Listing 5.30 to the Load event of the page. Listing 5.30 wfrmHowTo5_8a.aspx.vb: Filling and Binding the Products to the DataGrid Object Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here odaProducts.Fill(DsProducts) dgProducts.DataBind() End Sub 4. Create another Web Form. Then place the controls in Table 5.13 and Figure 5.16 with the following properties set. Table 5.13. Property Settings for the Controls Used on the Second Page of This How-To Object Label Label TextBox TextBox 5. Property Text Text ID ID Setting Product Name Unit Price txtProductName txtUnitPrice Add the code in Listing 5.31 to the Load event of the page. In the SQL select statement created in this listing, the Request.Item is used to grab the productID that was passed from the first form. The dtProdIndiv data table is filled, and the individual column information is loaded into the text boxes. Listing 5.31 wfrmHowTo5_8b.aspx.vb: Loading the Detail Information Based on the ProductID Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Dim odaProdIndiv As OleDb.OleDbDataAdapter odaProdIndiv = New _ OleDb.OleDbDataAdapter(_ "Select * From Products Where ProductID = " & Page 188 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Request.Item("ID"), BuildCnnStr("(local)", "Northwind")) Dim dtProdIndiv As New DataTable() odaProdIndiv.Fill(dtProdIndiv) With dtProdIndiv.Rows(0) Me.txtProductName.Text = .Item("ProductName") Me.txtUnitPrice.Text = .Item("UnitPrice") End With End Sub Figure 5.16. You will use the request object in code on this page to retrieve detail data. Comments That's it! A good way to expand this example is to add the coding technique learned in the previous How-To for editing data. Using data with your Web Forms is not much harder than using Windows Forms. Just remember to stash some variables for round trips to the server and to bind your data. [ Team LiB ] Page 189 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 6. Creating Transact-SQL Commands In this chapter you will         Retrieve unique records using only a select query Use variables and functions in T-SQL Use wildcards and ranges of values in a SQL query Find records in a table without corresponding entries in a related table Take advantage of using subqueries Create, modify, and delete tables Create a new table with data from existing tables Create and call SQL Server 2000 user-defined functions Many databases use the SQL database language as the primary way of communicating from an application to the database and working with data. Transact-SQL (T-SQL) is an enhanced version developed to work with Microsoft SQL Server. Besides being able to handle standard SQL commands, T-SQL provides additional statements and commands that allow you to create database objects, maintain data, and use programmatic control from within stored procedures and user-defined functions. With T-SQL, you can perform pretty well any of the necessary tasks that you have from day to day. When you combine that with SQL-DMO, discussed in the next chapter, you can create quite advanced applications that take care of all your users' needs. Note This chapter takes you through creating SQL statements and more extensive routines by setting the command text of command objects. Normally, you would create stored procedures to perform these tasks. This chapter uses the technique it does so that you don't need to add stored procedures to your copy of the SQL Server Northwind database. You can find all of the examples in this chapter in the Solution called Visual Basic .NET on the Web site. Chapter 6 [ Team LiB ] Page 190 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.1 Retrieve Unique Records Using Only a Select Query I need to figure out which customers have invoices. The problem is that when I join the Customers with the Orders tables, I get the customers listed for each order. I only want each customer listed once. How do I return only those customers who have orders, but only once? Technique For this How-To, you will be using the DISTINCT clause on a SQL SELECT statement to limit the data to unique values. When you include the DISTINCT clause, SQL Server uses the columns that are returned to determine how to limit the data. For the opposite affect, you can include the ALL clause, although it is not necessary because this is the default. You will create two SELECT statements for this task. The first one is for all records: SELECT Customers.CompanyName FROM Customers INNER JOIN Orders ON Customers .CustomerID = Orders.CustomerID To limit the records, use the DISTINCT clause: SELECT DISTINCT Customers.CompanyName FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.1. When the form loads, you will see two option buttons, Show All and Distinct, with Show All selected. The SELECT statement showing an inner join between customers and order is displayed in a Label control. You will also see a DataGrid control filled with multiple entries of customers displayed (see Figure 6.1). Figure 6.1. A common problem with inner joins is retrieving multiple records when you want to see just one per occurrence. Page 191 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html If you click on the option button labeled Use Distinct, then the DataGrid control will be refreshed, but only one customer per set of orders will be displayed. 1. Create a Windows Form. Then place the controls listed in Table 6.1 with the following properties set, as displayed in Figures 6.1 and 6.2. Figure 6.2. Using the DISTINCT clause gives you control over displaying unique records. Page 192 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 6.1. Control Property Settings for How-To 6.1 Object Property Setting RadioButton Name Checked rbShowAll True rbDistinct SQL Statement lblSQLString Results dgResults RadioButton Label Label Label DataGrid 2. Name Text Name Text Name As with some of the other chapters' projects, you need to build a support routine to create the Connection string. Called BuildCnnStr, the function can been seen in Listing 6.1. This function takes a server and database name passed to it and creates a connection string. Listing 6.1 modGeneralRoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, _ Page 193 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method would be to pass back a string. The reason for this is that for some objects, you are asked only for a Connection object, but other objects want just a string. 3. Add the code in Listing 6.2 to the Load event of the form. (Double-click on the form to bring up the code.) Listing 6.2 frmHowTo6_1.vb: Loading the Form Private Sub frmHowTo6_1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load GenerateData(Me.rbDistinct.Checked) End Sub 4. Add the code in Listing 6.3 to the class module of the page, creating the GenerateData routine. This routine creates the necessary SQL SELECT statement based on whether blnUseDistinct is true or false. If you look back at Listing 6.2, you will see that this is the value of option button rbDistinct. After the SQL string is created, it is assigned to lblSQLString to display the string, and then it is used in a data adapter to fill a dataset. Last, the SQL string is assigned as the data source for the data grid dgResults. Listing 6.3 frmHowTo6_1.vb: Building the SQL String for Retrieving the Data Sub GenerateData(ByVal blnUseDistinct As Boolean) '-- Build the SQL String Dim strSQL As String strSQL = "SELECT " If blnUseDistinct Then strSQL += "DISTINCT " End If strSQL += "Customers.CompanyName FROM Customers " strSQL += "INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID" '-- Store the SQL String Me.lblSQLString.Text = strSQL Page 194 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Use the SQL String to build the data adapter and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblSQLString.Text, _ BuildCnnStr("(local)", "Northwind")) Dim dtResults As New DataTable() odaResults.Fill(dtResults) '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults End Sub 5. Add the code in Listing 5.4 to the CheckChanged event of the rbDistinct Radio Button control. Listing 6.4 frmHowTo6_1.vb: Regenerating the Data Based on the Radio Button That Is Checked Private Sub rbDistinct_CheckedChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles rbDistinct.CheckedChanged GenerateData(Me.rbDistinct.Checked) End Sub Tip You might have noticed that besides the loading of the form, I only call the GenerateData routine when the rbDistinct option button is changed, and not when the rbShowAll option button is changed. Because only two buttons are available, you only have to program one of the control's events. If you put it on both, you will have the routine called twice, which is not a good thing in this case. Comments It is hard to believe that just one word can affect the data that a SQL statement returns. For the most part, you will want to see all of the records that a SELECT statement returns, but it is nice to have the DISTINCT clause when you need to limit the data. [ Team LiB ] Page 195 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.2 Use Variables and Functions in T-SQL I understand that I can use parameters in my stored procedures, but how do I use variables and functions within T-SQL? Technique It is time to expand the coding you do using T-SQL. In this book so far, you have pretty well been limited to single-line SELECT statements. Now you will learn how to use variables and built-in functions. To achieve this, look at the routine that will be created here: DECLARE @Cust_Id nchar(5), @Order_Date datetime SET @Cust_Id = 'ANTON' SET @Order_Date = '11/27/1996' SELECT OrderID, OrderDate, ShippedDate, DateDiff(day, @Order_Date, ShippedDate) as Days_To_Ship FROM Orders WHERE CustomerID = @Cust_Id and OrderDate = @Order_Date Declaring Local Variables in T-SQL You can use variables in T-SQL much like you would in your other coding languages. First, you must declare them. To declare variables in T-SQL, you will use the DECLARE statement, the ampersand with the variable name, and the data type. You can see an example of the variable declaration here, where nchar, with the length and datetime variables, is declared. DECLARE @Cust_Id nchar(5), @Order_Date datetime Note Besides the standard SQL Server data types, such as nchar, int, and datetime, you can also declare and create a Table datatype. You will see an example of this in How-To 6.8, found later in this chapter. After you have declared the variables, you need to initialize them before you can use them. Initialing Local Variables in T-SQL To initialize the variables, you will use the SET command, shown in these two lines of code: SET @Cust_Id = 'ANTON' SET @Order_Date = '11/27/1996' By setting the initial values, you are then ready to use the variables within the rest of your procedure, any way that you need them, again, by using the @varname syntax. Utilizing Built-In Functions Within T-SQL, you can also use functions to perform some of the tasks needed, just as you do within Visual Basic. Not all of the functions are the same, nor are there necessarily as many. For Page 196 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html instance, instead of a Date() function, which is used in Visual Basic, in T-SQL, you use the GetDate() function. Functions also will not necessarily return the same values or accept the same parameters. This How-To calls the DateDiff() function. As with Visual Basic's DateDiff() function, this function takes two dates, and based on the interval requested, it returns the difference between the two. To check out other functions that are available, you can look up the word function in the Books On-Line for SQL-SQL Server. Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main page, click on the button with the caption How-To 6.2. When the form loads, you will see a SQL statement display in a label, and a DataGrid displayed below (see Figure 6.3). 1. Create a Windows Form. Then place the controls listed in Table 6.2 and seen in Figure 6.3 with the following properties set. Table 6.2. Control Property Settings for This How-To Object Label Label Label DataGrid 2. Property Text Name Text Name Setting SQL Statement lblSQLString Results dgResults Add the code in Listing 6.2 to the Load event of the form. (Double-click on the form to bring up the code.) Creating the T-SQL routine described in the "Technique" section, this code then assigns the routine to the Text property of the Label called lblSQLString. It then creates a data adapter using the string and fills the dtResults DataTable. Last, the code assigns the data adapter as the data source for the dgResults data grid. Listing 6.5 frmHowTo6_2.vb: Storing the SQL Statement and Then Executing Private Sub frmHowTo6_2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Build the SQL String Dim strSQL As String strSQL = "DECLARE @Cust_Id nchar(5), @Order_Date datetime " & _ vbCrLf & vbCrLf strSQL &= "SET @Cust_Id = 'ANTON'" & vbCrLf strSQL &= "SET @Order_Date = '11/27/1996'" & vbCrLf & vbCrLf Page 197 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html strSQL &= "SELECT OrderID, OrderDate, ShippedDate, " strSQL &= "DateDiff(day, @Order_Date, ShippedDate) as Days_To_Ship " strSQL &= "FROM Orders" & vbCrLf strSQL &= "WHERE CustomerID = @Cust_Id and OrderDate = @Order_Date" '-- Store the SQL String Me.lblSQLString.Text = strSQL '-- Use the SQL String to build the data adapter and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblSQLString.Text, BuildCnnStr("(local)", "Northwind")) Dim dtResults As New DataTable() Try odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults End Sub Figure 6.3. The Days_To_Ship is derived from using the DateDiff function with the OrderDate and ShippedDate. Comments For the most part, you will use parameters when you are creating your T-SQL routines. However, when you're creating multiple steps in your routines that are getting more complex, you'll use variables more often. [ Team LiB ] Page 198 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.3 Use Wildcards and Ranges of Values in a SQL Query I need to be able to either search for a range of values, or at least be able to use wild cards with my query. How do I do this using T-SQL? Technique This is one of those fairly simple but necessary How-Tos. You will learn how to use a combination of both wild cards and a range of values. Here is the T-SQL routine that you will use for this How-To: SELECT Customers.CompanyName, Orders.OrderID, Orders.OrderDate FROM Orders INNER JOIN Customers ON Orders.CustomerID = Customers.CustomerID WHERE Customers.CustomerID LIKE 'A%' AND Orders.OrderDate BETWEEN '11/01/1996' AND '12/01/1996' Note The literal values have been used here, rather than the text box values that will be used in the How-To. Using Wild Cards Fairly similar to the wild cards of the old DOS days, wild cards in T-SQL are fairly straightforward to use. It is just a matter of knowing which one to use for which task. When using wild cards, you will use the LIKE operator, as seen in the SQL string for this How-To. You can see where the LIKE operator is used with A%. The % is used to specify anything after the given letter. In this case, it's used for anything starting with the letter A. (This operator will, of course, have to have the OrderDate fall between the dates specified, but we'll talk about this in a moment. You can use other wild cards as well, such as the following:  % (Percent sign). You use this to specify any given group of characters. If used before a letter or group of letters, you are then specifying that you want values ending with those letters. For instance, if you specify %ing, you get skiing, flying, and so on.  _ (Underscore). You use this to specify a single character. For instance, if you type _ake, then you would get four-letters words, such as lake, bake, and sake.  [] (Square brackets) This is a range or group of characters to compare against. For example, if you type [B-D]ake, you would get bake and cake. Another way to use it, with a group of letters, would be to type [BF]ake. In this case, you would get bake and fake, but not the other letter that fall inbetween.  [^] (Caret). This is not within the given range or group. Opposite of the last entry, if you typed [^B-D]ake, you would get those words ending in ake, where the first letter doesn't fall within B D. The same works for the group of letters as well. Using BETWEEN Page 199 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When you need to look at a range of values, whether it be numbers or dates, you use the BETWEEN operator. The syntax for BETWEEN is as follows: table.column BETWEEN startingvalue AND endingvalue This returns all records where the given column falls between the two values, including the two values. Because the BETWEEN statement mentioned a moment ago was Orders.OrderDate BETWEEN '11/01/1996' AND '12/01/1996', then those records with the OrderDate falling between 11/1/1996 and 12/1/1996 inclusively will be displayed. Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.3. When the form loads, you will see a form that allows you to specify letter(s) for the company name to fill the data grid for, along with a range to specify for order dates (see Figure 6.4). 1. Create a Windows Form. Then place the controls listed in Table 6.3 with the following properties set, as displayed in Figure 6.4. Table 6.3. Control Property Settings for This How-To Object Property Setting Label TextBox Text Name Text Customer ID txtCustomerID A% Order Date: From To txtFromDate 11/01/1996 txtToDate 12/01/1996 SQL String lblSQLString Results dgResults Label Label TextBox Text Text Name Text TextBox Name Text Label Label Label DataGrid Text Name Text Name Page 200 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 2. Add the following code in Listing 6.6 to the Load event of the form. (Double-click on the form to bring up the code.) Listing 6.6 frmHowTo6_3.vb: Calling GenerateData When Loading the Form Private Sub frmHowTo6_3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load GenerateData() End Sub 3. In the class module for the form, add the code in Listing 6.7 to create the GenerateData routine. After creating the SQL statement, this routine assigns it to the Text property of lblSQLString. Then the string is used in a data adapter that was created to fill the dtResults data table. Last, the data table is set as the data source for dgResults. Listing 6.7 frmHowTo6_3.vb: Generating Data Using LIKE and BETWEEN Statements Sub GenerateData() '-- Build the SQL String Dim strSQL As String strSQL &= "SELECT Customers.CompanyName, " & _ "Orders.OrderID, Orders.OrderDate " strSQL &= "FROM Orders INNER JOIN Customers " strSQL &= "ON Orders.CustomerID = Customers.CustomerID" & vbCrLf strSQL &= "WHERE Customers.CustomerID LIKE '" & _ Me.txtCustomerID.Text & "' AND " strSQL &= "Orders.OrderDate BETWEEN '" & Me.txtFromDate.Text strSQL &= "' AND '" & Me.txtToDate.Text & "'" '-- Store the SQL String Me.lblSQLString.Text = strSQL '-- Use the SQL String to build the data adapter and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblSQLString.Text, BuildCnnStr("(local)", "Northwind")) Dim dtResults As New DataTable() Try odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults Page 201 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 4. Add the code in Listing 6.8 to the TextChanged events of txtCustomerID, txtFromDate, and txtToDate, respectively. These routines call GenerateDate when the values change. Listing 6.8 frmHowTo6_3.vb: Calling the GenerateData Routine When Text Is Updated Private Sub txtCustomerID_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtCustomerID.TextChanged GenerateData() End Sub Private Sub txtFromDate_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtFromDate.TextChanged GenerateData() End Sub Private Sub txtToDate_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtToDate.TextChanged GenerateData() End Sub Figure 6.4. A common problem with inner joins is retrieving multiple records when you just want to see one per occurrence. Comments By placing your use of wild cards and allowing for ranges of values, you can make your applications and the querying of data more versatile than ever! [ Team LiB ] Page 202 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.4 Find Records in a Table Without Corresponding Entries in a Related Table I have a situation in which I need to find which clients don't have invoices. How do I do this? Technique To find out which records (customers) don't have corresponding records (invoices) in a related table, you have to have a better understanding of the types of joins that can be used between tables during queries. Before looking at the joins, following is the T-SQL statement that will be used in this How-To: SELECT Customers.CustomerID, Customers.CompanyName FROM Customers LEFT OUTER JOIN Orders ON Customers.CustomerID = Orders.CustomerID WHERE Orders.CustomerID IS NULL Types of Joins You can use three types of joins to bring back different information. These join types include inner joins, left outer joins, and right outer joins. Inner Join This join displays records in which at least one record exists in each table for the joined field. This means that customers are displayed only if they have at least one invoice. If you want to see the CompanyName and OrderDate, the SELECT statement would be as follows: SELECT Customers.CompanyName, Orders.OrderDate FROM Customers INNER JOIN Orders ON Customers.CustomerID = Orders.CustomerID Left Outer Join You use this join when you want to see all of the records in the first table, but only those records in the second table that have matching records in the first table. An example of this would be if some customers didn't have invoices; all the customers would appear, but only those invoices that had customers assigned to them would be displayed. Note Normally, if your database is set up with referential integrity correctly, as Northwind is, you won't have any invoices without customers assigned to them. The example SELECT statement for this will be used in the How-To. ON Customers.CustomerID = Orders.CustomerID WHERE Orders.CustomerID IS NULL Remember, because you want only those customers without invoices, you need to check to see where Orders.CustomerID is NULL. Note Page 203 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Although it is not strictly necessary to check whether the Orders.CustomersID is NULL, make sure to check for a column that would not be NULL if a record were there. OrderID would be another good column to check. Right Outer Join As you might have guessed by now, the right outer join is the opposite of the left outer join. Instead of listing all the customers and only those invoices that have customers, the right outer join shows you all records in the second table (invoices) and only those records from the first table (customers) in which there is a matching record on the joined column (CustomerID). One of the ways that the right outer join is used is to find bad data, such as non-relational data that could result from importing data from other systems. Use a SELECT statement similar to the one used for the left outer join type: SELECT Customers.CustomerID, Customers.CompanyName FROM Customers RIGHT OUTER JOIN Orders ON Customers.CustomerID = Orders.CustomerID WHERE Customers.CustomerID IS NULL You will notice that instead of testing for Orders.CustomerID being NULL, you are checking to see if Customers.CustomerID is NULL. Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.4. When the form loads, you will see the SQL String displayed with the data grid displaying customers who don't have orders (see Figure 6.5). 1. Create a Windows Form. Then place the controls listed in Table 6.4 with the following properties set, as displayed in Figure 6.5. Table 6.4. Control Property Settings for This How-To Object Property Setting Label Label Label DataGrid 2. Text Name Text Name SQL Statement lblSQLString Results dgResults Add the following code in Listing 6.9 to the Load event of the form. (Double-click on the form to bring up the code.) The only difference in this routine from the previous How-To is the SELECT statement, which is described in the "Technique" section. Listing 6.9 frmHowTo6_4.vb: Using the Left Outer Join Page 204 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub frmHowTo6_4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Build the SQL String Dim strSQL As String strSQL &= "SELECT Customers.CustomerID, Customers.CompanyName " strSQL &= "FROM Customers LEFT OUTER JOIN Orders " strSQL &= "ON Customers.CustomerID = Orders.CustomerID" & vbCrLf strSQL &= "WHERE Orders.CustomerID IS NULL" '-- Store the SQL String Me.lblSQLString.Text = strSQL '-- Use the SQL String to build the data adapter and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblSQLString.Text, _ BuildCnnStr("(local)", "Northwind")) Dim dtResults As New DataTable() Try odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults End Sub Figure 6.5. Using an outer join to retrieve records without corresponding records. Comments The majority of the time, you will be using the inner join rather than the outer joins. However, Page 205 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html sometimes outer joins will be necessary, so you should experiment with them and get comfortable with them. [ Team LiB ] Page 206 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.5 Take Advantage of Using Subqueries I think there are some duplicate records in one of my tables. Also, I need to know which of the cities (and regions) in a Northwind database has more than one customer in it. How can I use subqueries to perform these tasks? Technique To get the answers to the situations just presented, you will use a subquery in your T-SQL statement. A subquery is a complete SELECT statement. Following is the query that will be used for this How-To. It uses a subquery in the WHERE clause of the outer, or main query: SELECT Customers.City, Customers.Region, Customers.CustomerID, Customers.CompanyName From Customers WHERE (((Customers.City) IN (SELECT Tmp.City FROM Customers As Tmp GROUP BY Tmp.City,Tmp.Region HAVING Count(*)>1 And Region = Customers.Region))) ORDER BY Customers.City, Customers.Region You can see in this query that in the WHERE clause, the City column in Customers is used with an IN operator. The subquery in this case returns all the cities that are assigned to more than one customer. Note In this case, you are using a subquery much as you would a joined table or against another view. The nice thing about using the subquery is that you can see the entire query here, instead of opening another view that is joined. Performancewise, there is no benefit or degradation in using subqueries. In addition to using subqueries in WHERE clauses, you can use them anywhere you would use an expression. Steps Open and run the "Visual Basic .NET Chapter 6" solution. From the main form, click on the button with the caption How-To 6.5. Much like a couple of the other How-Tos in this chapter, you will see the query displayed in the label on the top of the form, with the results displayed in the data grid object below (see Figure 6.6). 1. Create a Windows Form. Then place the controls listed in Table 6.5 with the properties set displayed in Figure 6.6. Table 6.5. Control Property Settings for This How-To Object Property Setting Label Label Label Text Name Text SQL Statement lblSQLString Results Page 207 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataGrid 2. Name dgResults Add the code in Listing 6.10 to the Load event of the form. (Double-click on the form to bring up the code.) Listing 6.10 frmHowTo6_5.vb: Loading and Executing the SQL Statement by Using the Subquery Private Sub frmHowTo6_5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Build the SQL String that returns cities that ' have more than one customer in them. Dim strSQL As String strSQL = "SELECT Customers.City, Customers.Region, " & "Customers.CustomerID, Customers.CompanyName " strSQL &= "From Customers " strSQL &= "WHERE (((Customers.City) In " strSQL &= "(SELECT Tmp.City FROM Customers As Tmp " strSQL &= "GROUP BY Tmp.City,Tmp.Region HAVING Count(*)>1 " strSQL &= "And Region = Customers.Region))) " & _ "ORDER BY Customers.City, Customers.Region" Me.lblSQLString.Text = strSQL '-- Use the SQL String to build the data adapter and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblSQLString.Text, BuildCnnStr("(local)", "Northwind")) Dim dtResults As New DataTable() Try odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults End Sub Figure 6.6. Using subqueries in one step to retrieve information saves time and effort. Page 208 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Subqueries are a powerful tool for getting at your data in different ways. Following are some rules you have to remember when using subqueries:   You can only use an ORDER BY clause if you are using the TOP clause. If a table is being used in the subquery but not in the main query, then you cannot use columns from that table in the output of the main query.   You need to use parentheses around the subquery SELECT statement. You can't include a FOR BROWSE or COMPUTE clause in the subquery. [ Team LiB ] Page 209 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.6 Create, Modify, and Delete Tables It is common in database applications to programmatically create, modify, and delete tables. How do I do this using T-SQL? Technique To perform these tasks, you will use the CREATE TABLE, ALTER TABLE, and DROP TABLE T-SQL statements. With these statements, you can handle any requirements that your application might have. Look at these statements one at a time. Creating a Table Using CREATE TABLE With the CREATE TABLE statement, not only can you specify columns and their data types, but you also can specify indexes, check constraints, and other table level properties. For this How-To, you will be use the following T-SQL statement: CREATE TABLE ListsExample ( ListID smallint IDENTITY(1, 1) PRIMARY KEY CLUSTERED, LastName varchar(50) NOT NULL, FirstName varchar(50) NOT NULL, Age smallint , DateEntered datetime NOT NULL DEFAULT GetDate() CHECK (DateEntered <= GetDate()) ) This statement shows how to perform a number of different tasks: 1. 2. 3. 4. 5. 6. 7. 8. 9. LastName varchar(50) NOT NULL, 10. FirstName varchar(50) NOT NULL, 11. Age smallint , 12. Create a field with the Default Value set, and with a Check Constraint specified. 13. 14. DateEntered datetime NOT NULL DEFAULT GetDate() 15. CHECK (DateEntered <= GetDate()) ListID smallint IDENTITY(1, 1) PRIMARY KEY CLUSTERED, Create fields that can't be NULL, and using different data types: CREATE TABLE ListsExample Create an Identity column, which is the primary key: Specify the name of the table: Modifying a Table Using ALTER TABLE The example T-SQL statement used for modifying the table in this How-To is pretty simple in that it adds a column and removes (drops) a column: ALTER TABLE ListsExample ADD MyNewColumn varchar(30) Page 210 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ALTER TABLE ListsExample DROP COLUMN Age You can perform quite a few other tasks with this statement. You can even see by the syntax displayed here that you can handle many tasks, including dropping constraints. ALTER TABLE table { [ ALTER COLUMN column_name { new_data_type [ ( precision [ , scale ] ) ] [ COLLATE < collation_name > ] [ NULL | NOT NULL ] | {ADD | DROP } ROWGUIDCOL } ] | ADD { [ < column_definition > ] | column_name AS computed_column_expression } [ ,...n ] | [ WITH CHECK | WITH NOCHECK ] ADD { < table_constraint > } [ ,...n ] | DROP { [ CONSTRAINT ] constraint_name | COLUMN column } [ ,...n ] | { CHECK | NOCHECK } CONSTRAINT { ALL | constraint_name [ ,...n ] } | { ENABLE | DISABLE } TRIGGER { ALL | trigger_name [ ,...n ] } } You can do even more. Look at the Books Online for SQL Server to see complete coverage of this statement. Deleting a Table Using the DROP TABLE Statement This statement is the easiest, and it's a one liner: DROP TABLE ListsExample However, you need to keep some things in mind when you are trying to drop a table:  You can't use the DROP TABLE statement when the table is used in a relationship and is referenced in the FOREIGN KEY constraint. You will need to drop the other table or the constraint.  You will need to be the administrator or owner of the table to be able to use the DROP TABLE statement.  Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.6 (see Figure 6.7). 1. Create a Windows Form. Then place the controls listed in Table 6.6 with the following properties set, as displayed in Figures 6.7. You can't use the DROP TABLE statement on system tables. Table 6.6. Control Property Settings for This How-To Object Property Setting Page 211 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label Label Button Text Name Name Text SQL Statement to Create a Table lblCreateTable btnCreateTable Create Table SQL Statement to Modify a Table lblModifyTable btnModifyTable Modify Table SQL Statement to Delete a Table lblDeleteTable btnDeleteTable Delete Table Label Label Button Text Name Name Text Label Label Button Text Name Name Text 2. Add the code in Listing 6.11 to the Load event of the form. (Double-click on the form to bring up the code.) This routine creates the SQL statements for all three tasks and assigns them to the appropriate label for display. Listing 6.11 frmHowTo6_6.vb: Loading the SQL Statements into the Appropriate Labels Private Sub frmHowTo6_6_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Build the SQL String for Creating a Table Dim strSQL As String strSQL = "CREATE TABLE ListsExample" & vbCrLf strSQL &= "(" & vbCrLf strSQL &= " strSQL &= " strSQL &= " strSQL &= " strSQL &= " strSQL &= " strSQL &= ")" Me.lblCreateTable.Text = strSQL strSQL = "ALTER TABLE ListsExample ADD MyNewColumn varchar(30) " & vbCrLf strSQL &= "ALTER TABLE ListsExample DROP COLUMN Age" ListID smallint IDENTITY(1, 1) " & _ LastName varchar(50) NOT NULL, " & vbCrLf FirstName varchar(50) NOT NULL, " & vbCrLf Age smallint , " & vbCrLf DateEntered datetime NOT NULL DEFAULT GetDate() " & vbCrLf CHECK (DateEntered <= GetDate())" & vbCrLf "PRIMARY KEY CLUSTERED," & vbCrLf Page 212 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.lblModifyTable.Text = strSQL strSQL = "DROP TABLE ListsExample" Me.lblDeleteTable.Text = strSQL End Sub 3. Add the code in Listing 6.12 to the Click event of the btnCreateTable button. This routine calls the function PerformTask(), passing the text in the lblCreateTable label. PerformTask() is described in the next step. If you perform the task successfully, then a message box is displayed letting you know that all went as it should have. Listing 6.12 frmHowTo6_6.vb: Calling PerformTask() from the btnCreateTable Click Event Private Sub btnCreateTable_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCreateTable.Click If PerformTask(Me.lblCreateTable.Text) Then MessageBox.Show("Table Created Successfully, " & _ _Look for ListsExample " & "Table in Northwind Database in Server Explorer", _ "Action Performed") End If End Sub 4. In the class module of the form created for this How-To, create the code displayed in Listing 6.13 for the PerformTask() function. This code creates a Connection object. Next, create a Command object that is based on the string passed in strSQL. Open the connection and execute the command. Notice that the execution of the command has been wrapped in the Try..Catch..End Try code block to make sure the command is executed correctly; if it's not, a message is displayed. Listing 6.13 frmHowTo6_6.vb: Executing the SQL Statement Passed in Using strSQL Function PerformTask(ByVal strSQL As String) As Boolean Dim cnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Dim cmdAction As New OleDb.OleDbCommand(strSQL) cmdAction.Connection = cnn cnn.Open() PerformTask = True Try Page 213 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html cmdAction.ExecuteNonQuery() Catch excp As Exception MessageBox.Show(excp.Message, "Error with Action") PerformTask = False End Try cnn.Close() End Function 5. Add the code snippets in Listing 6.14 to the appropriate Click events for btnModifyTable and btnDeleteTable to the Load event of the form. Listing 6.14 frmHowTo6_6.vb: Calling PerformTask from btnModifyTable and btnDeleteTable Click Events Private Sub btnModifyTable_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnModifyTable.Click If PerformTask(Me.lblModifyTable.Text) Then MessageBox.Show("Table Modified Successfully, " & _ Look for ListsExample " & "Table in Northwind Database in Server Explorer", _ "Action Performed") End If End Sub Private Sub btnDeleteTable_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDeleteTable.Click If PerformTask(Me.lblDeleteTable.Text) Then MessageBox.Show("Table Deleted Successfully, " & _ "Look for ListsExample " & "Table in Northwind Database in Server Explorer", _ "Action Performed") End If End Sub Figure 6.7. A common problem with inner joins is retrieving multiple records when you just want to see one per occurrence. Page 214 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments You don't have to add, modify, and delete tables manually. Just make sure that you back up your data before performing these tasks. [ Team LiB ] Page 215 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.7 Create a New Table with Data from Existing Tables I often need to create new tables from existing data. If the table already exists, I need to delete the old table first. How do I do this using T-SQL? Technique To perform these tasks, you will create two T-SQL statements and use them in one Command object. Here are the two statements that will be used: IF EXISTS (SELECT * FROM sysobjects WHERE id = object_id(N'[Northwind].[dbo].[MyProdAndCat]')) DROP TABLE [Northwind].[dbo].[MyProdAndCat] SELECT Categories.CategoryName, Products.ProductName INTO MyProdAndCat FROM Categories INNER JOIN ProductsON Categories.CategoryID = Products.CategoryID" The first statement checks for the existence of the particular table you will be creating, in this case MyProdAndCat. This statement demonstrates a couple of techniques that you can use in T-SQL:  Using the EXIST statement with a SELECT statement, querying the system table called sysobjects  Using an IF statement to conditionally execute another command, in this case the DROP TABLE statement Tip Now that you have learned this technique, you will want to use it repeatedly. Make sure you mark this page! The last statement uses an inner join to join two tables displaying the CategoryName and ProductName. The clause that creates the new table is this: INTO MyProdAndCat This tells SQL Server to create a new table called MyProdAndCat from the SELECT statement that is specified. Steps Open and run the Visual Basic .NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.7. You will see the SQL string specified in the "Technique" section displayed in a label. If you click the Execute button, the new table is generated a SELECT statement is executed, and the results are displayed in the DataGrid object (see Figure 6.8). 1. Create a Windows Form. Then place the controls listed in Table 6.7 with the following properties set, as displayed in Figure 6.8. Page 216 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 6.7. Control Property Settings for This How-To Object Property Setting Label Label Label Button Text Name Text Name Text SQL Statement lblSQLString Results btnExecute Execute dgResults DataGrid 2. up the code.) Name Add the code in Listing 6.16 to the Load event of the form. (Double-click on the form to bring Listing 6.16 frmHowTo6_7.vb: Storing the SQL Statement in the lblSQLString Label to Display and Use Later Private Sub frmHowTo6_7_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Build the SQL String that returns cities that ' have more than one customer in them. Dim strSQL As String strSQL = "IF EXISTS (SELECT * from sysobjects " & vbCrLf strSQL &= " vbCrLf strSQL &= " vbCrLf & vbCrLf strSQL &= "SELECT Categories.CategoryName, Products.ProductName" & vbCrLf strSQL &= "INTO MyProdAndCat" & vbCrLf strSQL &= "FROM Categories INNER JOIN Products" & vbCrLf strSQL &= "ON Categories.CategoryID = Products.CategoryID" Me.lblSQLString.Text = strSQL End Sub 3. Add the following code in Listing 6.17 to the Click event of btnExecute. This code creates DROP Table [Northwind].[dbo].[MyProdAndCat]" & _ WHERE id = object_id(N'[Northwind].[dbo].[MyProdAndCat]'))" & _ Connection and Command objects by using the T-SQL routine discussed in the "Technique" section. Then the code executes the query. Next, a select query is run against the new table, and the DataSource property is set to the data table that was filled. Listing 6.17 frmHowTo6_7.vb: Loading the Form Private Sub btnExecute_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExecute.Click Dim dtResults As New DataTable() Try Page 217 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmd As New OleDb.OleDbCommand(Me.lblSQLString.Text) ocmd.Connection = ocnn ocnn.Open() ocmd.ExecuteNonQuery() ocnn.Close() '-- Use the SQL String to build the data adapter ' and fill the data table. Dim odaResults As _ New OleDb.OleDbDataAdapter("Select * From MyProdAndCat", BuildCnnStr("(local)", "Northwind")) odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property Me.dgResults.DataSource = dtResults End Sub Figure 6.8. These results are based on a new table created by the SQL string that is displayed. Comments You will probably want to go ahead and drop the new table after you are finished using it if you don't need to keep it around for any other purposes. Page 218 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Page 219 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 6.8 Create and Call SQL Server 2000 User-Defined Functions In SQL Server 2000, I have heard that you can create user-defined functions (UDFs). Where would you use UDFs, and how do you create and call them from within T-SQL? Technique UDFs have been used for years in application development languages. You can now create them in SQL Server 2000 as well. Creating SQL Server 2000 UDFs You can create UDFs in SQL Server 2000 by using the CREATE FUNCTION command. Normally, you would do this using the Enterprise Manager or some tool, but here you will learn how to do it using VB.NET. Following is the function that will be created: CREATE FUNCTION udf_ShowProdAndCat (@UnitPriceParm money) RETURNS @ProdAndCatTab TABLE ( ProductID int, ProductName nvarchar(80), CategoryName nvarchar(80), UnitPrice int ) AS BEGIN INSERT @ProdAndCatTab SELECT P.ProductID, P.ProductName, C.CategoryName, P.UnitPrice FROM Products AS P INNER JOIN Categories AS C ON P.CategoryID = C.CategoryID WHERE P.UnitPrice > @UnitPriceParm RETURN END This function definitely looks a lot different from functions you have created in other languages, but it doesn't look as funky when you remember you are using T-SQL commands. Passing Parameters to SQL Server UDFs The parameter that is passed starts with the @ symbol, much like local variables that were discussed in How-To 6.1. You will also want to declare the data type. Returning Scalar or Table Types from SQL Server UDFs When returning values from a UDF, you will either pass back a scalar type, which is actually a single value of one of the standard data types, or pass back a new Table data type. The example for this How-To creates and returns a Table data type, specified with the following lines of code: RETURNS @ProdAndCatTab TABLE ( ProductID int, ProductName nvarchar(80), Page 220 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CategoryName UnitPrice ) By including the opening and closing parentheses, you can specify and return an entire table's worth of data, but be careful not to because performance would not be good. This is the same as it would be using SQL Server data. You can then use this table that is returned in another T-SQL statement. After establishing the return value, in this case the table ProdAndCatTab, you need to create the body of code for the UDF. Note Although this return value has been called ProdAndCatTab, there is not going to be a table that you can access outside the function by that name. It will just be strictly for use in the calling statement. nvarchar(80), int Formatting the Body of Code for SQL Server UDFs You can see from the block of code that follows that you need to have a BEGIN and END statement: AS BEGIN INSERT @ProdAndCatTab SELECT P.ProductID, P.ProductName, C.CategoryName, P.UnitPrice FROM Products AS P INNER JOIN Categories AS C ON P.CategoryID = C.CategoryID WHERE P.UnitPrice > @UnitPriceParm RETURN END Notice also that you will have INSERT @ProdAndCatTab and RETURN statements in there to create the Table return value. The rest of the code is much the same as other T-SQL statements. Calling SQL Server 2000 UDFs You can call UDFs from other T-SQL Statements, as displayed here for this How-To: Select * From udf_ShowProdAndCat(" & Me.txtUnitPrice.Text & ")" There, the UDF is called in a SELECT statement, and the parameter is passed. Steps Open and run the VB.NET Chapter 6 solution. From the main form, click on the button with the caption How-To 6.8 (see Figure 6.9). Figure 6.9. A common problem with inner joins is retrieving multiple records when you want to see only one per occurrence. Page 221 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You will see the UDF described in the "Technique" section in a label. Click the button labeled Create UDF. If the UDF already exists, then a message box will tell you so. Otherwise, the UDF is created. Next, click the button labeled Use UDF. The data grid is then filled and the data is displayed. You can change the value in the Products Greater Than text box. Then click Use UDF again to see the new data displayed. 1. Create a Windows Form. Then place the controls listed in Table 6.8 with the following properties set, as displayed in Figure 6.9. Table 6.8. Control Property Settings for This How-To Object Property Setting Label TextBox Label Label Button Text Name Text Name Name Report Products Greater Than: txtUnitPrice SQL Statement Creating Temporary Table lblCreateUDF btnCreateUDF Page 222 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text Label Label Button Text Name Name Text Label Text Create UDF SQL Statement Using UDF lblUseUDF btnUseUDF Use UDF Results dgResults DataGrid Name 2. up the code.) Add the code in Listing 6.18 to the Load event of the form. (Double-click on the form to bring Listing 6.18 frmHowTo6_8.vb: Create the UDF Code, and Assign It to a Label for Display and Use Later Private Sub frmHowTo6_8_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Create the UDF string Dim strSQL As String strSQL = "CREATE FUNCTION udf_ShowProdAndCat ( @UnitPriceParm money)" strSQL &= "RETURNS @ProdAndCatTab TABLE" & vbCrLf strSQL &= "(" & vbCrLf strSQL &= " strSQL &= " strSQL &= " strSQL &= " ProductID ProductName CategoryName UnitPrice int," & vbCrLf nvarchar(80)," & vbCrLf nvarchar(80)," & vbCrLf int" & vbCrLf strSQL &= ")" & vbCrLf strSQL &= "AS" & vbCrLf strSQL &= "BEGIN" & vbCrLf strSQL &= " strSQL &= " strSQL &= " strSQL &= " vbCrLf strSQL &= " strSQL &= " strSQL &= " strSQL &= "END" ON P.CategoryID = C.CategoryID" & vbCrLf WHERE P.UnitPrice > @UnitPriceParm" & vbCrLf RETURN" & vbCrLf INSERT @ProdAndCatTab" & vbCrLf SELECT P.ProductID, P.ProductName," & vbCrLf C.CategoryName, P.UnitPrice" & vbCrLf FROM Products AS P INNER JOIN Categories AS C" & _ Me.lblCreateUDF.Text = strSQL '-- Create the SQL string that calls the UDF Me.lblUseUDF.Text = "Select * From udf_ShowProdAndCat(" & _ Me.txtUnitPrice.Text & ")" Page 223 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 3. Add the code in Listing 6.19 to the Click event of btnCreateUDF. This code uses Connection and Command objects to create the UDF based on the code that is provided. Listing 6.19 frmHowTo6_8.vb: Creating the New UDF in SQL Server Private Sub btnCreateUDF_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCreateUDF.Click Try Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmd As New OleDb.OleDbCommand(Me.lblCreateUDF.Text) ocmd.Connection = ocnn ocnn.Open() ocmd.ExecuteNonQuery() ocnn.Close() Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try MessageBox.Show("UDF Created") End Sub 4. Add the code in Listing 6.20 to the TextChanged event of the button txtUnitPrice. Listing 6.20 frmHowTo6_8.vb: Updating the SELECT Statement That Is Calling the UDF Private Sub txtUnitPrice_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtUnitPrice.TextChanged Me.lblUseUDF.Text = "Select * From udf_ShowProdAndCat(" & _ Me.txtUnitPrice.Text & ")" End Sub 5. Add the code in Listing 6.21 to the Click event of the button btnUseUDF. This code fills a dataset based on the SELECT statement that calls the UDF. The code then assigns the dataset to the DataSource property of dgResults. Listing 6.21 Displaying Data Using the SELECT Statement in the Text Property of lblUseUDF Private Sub btnUseUDF_Click(ByVal sender As System.Object, Page 224 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal e As System.EventArgs) Handles btnUseUDF.Click Dim dtResults As New DataTable() Try '-- Use the SQL String to build the data adapter ' and fill the data table. Dim odaResults As New OleDb.OleDbDataAdapter(Me.lblUseUDF.Text, BuildCnnStr("(local)", "Northwind")) odaResults.Fill(dtResults) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try '-- Assign the data table to the data grid's DataSource property. Me.dgResults.DataSource = dtResults End Sub Comments When you have to use the same T-SQL statements repeatedly, it is handy to be able to store that code somewhere, just like you can do with UDFs you create in Visual Basic. When using UDFs, you can use the value inline and save a number of steps when creating your T-SQL routines. [ Team LiB ] Page 225 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 7. Performing Common Database Tasks Using SQL-DMO In this chapter you will      Create a dialog box to connect to a new database Back up and verify a SQL Server database Restore a SQL Server database Transfer tables between SQL Server databases Create a Detach/Attach SQL Server database dialog box Regardless of the language you are now using for creating your database applications, if you are using SQL Server for your database, you still need to be able to perform basic database tasks on your back-end database. In addition, you will probably want to give your users the ability to perform these tasks without having to use Enterprise Manager. The way to allow the users to perform some of the common database tasks such as backing up and restoring the database is to take advantage of SQL-Distributed Management Objects (SQL-DMO) and Data Transformation Services (DTS). When you use the Backup/Restore Wizard (see Figure 7.1) in the Enterprise Manager, you are really using SQL-DMO, with the interface created for you. Figure 7.1. Under the covers, the SQL-DMO objects are being used to perform the requested tasks such as backup. Page 226 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html The same also can be said of the DTS object model, used to create transformation packages and other services (see Figure 7.2.) Figure 7.2. As with SQL-DMO and backing up databases, when exporting data, SQL-DTS objects are used. As this chapter describes each of the tasks that you will be able to accomplish, you will see more of the various objects, properties, and methods that you can use to accomplish your tasks. [ Team LiB ] Page 227 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Looking at the SQL Server DMF APIs The SQL Distributed Management Framework is a framework of objects, services, and components used to manage Microsoft SQL Server 2000. It is made up of a few APIs that you can use to accomplish tasks in your applications. You can see how these APIs are used in Figure 7.3. Figure 7.3. Under the covers, the SQL-DMO objects are being used to perform the requested tasks. Following is a brief description of each of the APIs. We will be using the last two directly in the rest of this chapter.  SQL-NS. SQL Namespace provides a way to actually call the Enterprise Managers dialog boxes and User Interface. SQL Namespace uses the other APIs listed.  SQL-DMO. SQL Distributed Management Objects give you access to the various objects within SQL Server, as well as some of the tasks that can be performed using the Enterprise Manager, so that you can perform them within your own application.  SQL-DTS. SQL Data Transformation Services allows you to create transformation packages and tasks, much like you would by using the DTS user interface. [ Team LiB ] Page 228 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Setting References in .NET for the SQL APIs Before you can use the APIs within your .NET application, you need to create a reference to the particular library you are going to use. The libraries you will be using are COM libraries; therefore, you will not have certain benefits of using the .NET Framework, such as some of the performance gains. However, you can still use the libraries. Hopefully, if and when the libraries are updated to the framework, you will be able to convert your code over to use them. To access the necessary libraries, choose Add Reference from the Project menu. Click on the COM tab to display possible COM libraries. Next, click Select after highlighting the following libraries: Microsoft DTSPackage Object Library and Microsoft SQLDMO Object Library. Click OK to close the dialog box. At that point, if you open the Object Browser, you can expand the Interop.SQLDMO library and even highlight the SQL Server object to see the properties and methods available. This is shown in Figure 7.4. Figure 7.4. The objects displayed here are now available for use in your applications. As you work through the following How-Tos, the various collections, objects, properties, and methods that you will be using will be listed as you need them. So many objects are available that it would take multiple pages to display the whole trees of the SQL-DMO and SQL-DTS object models. [ Team LiB ] Page 229 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 7.1 Create a Dialog Box to Connect to a New Database, Including Listing Available SQL Servers and Databases Users sometimes need to connect to various databases. An example of this is a large company that might keep its site information in separate databases in the same or even different SQL Servers. Management might need to point the application to different site databases, depending on which one it needs to work with. This How-To shows you how to create a dialog box to let the user pick the SQL Server and database and then create a new connection based on the selections. Within a database application, it is necessary to allow users to select a SQL Server back end to which to connect. If you have created my application with the necessary flexibility, you should not have hard-coded SQL Server or database names within my application. How do you create a dialog box that lists available SQL Servers and databases and that the user can utilize to connect to a new database? Technique For this How-To, you will be using the base object in SQL-DMO, which is the Application object, and then the SQLServer object. You can use many objects off this object, the first layer of which is shown in Figure 7.5. Figure 7.5. These are just the tip of the iceberg as far as collections and objects used in SQL-DMO. Page 230 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 7.1 presents the objects, properties, and methods that will be used for this -To. Table 7.1. SQL-DMO Objects Used for Listing SQL Servers, Databases, and Connecting to a Database Object Property/Method Description Collection used to hold the list of available servers Application NameList ListAllAvailableServers Method used to retrieve available servers on the network SQLServer Connect Connection string that connects you to the SQL Server, allowing you access to the databases Flag that specifies that you want to connect to the SQL Server using a trusted connection Collection of databases for the specified SQL Server LoginSecure Databases Page 231 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You will also be using the OleDbConnection object. Steps Open and run the VB.NET Chapter 7 solution. From the main Windows form, click on the command button with the caption How-To 7.1. When the form loads, you will see the SQL Servers that are available on your network. If you are not on the network, you will only see a SQL Server called "local." If you click on a SQL Server and you are in fact using the Windows NT Integrated Security, then you will see the list of databases located in the chosen SQL Server. You can then select a database and then click the Connection button. If you are successful, you will see the connection string displayed in the text box at the bottom of the form. The form will then look like the form displayed in Figure 7.6. 1. Create a Windows Form. Then place the controls shown in Figure 7.6 with the following properties set. Table 7.2. Label, ComboBox, ListBox, and Command Button Control Property Settings Object Property Setting Label Name Text Label1 SQL Servers lstSQLServers Label2 Databases lstDatabases Label3 Connection String txtConnectionString Not Connected btnConnect Connect ListBox Label Name Name Text ListBox Label Name Name Text TextBox Name Text Command Button Name Text Page 232 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 2. As with some of the other chapters' projects, before creating the code that will be attached to the Load event of the form, you need to create a support routine to create the Connection string. Called BuildCnnStr, the function can be seen in Listing 7.1. This function takes a server and database names passed to it and returns a connection string. You will want to create a basic module in which to keep the routine. Listing 7.1 modSQLDMORoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, _ ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method would be to pass back a string. The reason for this is that some objects ask for a Connection object, but others just want a string. 3. On the form, add the code in Listing 7.2 to the Load event. Listing 7.2 frmHowTo7_1.vb: Loading SQL Servers into a List Box Private Sub frmHowTo7_1_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Load up the SQL Servers LoadSQLServers(Me.lstSQLServers) End Sub 4. In the same module as step 2, create the routine called LoadSQLServers. After establishing an instance of the SQL-DMO application, the code calls the ListAvailableSQLServer method. If no names are loaded into the oNames namelist object (meaning that they were not available or you weren't on the network), then the (local) server is added to the list box. Otherwise, the list returned is added to the list box. The first item in the list box is then selected, causing the event described in the next step to be executed. Listing 7.3 modSQLDMORoutines.vb: Loading SQL Servers into a List Box Sub LoadSQLServers(ByRef lstSQLServers As ListBox) Dim intCurrSQL As Integer Dim oNames As SQLDMO.NameList Dim oSQLApp As New SQLDMO.Application() '-- Load available SQL Servers into a NameList Page 233 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' (those that are able to be seen by the network) oNames = oSQLApp.ListAvailableSQLServers '-- Load the local instance as first in the list, if not on the network. If oNames.Count = 0 Then lstSQLServers.Items.Add("(local)") End If '-- Load the namelist into the list box For intCurrSQL = 1 To oNames.Count lstSQLServers.Items.Add(oNames.Item(intCurrSQL)) Next intCurrSQL '-- Choose the first instance lstSQLServers.SelectedIndex = 0 End Sub Note At this point, if you try to run your sample application, you might get an error that includes the text QueryInterface for interface SQLDMO.NameList failed. on the ListAvailableSQLServer method. If this is the case, then you need to install Service Release 2 for SQL Server 2000. This will take care of this problem. 5. Add the code listed in Listing 7.4 to the SelectedIndexChanged event of the list box called lstSQLServers. This routine starts by testing to see whether a SQL Server and database have been selected. If so, the routine enables the btnConnect button; otherwise, the button is disabled. The routine called GetSQLDatabases is then called, passing selected SQL Server and the lstDatabases list box. You can see the GetSQLDatabases routine listed in the next step. Listing 7.4 frmHowTo7_1.vb: Enabling or Disabling the btnConnect Button and Calling the Routine to Load the Database List Box Private Sub lstSQLServers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstSQLServers.SelectedIndexChanged '-- If both the SQL Server and database are chosen, enable ' the Connect button. lstDatabases.SelectedItems.Count > 0 Then Me.btnConnect.Enabled = True Else Me.btnConnect.Enabled = False End If If lstSQLServers.SelectedItems.Count > 0 And _ Page 234 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) End Sub 6. Create the GetSQLDatabases routine by entering the code in Listing 7.5 to the new module that you created in step 2. The first task that this routine attempts is to connect to the server that is selected. If the routine can't connect, then the function is exited; otherwise, the names of the database that are within the SQL Server are loaded into the list box called lstDatabases. Listing 7.5 modSQLDMORoutines.vb: Retrieving Database Names for a Given SQL Server Function GetSQLDatabases(ByVal strSQLServer As String, _ ByRef lstTemp As ListBox) Dim intDBs As Integer Dim db As Object Dim strDBs As String '-- Establish a connection to the server. If not, then exit the function. Dim osvr As SQLDMO.SQLServer osvr = New SQLDMO.SQLServer() osvr.LoginSecure = True Try osvr.Connect(strSQLServer) Catch excp As Exception MessageBox.Show("There is a problem retrieving " & _ "databases for this server. " & "Please check the name and try again. ", vbInformation, "Error with Server") Exit Function End Try '-- Clear the current list lstTemp.Items.Clear() '-- Load up the database names for the selected server into the list box. For Each db In osvr.Databases lstTemp.Items.Add(db.Name) Next End Function 7. Add the code from Listing 7.6 to the SelectedIndexChanged event of the lstDatabases list box. This code is similar to the listing in step 4 in that it enables the btnConnect button if an Page 235 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html item is selected in both the lstSQLServers and lstDatabases list boxes. Listing 7.6 frmHowTo7_1.vb: Repopulating the List Boxes Based on the Current Category Selected Private Sub lstDatabases_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles lstDatabases.SelectedIndexChanged '-- If both the SQL Server and database are chosen, ' enable the Connect button. lstDatabases.SelectedItems.Count > 0 Then Me.btnConnect.Enabled = True Else Me.btnConnect.Enabled = False End If End Sub 8. Add the code in Listing 7.7 to the Click event of the btnConnect button. In this routine, a If lstSQLServers.SelectedItems.Count > 0 And _ Connection object is instantiated and its Connection string is set to the chosen SQL Server and database. If the connection has a problem opening, then the Text property of txtConnectionString is set to an error message. Otherwise, the Text property is set to the new connection string. Listing 7.7 frmHowTo7_1.vb: Calling the Routine to Reload the lstUnSelected List Box If This Check Box Is Changed Private Sub btnConnect_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnConnect.Click Dim ocnn As New OleDb.OleDbConnection() Try '-- Create the connection string and open the connection ocnn.ConnectionString = BuildCnnStr(Me.lstSQLServers.SelectedItem, _ Me.lstDatabases.SelectedItem) ocnn.Open() Catch excp As Exception Me.txtConnectString.Text = "Error with Connection" Exit Sub End Try Me.txtConnectString.Text = ocnn.ConnectionString End Sub Page 236 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 7.6. This form works great for logging users into a database using Windows NT Integrated Security. How It Works When the form opens, the SQL Servers that are available on the network are loaded into the first list box on the form. When the user clicks on a specific SQL Server, then the databases from that SQL Server are loaded into the Databases list box. The user can then select a database from the list. When the user does this, the Connect button is enabled. If the user then clicks on the Connect button, the connect string is loaded into the text box on the bottom of the form. Comments Like the others, this How-To is set up to use the Windows NT Integrated Security. If you wanted to use the SQL Server security, you could add text boxes for login name and password and then supply them when calling certain methods such as the Connect method in the code listed in step 6. You would also then set the LoginSecure property used in the same listing to False. This How-To is great for exactly what it does: letting the user (or administrator) pick a new SQL Server and database to connect to if necessary. You can then save this connection string to a Public variable and use it with all your connection objects. You will also be using similar controls and code for the rest of the How-Tos in this chapter. [ Team LiB ] Page 237 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 7.2 Back Up and Verify a SQL Server Database Backing up a database is probably one of the most important features to incorporate into your application. If you leave it up to the user to use the Enterprise Manager to back up the database, then it won't happen. You can arrange to have the backup scheduled, but sometimes you need to back it up at a moment's notice. This How-To shows you how to create a custom dialog box that will allow the user not only to back up your SQL Server database, but also to verify the backup. Your users need to have a method for backing up and verifying their databases without using Enterprise Manager. How do you create a dialog box that would let them back up and verify their databases? Technique To accomplish this task, you will once again use the SQL-DMO objects. A couple of the new objects you will use are the Backup and BackupDevices objects. You can see some of the additional objects, along with the properties and methods that will be used, in Table 7.3. Table 7.3. Additional SQL-DMO Objects Used for Backing Up and Verifying a Database Object Property/Method Description This property allows you to specify what type of backup that you want to take place. The choices are SQLDMOBackup_Database, Backup Action SQLDMOBackup_Differential, SQLDMOBackup_Files, and SQLDMOBackup_Log. BackupSetDescription This property allows you to specify a description for the backup set. BackupSetName Database This property is the Backup set name. This property allows you to specify the database to back up. This property specifies the devices you will be backing up to. This method initializes the Backup process. This property allows you to specify how to handle the truncate log when backing up. This method performs the actual backup. This is a collection of backup devices for a SQL Server. Devices Initialize TruncateLog SQLBackup BackupDevices BackupDevice Name ReadBackupHeader Thisis the name of a specific backup device. This method reads in the header information for a backup, returning a QueryResults object. This is the individual property information about a backup. QueryResults ColumnName Page 238 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html GetColumnString This is the actual value for individual header information. Using the objects listed in Table 7.3, you will create a form with options for the user to back up his database and verify the information after it has been saved. Note Not all the possible options will be included in the form created for this How-To. For example, you could allow the user to back up the database to a separate file and give him additional options for the type of backup to perform. Odds are good that you will not want to give the users all the options they could have; that is one of the reasons you want to create the dialog box here instead of letting users use the Enterprise Manager. Steps Open and run the VB.NET Chapter 7 solution. From the main Windows form, click on the command button with the caption How-To 7.2. As with How-To 7.1, a user clicks on the SQL Server that he wants to display the databases of. He can then choose the database and backup device. From there, the user can click the Backup button to perform the backup. You can then click on the verify button to have information about the backup displayed in the text box at the bottom of the form. The form will look similar to the one displayed in Figure 7.7. 1. Create a Windows Form. Then place the controls shown in Figure 7.7, with the following properties set as in Table 7.4. Table 7.4. Controls and Their Property Settings Object Property Setting Label Name Text Label1 SQL Servers lstSQLServers Label2 Databases lstDatabases Label3 Backup Devices lstBackupDevices btnBackup ListBox Label Name Name Text ListBox Label Name Name Text ListBox Command Button Name Name Page 239 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text Label Name Text TextBox Name Text Label Name Text Panel Groupbox Name Name Text Radio Button Name Checked Text Radio Button Name Checked Text Groupbox Name Text Radio Button Name Checked Text Radio Button Name Checked Text Radio Button Name Checked &Backup Label4 Backup Set Name txtBackupSetName MyTestBackup Label5 Options Panel1 grpAction Action rbFull True Full rbIncremental False Incremental grpTruncateLog Truncate Log rbNoLog True No Log rbNoTruncate False No Truncate rbTruncate False Page 240 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text Label Name Text TextBox Name Text Checkbox Name Text TextBox Name Multiline Scrollbars Command Button Name Text Command Button Name Text 2. Truncate Label5 Backup Set Description txtBackupSetDescription MyTestBackup chkInitialize Initialize? txtVerify True Both btnVerify &Verify btnClose &Close On the form, add the code in Listing 7.8 to the Load event. This will look familiar to How-To 7.1. For an examination of the LoadSQLServers routine, check out step 4 in that How-To. Listing 7.8 frmHowTo7_2.vb: Calling the Routine That Loads Available SQL Servers into a List Box Private Sub frmHowTo7_2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '-- Load up the SQL Servers LoadSQLServers(Me.lstSQLServers) End Sub 3. On the lstSQLServers list box, add the code in Listing 7.9 to the SelectedIndexChanged event. This routine calls both the GetSQLDatabases, described in step 6 of How-To 7.1, and GetBackupDevices, described in the next step. Listing 7.9 frmHowTo7_2.vb: Populating the lstDatabases and lstBackupDevices List Boxes Private Sub lstSQLServers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstSQLServers.SelectedIndexChanged Page 241 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) GetBackupDevices(Me.lstSQLServers.SelectedItem, Me.lstBackupDevices) End Sub 4. Create the GetBackupDevices routine by entering the code in Listing 7.10 into the new module you created in How-To 7.1. The first task attempted by this routine is to connect to the server that is selected. Next, the names of the backup devices that are within the SQL Server are loaded into the list box called lstBackupDevices. Listing 7.10 modSQLDMORoutines.vb: Retrieving Backup Device Names for a Given SQL Server Public Sub GetBackupDevices(ByVal strSQLServer As String, _ ByRef lstBackupDevices As ListBox) Dim oDevice As SQLDMO.BackupDevice '-- Log on to the SQL Server. Dim osvr As SQLDMO.SQLServer = New SQLDMO.SQLServer() osvr.LoginSecure = True osvr.Connect(strSQLServer) lstBackupDevices.Items.Clear() '-- Iterate through the backup devices. For Each oDevice In osvr.BackupDevices lstBackupDevices.Items.Add(oDevice.Name) Next End Sub 5. On the btnBackup button, add the code in Listing 7.11 to the Click event. After connecting to the chosen SQL Server, a Backup object is instantiated. Next, certain properties of the Backup object, called oBackup, are set to values that are specified on the form. The SQLBackup method is called off the Backup object, and the connection is closed. Last, the variables are cleared (set to Nothing) and a message box is displayed. Listing 7.11 frmHowTo7_2.vb: Performing the Backup Private Sub btnBackup_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnBackup.Click '-- Create a connection to the server Dim osvr As New SQLDMO.SQLServer() osvr.LoginSecure = True osvr.Connect(Me.lstSQLServers.SelectedItem) '-- Create a Backup object, and set the necessary properties ' based on options chosen on the form. Page 242 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim oBackup As New SQLDMO.Backup() With oBackup If Me.rbFull.Checked Then .Action = SQLDMO.SQLDMO_BACKUP_TYPE.SQLDMOBackup_Database Else .Action = SQLDMO.SQLDMO_BACKUP_TYPE.SQLDMOBackup_Differential End If .BackupSetDescription = Me.txtBUSetDescription.Text .BackupSetName = Me.txtBUSetName.Text .Database = Me.lstDatabases.SelectedItem .Devices = "[" & Me.lstBackupDevices.SelectedItem & "]" If Me.rbNoLog.Checked Then .TruncateLog = _ SQLDMO.SQLDMO_BACKUP_LOG_TYPE.SQLDMOBackup_Log_NoLog ElseIf Me.rbNoTruncate.Checked Then .TruncateLog = _ SQLDMO.SQLDMO_BACKUP_LOG_TYPE.SQLDMOBackup_Log_NoTruncate Else .TruncateLog = _ SQLDMO.SQLDMO_BACKUP_LOG_TYPE.SQLDMOBackup_Log_Truncate End If .Initialize = Me.chkInitialize.Checked '-- Execute the backup .SQLBackup(osvr) End With '-- Disconnect from the server and clean up. osvr.DisConnect() osvr = Nothing oBackup = Nothing MessageBox.Show("Database Backed Up", "Task Completed", _ MessageBoxButtons.OK) End Sub 6. Add the code in Listing 7.12 to the Click event of btnVerify. After connecting to the SQL Server, the code iterates through each of the backup devices for the server and locates the one that the form specifies. After the specific backup device is located, the ReadBackupHeader method is called, with an SQLDMO.QueryResults object returned. Each row of the QueryResults is read, and then the information is displayed in a text box called txtVerifyDisplay. From there, the SQLServer object is disconnected. Page 243 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 7.12 frmHowTo7_2.vb: Performing the Backup Private Sub btnVerify_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnVerify.Click Dim oDevice As SQLDMO.BackupDevice Dim oResults As SQLDMO.QueryResults Dim intRowCount As Integer Dim intColCount As Integer '-- Create a connection to the server Dim osvr As New SQLDMO.SQLServer() osvr.LoginSecure = True osvr.Connect(Me.lstSQLServers.SelectedItem) '-- Iterate through the devices For Each oDevice In osvr.BackupDevices If oDevice.Name = Me.lstBackupDevices.SelectedItem Then '-- If found, display the results oResults = oDevice.ReadBackupHeader For intRowCount = 1 To oResults.Rows For intColCount = 1 To oResults.Columns Me.txtVerifyDisplay.Text &= _ oResults.ColumnName(intColCount) & " - " Me.txtVerifyDisplay.Text &= _ oResults.GetColumnString(intRowCount, _ intColCount) & vbCrLf & vbCrLf Next Next End If Next '-- Disconnect and clean up osvr.DisConnect() osvr = Nothing oDevice = Nothing oResults = Nothing End Sub 7. Add the code in Listing 7.13 to the Click event of btnClose. Listing 7.13 frmHowTo7_2.vb: Performing the Backup Page 244 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub btnClose_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnClose.Click Me.Close() End Sub Figure 7.7. Creating a form for backing up and verifying a SQL Database gives you control over what options the user has when performing the task. How It Works After the form loads, the user can select the SQL Server, database, and backup device. When the user clicks the button labeled Perform Backup, a SQLDMO Backup object is created. The Backup object gives you the same capabilities as if you were using the Enterprise Manager except that you control them. Only put options on the form that you want to have the user set, and then set the other options yourself, as you deem necessary. After setting the options, the SQLBackup method performs the backup. By using the QueryResults object off the BackupDevice, you have a means of looking at some of the properties of the backup and verifying them to make sure the database did indeed get backed up. Comments You could enhance this utility in a number of ways, a couple of which include the following: Page 245 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html  Add a text box for letting the user specify a filename for the backup, rather than using a backup device.  Allow the user to add backup devices. Currently, only existing backup devices can be used. Just be careful on what options you give the user so he doesn't shoot himself in the foot. [ Team LiB ] Page 246 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 7.3 Restore a SQL Server Database Sometimes the user needs to restore a database, and again, it is nice if he doesn't have to go to Enterprise Manager to accomplish this task. This How-To explains how to use the Restore object from SQL-DMO to accomplish this task. It's all well and good to be able to back up and verify a SQL Server database, but what about being able to restore the database if necessary? How do you create a dialog box to restore a SQL Server database? Technique For this How-To, you will use the Restore object of the SQL-DMO object model. You can see the properties and methods that will be used in Table 7.5. Table 7.5. Properties and Methods of the Restore Object Property/Method Description Action This property allows you to specify what type of backup you want to take place. The choices are found in the SQLDMO.SQLDMO_RESTORE_TYPE namespace and are SQLDMORestore_Database, SQLDMORestore_Files, SQLDMORestore_Log. Database Devices This property allows you to specify the database name to restore to. This property shows which device(s) you are restoring from. ReplaceDatabase This property tells whether to replace the database. SQLRestore This method causes the restore to be executed . Using the objects listed in Table 7.5, you will create a form with options for the user to restore his database. Steps Open and run the VB.NET Chapter 7 solution. From the main Windows Form, click on the command button with the caption How-To 7.3. You will then see the form displayed in Figure 7.8. Figure 7.8. This form restores a SQL Server database. Page 247 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html As with How-To 7.2, a user clicks on the SQL Server for which he wants to display the databases. He can then choose the database and backup device. From there, the user can click the Restore button to restore the database. 1. Create a Windows Form. Then place the controls shown in Figure 7.8, with the following properties set as in Table 7.6. Table 7.6. Label, ListBox, DataGrid, and Command Button Controls Property Settings Object Property Setting Label Name Text Label1 SQL Servers lstSQLServers Label2 Databases lstDatabases Label3 Backup Devices lstBackupDevices btnBackup &Backup Label4 ListBox Label Name Name Text ListBox Label Name Name Text ListBox Command Button Name Name Text Label Name Page 248 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text Panel CheckBox Name Name Text Checked Command Button Name Text 2. Options Panel1 chkReplaceDB Replace Database? True btnClose &Close On the form, add the code in Listing 7.14 to the Load event. This will look familiar from the first How-To. For an examination of the LoadSQLServers routine, check out step 4 in How-To 7.1. Listing 7.14 frmHowTo7_3.vb: Calling the Routine That Loads Available SQL Servers into a List Box Private Sub frmHowTo7_3_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Load up the SQL Servers LoadSQLServers(Me.lstSQLServers) End Sub 3. On the lstSQLServers list box, add the code in Listing 7.15 to the SelectedIndexChanged event. This routine calls both GetSQLDatabases, described in step 6 of How-To 7.1, and GetBackupDevices, described in step 4 of How-To 7.2. Listing 7.15 frmHowTo7_3.vb: Populating the lstDatabases and lstBackupDevices List Boxes Private Sub lstSQLServers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstSQLServers.SelectedIndexChanged GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) GetBackupDevices(Me.lstSQLServers.SelectedItem, Me.lstBackupDevices) End Sub 4. On the btnRestore button, add the code in Listing 7.16 to the Click event. After logging into the server, the Restore object is created and its properties are set from the form. The SQLRestore method is invoked and the connection is closed. Listing 7.16 frmHowTo7_3.vb: Performing the Backup Private Sub btnRestore_Click(ByVal sender As System.Object, _ Page 249 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal e As System.EventArgs) Handles btnRestore.Click '-- Create a connection to the server Dim osvr As New SQLDMO.SQLServer() osvr.LoginSecure = True osvr.Connect(Me.lstSQLServers.SelectedItem) '-- Create the restore object, set the properties from the form, ' and execute the restore. Dim oRestore As New SQLDMO.Restore() With oRestore .Action = SQLDMO.SQLDMO_RESTORE_TYPE.SQLDMORestore_Database .Database = Me.lstDatabases.SelectedItem .Devices = "[" & Me.lstBackupDevices.SelectedItem & "]" .ReplaceDatabase = Me.chkReplaceDB.Checked .SQLRestore(osvr) End With '-- Disconnect and clean up. osvr.DisConnect() osvr = Nothing oRestore = Nothing MessageBox.Show("Database Restored", "Task Completed", _ MessageBoxButtons.OK) End Sub 5. Add the code in Listing 7.17 to the Click event of btnClose. Listing 7.17 frmHowTo7_3.vb: Performing the Backup Private Sub btnClose_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnClose.Click Me.Close() End Sub How It Works The Restore object is the counter object to the Backup object, allowing you to restore databases that have been backed up. As with the Backup object, you can either specify the properties yourself or let the user choose them on the form. Comments Again, you need to be careful which options you let the user specify and which you specify yourself. This is a utility that you might want to secure; only let an administrator have access to it so that Page 250 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html users don't accidentally overwrite a good database with an old one. As with the backup, you could enhance this utility by allowing the user to specify a file to restore from instead of a backup device. [ Team LiB ] Page 251 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 7.4 Transfer Tables Between SQL Server Databases Users sometimes need to transfer (copy) tables between SQL Server databases. This How-To shows how to allow the user to choose multiple tables and copy them from one database to another as well as tables from two different databases on two different SQL servers. One of the tasks your clients have you perform for them using the Enterprise Manager is to transfer objects, such as tables, between SQL Server databases. How do you create a dialog box that would allow the user to transfer databases between two SQL Server databases? Technique Unlike the earlier How-Tos in this chapter, you will be using the SQL-DTS object model in addition to SQL-DMO. You can see the objects, properties, and methods that will be used from SQL-DTS in Table 7.7. Table 7.7. SQL-DTS Objects That Are Used to Perform the Transfer of Tables from One SQL Server Database to Another Object Property/Method Package Steps.New Tasks.New Steps.Add Tasks.Add Execute Step TaskName Name Task CustomTask CustomTask Name SourceServer SourceUseTrustedConnection SourceDatabase DestinationServer DestinationUseTrustedConnection DestinationDatabase CopyAllObjects IncludeDependencies IncludeLogins IncludeUsers Page 252 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DropDestinationObjectsFirst CopySchema CopyData AddObjectForTransfer Using the items just listed, you will create a form with options to transfer tables between two SQL databases. Steps Open and run the VB.NET Chapter 7 solution. From the main Windows form, click on the command button with the caption How-To 7.4. You will then see a form allowing you to pick SQL Servers on the network to transfer from and to. After you have chosen these, you can then select which databases you want to transfer from and to. After choosing from the database to transfer from, you are then presented with a list of tables to transfer from. You can then highlight multiple tables, as shown in Figure 7.9. Figure 7.9. Transferring tables between SQL Server databases. Tip One of the options included as a property of the CustomTask object is IncludeDependencies. This option specifies whether to have DTS transfer related tables as well as the selected table(s). This could be put as an option on the form as well. For this example, I have it set to True. 1. Create a Windows Form. Then place the controls shown in Figure 7.9, with the following properties set as in Table 7.8. Table 7.8. Label, ListBox, and Command Button Controls Page 253 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Property Settings Object Property Setting Label Name Text Label1 From SQL Servers lstFromSQLServer Label2 To SQL Servers lstToSQLServer Label3 Transfer from Database lstFromDB Label4 Transfer to Database lstToDB Label5 Table(s) to Transfer lstTables MultiSimple btnTransfer &Perform Transfer ListBox Label Name Name Text ListBox Label Name Name Text ListBox Label Name Name Text ListBox Label Name Name Text ListBox Name SelectionMode Command Button Name Text 2. On the form, add the code in Listing 7.18 to the Load event. This will look familiar from How-To 7.1. For an examination of the LoadSQLServers routine, check out step 4 in that How-To. Different from the other How-Tos in this chapter thus far, however, is the fact that the LoadSQLServers routine is called twice: once for the lstFromSQLServer, and a second time for the lstToSQLServer. Listing 7.18 frmHowTo7_4.vb: Calling the Routine That Loads Available SQL Servers into a List Box Private Sub frmHowTo7_4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load LoadSQLServers(Me.lstFromSQLServer) Page 254 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html LoadSQLServers(Me.lstToSQLServer) End Sub 3. On the lstFromSQLServer and lstToSQLServer list boxes, add the code in Listing 7.19 to the SelectedIndexChanged event of each, as appropriate. These routines call GetSQLDatabases, described in step 6 of How-To 7.1. Listing 7.19 frmHowTo7_4.vb: Populating the lstDatabases and lstBackupDevices List Boxes Private Sub lstFromSQLServer_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstFromSQLServer.SelectedIndexChanged GetSQLDatabases(Me.lstFromSQLServer.SelectedItem, Me.lstFromDB) End Sub Private Sub lstToSQLServer_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles lstToSQLServer.SelectedIndexChanged GetSQLDatabases(Me.lstToSQLServer.SelectedItem, Me.lstToDB) End Sub 4. On the lstFromTables list box, add the code in Listing 7.20 to the SelectedIndexChanged event. This routine starts off by logging onto the server that is selected in the lstFromSQLServer list box, and then creates a reference to the database that is selected in the lstFromDB list box. After clearing the lstTables list box, the routine iterates through each of the tables in the database and adds the names of those that are user tables to the lstTables items. Listing 7.20 frmHowTo7_4.vb: Populating the lstDatabases and lstBackupDevices List Boxes Private Sub lstFromDB_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstFromDB.SelectedIndexChanged '-- Create the connection and specify the stored procedure to use. Dim odb As SQLDMO.Database Dim otbl As SQLDMO.Table Dim oapp As New SQLDMO.Application() Dim osvr As New SQLDMO.SQLServer() Try osvr.LoginSecure = True osvr.Connect(Me.lstFromSQLServer.SelectedItem) odb = osvr.Databases.Item(Me.lstFromDB.SelectedItem) Me.lstTables.Items.Clear() Page 255 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html For Each otbl In odb.Tables If otbl.TypeOf = _ SQLDMO.SQLDMO_OBJECT_TYPE.SQLDMOObj_UserTable Then Me.lstTables.Items.Add(otbl.Name) End If Next Catch excpData As Exception MessageBox.Show("Error Occurred: " & excpData.Message) End Try End Sub Tip You could really make this a flexible and powerful utility by including different objects to transfer other than just user tables. Some examples could be stored procedures or views. 5. On the lstTables list box, add the code in Listing 7.21 to the SelectedIndexChanged event. This routine enables the btnTransfer button. Listing 7.21 frmHowTo7_4.vb: Performing the Transfer of Tables Private Sub lstTables_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstTables.SelectedIndexChanged Me.btnTransfer.Enabled = True End Sub 6. Add the code in Listing 7.22 to the Click event of btnTransfer. This routine begins by declaring all the objects to be used, and then creates new Step and Task objects, with the type of task being specified. In this case, the task is of type DTSTransferObjectsTask. Next, the various necessary properties are set on the Task object. For each of the tables to be transferred, the AddObjectForTransfer method is executed, with the name of the table being passed to the method. After the name of the task is added to the step, both objects are added to their collections in the Package object. The Execute method of the Package object is then called. Listing 7.22 frmHowTo7_4.vb: Performing the Transfer of Tables Private Sub btnTransfer_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnTransfer.Click Dim oPackage As New DTS.Package() Dim oStep As DTS.Step Dim oTask As DTS.Task Dim oXferObj As DTS.TransferObjectsTask Page 256 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim intCurrTable As Integer Try '-- Create step and task oStep = oPackage.Steps.New oTask = oPackage.Tasks.New("DTSTransferObjectsTask") oXferObj = oTask.CustomTask '-- Configure transfer objects task With oXferObj .Name = "XferObjTask" .SourceServer = Me.lstFromSQLServer.SelectedItem .SourceUseTrustedConnection = True .SourceDatabase = Me.lstFromDB.SelectedItem .DestinationServer = Me.lstToSQLServer.SelectedItem .DestinationUseTrustedConnection = True .DestinationDatabase = Me.lstToDB.SelectedItem .CopyAllObjects = False .IncludeDependencies = True .IncludeLogins = False .IncludeUsers = False .DropDestinationObjectsFirst = False .CopySchema = True .CopyData = DTS.DTSTransfer_CopyDataOption.DTSTransfer_AppendData For intCurrTable = 0 To Me.lstTables.SelectedItems.Count - 1 .AddObjectForTransfer( _ Me.lstTables.SelectedItems.Item(intCurrTable), "dbo", DTS.DTSSQLObjectType.DTSSQLObj_UserTable) Next End With '-- Link step to task oStep.TaskName = oXferObj.Name oStep.Name = "XferObjStep" oPackage.Steps.Add(oStep) oPackage.Tasks.Add(oTask) oPackage.Execute() Catch excp As Exception MessageBox.Show(excp.Message, "Error Occurred") Exit Sub Page 257 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Try MessageBox.Show("Tables Transferred") End Sub 7. Add the code in Listing 7.23 to the Click event of btnClose. Listing 7.23 frmHowTo7_4.vb: Closing the Form Private Sub btnClose_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnClose.Click Me.Close() End Sub How It Works Using the Data Transformation Services API requires a bit more work than just using SQL-DMO. To use SQL-DTS, you need to also have a concept of using workflow. Workflow allows you to specify steps in a package and assign tasks to those steps. Task objects that are not assigned to steps can be included in the package, but they will not be executed. You can see an example of multiple tasks being performed by the arrows in the package in Enterprise Manager (see Figure 7.10). Figure 7.10. This DTS package has multiple tasks that are being performed and shows workflow. This example is simple in that it has only one step and task. For more information on using workflow and DTS packages, check out SQL Server's Books On-Line, and look up "workflow." As you create each of the tasks, you will have to set the various properties that are necessary to perform the tasks. The source and destination servers and databases are examples of this. Comments As mentioned, using DTS takes a bit more work to understand than DMO, but after you understand what needs to be done, there is little you can't perform using it. Page 258 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Page 259 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 7.5 Create a Detach/Attach SQL Server Database Dialog Box Situations sometimes arise that require a database to be attached, detached, or both. Perhaps your client needs to move the database from one SQL Server to another. This How-To shows you the methods you can use to perform these tasks. Before diving into solving some of the tasks that can be accomplished in the How-Tos just listed, it's important to discuss the SQL-DMO object model, as well as create a reference to it. Many times, you've used the Enterprise Manager to move databases for users by attaching and detaching them. It would be nice to be able to perform this task without users calling you. At he very least, you'd like to be able to walk users through the details over the phone, without having to use the Enterprise Manager. How do you create a dialog box to perform this task? Technique This is probably the easiest of the How-Tos to create for this chapter, other than How-To 7.1. For this task, you will be using two methods of the SQLServer object: DetachDB and AttachDBWithSingleFile. Along with the two methods just mentioned, you will also be using a Tab control to choose which task to perform, as well as an OpenFile Dialog control to allow the user to choose the file to attach. Steps Open and run the VB.NET Chapter 7 solution. From the main Windows form, click on the command button with the caption How-To 7.5. You can select a database, such as the one displayed in Figure 7.11, and click the Detach button. You will see the database disappear from the list of databases to choose from. Figure 7.11. Ready to detach the chosen database. After you have chosen the database, you can reattach the database by clicking on the tab labeled Attach Database. You can then type in the name you want to attach the database as, and click on the Locate File button to locate the database file to attach (see Figure 7.12.) Figure 7.12. Choosing the database file to attach. Page 260 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Select the file and click Open. To attach the file, click the Attach Database button. The database file will then be attached, and you can see it in the list of databases. To check this, you can look at the list back on the Detach Database tab; that list was refreshed when you clicked the Attach Database button. 1. 2. Create a Windows Form. Add a Tab control from the Windows Form Controls list. Click the builder button in the Tab Pages property, and add two pages. Set the Text property for Page1 to Detach Database, and the Text property for Page2 to Attach Database. 3. Add an OpenFileDialog control from the Windows Form Controls list. Go ahead and leave the default name given to the control, but make a note of it. 4. Place the other controls shown in Figure 7.10 and 7.11, with the following properties set as in Table 7.9. Table 7.9. Label, ListBox, and Command Button Controls Property Settings Object Location Property Setting Label Main Form Name Text Label1 SQL Servers lstSQLServers Label2 Databases lstDatabases btnDetach ListBox Label Main Form Main Form Name Name Text ListBox Button Tab Page1 Tab Page1 Name Name Page 261 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text Label Tab Page2 Name Text TextBox Label Tab Page2 Tab Page2 Name Name Text TextBox Button Tab Page2 Tab Page2 Name Name Text Button Tab Page2 Name Text 5. &Detach Database Label3 File to Attach txtFileToAttach Label4 Name of Attached Database txtNameOfAttach btnLocate &Locate File btnAttach &Attach Database On the form, add the code in Listing 7.24 to the Load event. This will look familiar from How-To 7.1. For an examination of the LoadSQLServers routine, check out step 4 in that How-To. Listing 7.24 frmHowTo7_5.vb: Calling the Routine That Loads Available SQL Servers into a List Box Private Sub frmHowTo7_5_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load LoadSQLServers(Me.lstSQLServers) End Sub 6. On the lstSQLServers list box, add the code in Listing 7.25 to the SelectedIndexChanged event. This routine toggles the btnDetach button, depending on whether a SQL Server and database has been selected. It then calls GetSQLDatabases, described in step 6 of How-To 7.1. Listing 7.25 frmHowTo7_5.vb: Populating the lstDatabases List Boxes Private Sub lstSQLServers_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstSQLServers.SelectedIndexChanged If lstSQLServers.SelectedItems.Count > 0 And _ lstDatabases.SelectedItems.Count > 0 Then Me.btnDetach.Enabled = True Else Me.btnDetach.Enabled = False Page 262 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End If GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) End Sub 7. On the lstDatabases list box, add the code in Listing 7.26 to the SelectedIndexChanged event. This routine toggles the btnDetach button, depending on whether a SQL Server and database have been selected. Listing 7.26 frmHowTo7_5.vb: Toggling the btnDetach Button Based on Whether a SQL Server and Database Have Been Chosen Private Sub lstDatabases_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstDatabases.SelectedIndexChanged If lstSQLServers.SelectedItems.Count > 0 And _ lstDatabases.SelectedItems.Count > 0 Then Me.btnDetach.Enabled = True Else Me.btnDetach.Enabled = False End If End Sub 8. On the btnDetach button, add the code in Listing 7.27 to the Click event. After connecting to the server, the DetachDB method is called. Then the GetSQLDatabases routine is called to refresh the database list. Listing 7.27 frmHowTo7_5.vb: Detaching a SQL Server Database Private Sub btnDetach_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDetach.Click Dim oSQLSvr As New SQLDMO.SQLServer() Dim strDetachMsg As String Try '-- Connect to the server oSQLSvr.LoginSecure = True oSQLSvr.Connect(Me.lstSQLServers.SelectedItem) '-- Perform the detach strDetachMsg = oSQLSvr.DetachDB(Me.lstDatabases.SelectedItem) '-- Refresh the databases GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) Catch excp As Exception Page 263 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html MessageBox.Show(excp.Message) Exit Sub End Try MessageBox.Show("Database Detached") End Sub 9. Add the code in Listing 7.28 to the Click event of btnLocateFile. This routine uses the OpenFileDialog control to retrieve the name of the file you want to attach. Listing 7.28 frmHowTo7_5.vb: Locating the Database File to Attach Private Sub btnLocateFile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnLocateFile.Click With OpenFileDialog1 .InitialDirectory = _ "E:\Program Files\Microsoft SQL Server\MSSQL\Data\" .Filter = "SQL Server Database files (*.mdf)|*.mdf" .ShowDialog() Me.txtFileToAttach.Text = .FileName End With End Sub 10. Add the code in Listing 7.29 to the TextChanged event of txtFileToAttach and txtNameToAttach as appropriate. Listing 7.29 frmHowTo7_5.vb: Closing the Form Private Sub txtFileToAttach_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtFileToAttach.TextChanged If Len(Me.txtFileToAttach.Text) > 0 And _ Len(Me.txtNameOfAttach.Text) > 0 Then Me.btnAttach.Enabled = True Else Me.btnAttach.Enabled = False End If End Sub Private Sub txtNameOfAttach_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtNameOfAttach.TextChanged If Len(Me.txtFileToAttach.Text) > 0 And _ Len(Me.txtNameOfAttach.Text) > 0 Then Me.btnAttach.Enabled = True Else Me.btnAttach.Enabled = False Page 264 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End If End Sub 11. Add the code in Listing 7.30 to the Click event of btnAttach. After connecting to the server, this code calls the AttachDBWithSingleFile method. Then it refreshes the database list using the routine GetSQLDatabases. Listing 7.30 frmHowTo7_5.vb: Attaching a SQL Server Database Private Sub btnAttach_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAttach.Click Dim oSQLSvr As New SQLDMO.SQLServer() Dim strAttachMsg As String Try oSQLSvr.LoginSecure = True oSQLSvr.Connect(Me.lstSQLServers.SelectedItem) '-- Attach the database strAttachMsg = oSQLSvr.AttachDBWithSingleFile( _ Me.txtNameOfAttach.Text, Me.txtFileToAttach.Text) '-- Refresh the databases GetSQLDatabases(Me.lstSQLServers.SelectedItem, Me.lstDatabases) Catch excp As Exception MessageBox.Show(excp.Message) Exit Sub End Try MessageBox.Show("Database Attached") End Sub How It Works This How-To uses the DetachDB and AttachDBWithSingleFile methods to attach and detach a database. Comments You can enhance this routine by allowing for databases that have multiple files to be attached and detached. There is so much you can do with the APIs that SQL Server provides. Open the Enterprise Manager and look at some of the various utilities, including Data Transformation Services. Then open the Object Browser to the SQL-DMO and SQL-DTS libraries, and notice the correlation between tasks that are displayed using the Enterprise Manager and the APIs. [ Team LiB ] Page 265 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Page 266 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 8. Taking Advantage of Data-Driven Techniques In this chapter you will         Work with data-bound multi-select list boxes using Windows Forms Use a single Windows Form to update multiple lookup tables Create a point-and-click query tool for users using a Windows Form Make a generic search form in a Visual Basic .NET desktop application Work with data-bound multi-select list boxes using Web Forms Use a single Web Form to update multiple lookup tables Create a point-and-click query tool for users using a Web Form Make a generic search form in an ASP.NET Web application Whenever you are working with databases, whether with Visual Basic .NET or other languages, an efficient method of development is to use data-driven techniques. The term data driven can mean different things. Sometimes people have data-driven applications by having all the options stored in tables and the interface driven from those tables. You can also make an application, or portions of it, be data driven through other methods. Some of the ways are outlined here in this chapter, along with this first one, which discusses using multi-select list boxes in Visual Basic .NET. One of the benefits of using data-driven techniques is that you usually end up with the smaller code base, especially if you use the technique for more than one task. An example of this is the search form example in How-To 8.4 (for Windows Forms) and How-To 8.8 for the Web Form version. You can see the Windows Form version of this technique used with the Customers table in Northwind in Figure 8.1. Figure 8.1. This particular form can be called for searching different record sources. Page 267 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html As with other data-driven techniques, although this form is shown being used with the Customers table, with just four lines of code-setting custom properties on this form, you can use it with just about any other tables, such as Suppliers. The more you use a specific technique in your application, such as this search form, the bigger benefit you receive in terms of number of lines of code and objects that are added to the application. Note Make a note that this is a techniques chapter. By now, you should be pretty familiar with all the objects and should be seeing new ways to use those objects. Note The solution for this chapter has been broken up into two projects, a Visual Basic .NET project called VB.NET Chapter 8, which covers How-Tos 8.1 8.4. The rest of the How-Tos in this chapter are in an ASP.NET project called VBNetHowToChap8Web. As with the code, this chapter could be started in two different chapters, depending on whether you wanted to use the techniques for Visual Basic .NET or ASP.NET. If you want the desktop solutions, start with How-To 8.1; for the Web, you can start with How-To 8.5. Note This chapter is split up to cover data-driven techniques using both Windows Forms and Web Forms. These techniques are useful in both Page 268 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html areas. In addition, they are different enough in the way they are coded that they warranted separate How-Tos for each technique and environment. [ Team LiB ] Page 269 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.1 Work with Data-Bound Multi-Select List Boxes Using Windows Forms It is common to have to assign products to categories, which is a one-to-many relationship. Sometimes you want to be able to do this in a somewhat bulk fashion. One of the methods that works well is using the ListBox control. Using the ListBox control for single selections is no big deal, but when it comes to using it in a multi-select method, it starts getting trickier. This How-To shows you how to create an intuitive interface for assigning products to categories using a couple of multi-select list boxes on a Windows Form. You can assign a category to each product, but you would like to have a method of maintaining all the products for a category at one time. How do you take advantage of a multi-select list box to perform this task? Technique Using the ListBox control in regular single selection mode is as straightforward in .NET as in prior versions of Visual Basic. The same can be said in the case of using the multi-select mode of list boxes. It is as confusing in .NET as it was in prior versions. Using the ListBox control in single entry mode is pretty straightforward. You just need to use the SelectedItem property with the index of 0. However, if you want to use the ListBox control in multi-select mode, then you must perform some more work and access some other properties (see Table 8.1). Table 8.1. Properties Having to Do with Multi-Selection on ListBox Controls (In Order of Use in This How-To's Steps) Property/Object Description Property of the ListBox control. The settings for this are None, One, SelectionMode MultiSimple, or MultiExtended. SelectedIndices (index A collection of the ListBox control, this returns the indices (location in ) the list) of all the selected items. SelectedIndices.Count Property of the ListBox control. A count of the number of items selected in the list box. DataRowView Items (index) Object type that the data provider provides. A collection of the ListBox control. Returns a DataRowView type object. If you have multiple columns, they are also returned in the DataRowView object. Steps Open and run the VB.NET Chapter 8 solution. From the main Windows Form, click on the command button with the caption How-To 8.1. You will then see the form displayed in Figure 8.2. Figure 8.2. This form uses controls bound at runtime and takes advantage of multi-select list boxes. Page 270 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When the form loads, you will see the Beverages category chosen in the top combo box. The Selected and Unselected Products ListBox controls are filled in with the appropriate products. If you click on a product in the Unselected Products list box and then click on the arrow button pointing to the right (>), then the item is moved to the Selected Products list box. If you select items in the Selected Products list box and click on the arrow button pointing to the left (<), those items are moved to the Unselected Products list box. If you click on the Unassigned Products Only check box located at the bottom of the form, then the Unselected Products list box is filled with products that are not assigned to any category. Note If you check the Unassigned Products Only check box when you're first getting into Northwind and running this example, you probably won't see unassigned items. You will need to unselect products from a category. 1. Create a Windows Form. Then place the controls shown in Figure 8.2 with the following properties set in Table 8.2. Table 8.2. Label, ComboBox, ListBox, and Command Button Control Property Settings Object Property Setting Label ComboBox Label ListBox Text Name Text Name SelectionMode Category cboCategories Unselected Products lstUnSelected MultiSimple Page 271 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label ListBox Text Name SelectionMode Selected Products lstSelected MultiSimple btnSelect Command Button Name Text Command Button Name > btnUnSelect Text CheckBox Name Text 2. < chkUnAssignedOnly UnAssigned Products Only As with some of the other chapters' projects, before creating the code that will be attached to the Load event of the form, you need to create a support routine to create the Connection string. Called BuildCnnStr, the function can been seen in Listing 8.1. This function takes a server and database names passed to it and creates a connection string. Listing 8.1 modGeneralRoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method would be to pass back a string. Some objects ask you for a Connection object, but others just ask for a string. You will see BuildCnnStr called in the next step. 3. On the form, add the code in Listing 8.2 to the Load event. In this code, you will start off by creating a data adapter called odaCategories and loading the category's SQL Statement into it. The dtCategories data table is then filled and set as the DataSource property of cboCategories. The DisplayMember and ValueMember of cboCategories are then set. Finally, two new subroutines called LoadUnSelectedProducts and LoadSelectedProducts are called to populate the appropriate list boxes. These routines are discussed in the next two steps. Listing 8.2 frmHowTo8_1.vb: Loading Categories into the List Box Page 272 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private Sub frmHowTo8_1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim odaCategories As OleDb.OleDbDataAdapter Dim dtCategories As New data table() '-- Load the Categories combo box up first odaCategories = New _ OleDb.OleDbDataAdapter( _ "Select CategoryID, CategoryName From Categories", (BuildCnnStr("(local)", "Northwind"))) odaCategories.Fill(dtCategories) Me.cboCategories.DataSource = dtCategories Me.cboCategories.DisplayMember = "CategoryName" Me.cboCategories.ValueMember = "CategoryID" '-- Load each of the product list boxes based on the selected category. LoadUnSelectedProducts() LoadSelectedProducts() End Sub 4. Create the LoadUnSelectedProducts routine by entering the code shown in Listing 8.3 into the form you created for this example. This routine starts off by testing the check box called chkUnAssignedOnly. Based on that value, a SQL string is created that grabs the products that are not assigned to any product, if chkUnAssignedOnly = True. All products that are not assigned to the chosen category are retrieved. The SQL String is stored in the variable called strSQL. Next, the DataAdapter object called odaUnselected is set to strSQL and the SQL Server connection string. The DataTable object called dtUnSelected is then filled and assigned to the list box called lstUnSelected. The DisplayMember and ValueMember properties are then set. Last, the ClearSelected method is called to make sure no entries remain selected. Listing 8.3 frmHowTo8_1.vb: Populating the List Box Displaying Unselected Products Sub LoadUnSelectedProducts() Dim odaUnSelected As OleDb.OleDbDataAdapter Dim dtUnSelected As New DataTable() Dim strSQL As String '-- If the check box for Unassigned Only is checked, then ' ' grab the product items where the category is null; otherwise, load it up with those products not assigned to the current category. If chkUnAssignedOnly.Checked Then strSQL = "Select ProductID, ProductName From Products " & _ " Where CategoryID IS NULL Order By ProductName" Page 273 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Else strSQL = "Select ProductID, ProductName From Products " & _ "Where CategoryID <> " & _ Me.cboCategories.SelectedItem(0) & " Or CategoryID IS NULL Order By ProductName" End If '-- Pretty well same old, same old here. Create a data adapter ' ' and fill the dataset. Next, bind it to the list box. odaUnSelected = New OleDb.OleDbDataAdapter(strSQL, (BuildCnnStr("(local)", "Northwind"))) odaUnSelected.Fill(dtUnSelected) Me.lstUnSelected.DataSource = dtUnSelected Me.lstUnSelected.DisplayMember = "ProductName" Me.lstUnSelected.ValueMember = "ProductID" Me.lstUnSelected.ClearSelected() End Sub 5. Create the LoadSelectedProducts routine by entering the code in Listing 8.4 into the form you created for this tutorial. This routine performs basically the same tasks that the routine listed in the previous step does, except that it performs the tasks using the lstSelected ListBox control. It also doesn't need to test the CheckBox control. Listing 8.4 frmHowTo8_1.vb: Populating the List Box Displaying Selected Products Sub LoadSelectedProducts() Dim odaSelected As OleDb.OleDbDataAdapter Dim dtSelected As New DataTable() Dim strSQL As String '-- Load the products assigned to this category. strSQL = _ "Select ProductID, ProductName From Products Where CategoryID = " & Me.cboCategories.SelectedItem(0) & " Order By ProductName" odaSelected = New _ OleDb.OleDbDataAdapter(strSQL, (BuildCnnStr("(local)", "Northwind"))) odaSelected.Fill(dtSelected) Me.lstSelected.DataSource = dtSelected Me.lstSelected.DisplayMember = "ProductName" Me.lstSelected.ValueMember = "ProductID" Page 274 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.lstSelected.ClearSelected() End Sub 6. Add the code in Listing 8.5 to the SelectedIndexChanged event of the cboCategories combo box. Listing 8.5 frmHowTo8_1.vb: Repopulating the List Boxes Based on the Current Category That Is Selected Private Sub cboCategories_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cboCategories.SelectedIndexChanged '-- Load each of the product list boxes based on the selected category. LoadUnSelectedProducts() LoadSelectedProducts() End Sub 7. Add the code in Listing 8.6 to the CheckChanged event of the chkUnAssignedOnly check box. Listing 8.6 frmHowTo8_1.vb: Call the Routine to Reload the lstUnSelected List Box If This Check Box Is Changed Private Sub chkUnAssignedOnly_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkUnAssignedOnly.CheckedChanged LoadUnSelectedProducts() End Sub 8. Add the code in Listing 8.7 to the Click event of the btnSelect command button. This and the next step contain the most code as well as some new objects and properties. The first thing that happens is that the number of highlighted items (SelectedIndices.Count) is stored to an Integer variable called intItemsNum. One is subtracted from the figure because the collections in .NET are zero based. Next, the code iterates through the SelectedItems collection of the lstUnSelected list box, and using the indices in that collection, the code accesses selected items. The type of object derived from the Items collection is the DataRowView object, mentioned in the "Techniques" section of this example. These items are then added to a string variable called strItems, which is then used to create the criteria for an IN clause of a SQL Update statement. This statement is passed to the Command object called ocmdSelect. This Command object is then executed, and the selected products are updated to reflect the category chosen. Last, the list boxes are reloaded to reflect the changes. Listing 8.7 frmHowTo8_1.vb: Updating the Server with Products Selected for the Given Category Private Sub btnSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSelect.Click Page 275 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim intItemsNum As Integer Dim intCurr As Integer Dim strItems As String Dim drv As DataRowView '-- Grab the number of selected items for the products ' unselected list box. intItemsNum = Me.lstUnSelected.SelectedIndices.Count - 1 '-- Iterate through each of the items and create a string. For intCurr = 0 To intItemsNum If Len(strItems) > 0 Then strItems = strItems & ", " End If drv = Me.lstUnSelected.Items(Me.lstUnSelected. _ SelectedIndices(intCurr)) strItems = strItems & CType(drv(0), String) Next '-- Run an update query to assign the category to the desired products '-- using an IN clause in the SQL statement Try Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Dim ocmdSelect As New _ OleDb.OleDbCommand("Update Products Set CategoryID = " & Me.cboCategories.SelectedItem(0) & _ " Where ProductID IN (" & strItems & ")", ocnn) ocmdSelect.CommandType = CommandType.Text ocnn.Open() ocmdSelect.ExecuteNonQuery() Catch excpCommand As Exception MessageBox.Show(excpCommand.Message) End Try LoadUnSelectedProducts() LoadSelectedProducts() End Sub 9. Add the code in Listing 8.8 to the Click event of the btnUnSelect command button. Again, this code is similar to the previous step, but it is used to set the CategoryID column to null if Page 276 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html the product was highlighted in the lstSelected list box and btnUnSelect was clicked. Listing 8.8 frmHowTo8_1.vb: Updating the Server with Products That Are Unselected for the Given Category Private Sub btnUnSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnSelect.Click Dim intItemsNum As Integer Dim intCurr As Integer Dim strItems As String Dim drv As DataRowView '-- Grab the number of selected items for the products ' selected list box. intItemsNum = Me.lstSelected.SelectedIndices.Count - 1 '-- Iterate through each of the items and create a string. For intCurr = 0 To intItemsNum If Len(strItems) > 0 Then strItems = strItems & ", " End If drv = Me.lstSelected.Items(Me.lstSelected.SelectedIndices(intCurr)) strItems = strItems & CType(drv(0), String) Next Try Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmdUnSelect As New OleDb.OleDbCommand( "Update Products Set CategoryID = Null Where ProductID IN (" & strItems & ")", ocnn) ocmdUnSelect.CommandType = CommandType.Text ocnn.Open() ocmdUnSelect.ExecuteNonQuery() Catch excpCommand As Exception MessageBox.Show(excpCommand.Message) End Try LoadUnSelectedProducts() LoadSelectedProducts() End Sub How It Works When the user chooses a category, the appropriate items are loaded into the two list boxes; Page 277 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html unselected items are placed in the list box on the left, and selected items are placed in the list box on the right. If the check box is selected, then only those items that are not currently assigned to a category are displayed in the list box on the left, which is titled Unselected Products. When the btnSelect button is clicked, any items highlighted in the lstUnSelected list box are used in a query that updates the server with the new category they now belong to. Similarly, when the btnUnSelect is clicked, items in the lstSelected list box are used in a query that updates the CategoryID of the products to null. Comments This example is not the smartest to create in real life because you want products to be assigned to a category. However, this example does a good job of showing the properties and methods you can use to work with the multi-select features of the ListBox control. For examples of using this same basic technique in a Web Form, check out example 8.5. [ Team LiB ] Page 278 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.2 Use a Single Windows Form to Update Multiple Lookup Tables Just about every database application uses lookup tables of some sort or another, such as categories, regions, and territories in the Northwind database. Normally, each of these lookup tables would get its own form for viewing or updating the information in the tables. This example will provide the means for you to create a single form to maintain any of your simple lookup tables, again using a Windows Form. You have a number of simple lookup tables in your application, and it is a pain to have to create a form for each table. How do you create a Windows Form that can be used to update most if not all of your lookup tables that are contained in your database? Technique Using two main controls, the ListBox control and DataGrid control, you can create a form that will take care of most of your simple lookup tables. When you get into those tables that contain lookups or graphics, you will have to come up with a more complete method to modify the data. For this example, you will be using some familiar friends: DataAdapter, CommandBuilder, and DataTable objects. Steps Open and run the VB.NET Chapter 8 solution. From the main Windows Form, click on the command button with the caption How-To 8.2. You will then see the form displayed in Figure 8.3. Figure 8.3. The DataGrid control is filled with different data every time a new item is chosen in the ListBox control. When you choose a new item from the list of tables on the left, the data grid on the right becomes filled with the data from the chosen table. You can then modify the data in the data grid and click on the Update button to update the data back to the server. This includes modifying existing records, as well as adding and deleting records in the DataGrid control. 1. Create a Windows Form. Then place the controls shown in Figure 8.3 with the properties set forth in Table 8.3. Table 8.3. Label, ListBox, DataGrid, and Command Button Controls Property Settings Page 279 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Object Property Setting Label Name Text Label1 Lookup Table to Edit Label2 Lookup Table Data lstLookupTables dgTableData btnUpdate Label Name Text ListBox DataGrid Button 2. Name Name Name Add data to the Items collection of lstLookupTables. To do this, click on the builder button beside the Items property in the property sheet for lstLookupTables. You will then see the String Collection Editor as shown in Figure 8.4. The Items you will add include Categories, Region, and Territories. Figure 8.4. Adding hard-coded items at design is pretty straightforward using this dialog box. Note To make this example truly "data driven," you would want to either keep these table names in a table by themselves and set the data source of lstLookupTables to that table, or generate the list at runtime by naming Page 280 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html your lookup tables a specific way. These values are hard coded for the sake of expediency and so that no more tables are added to Northwind. 3. In the class module for the form, add the following Private declarations just below the line of code that reads Windows Form Designer generated code. 4. 5. 6. Dim mcnn As New OleDb.OleDbConnection() Dim modaLookupData As OleDb.OleDbDataAdapter These lines of code declare Connection and DataAdapter objects that will be used throughout the form. 7. On the form, add the code in Listing 8.9 to the Load event. Listing 8.9 frmHowTo8_2.vb: Establishing the Connection String and Pointing to the First Item in lstLookupTables Private Sub frmHowTo8_2_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Initialize the connection string. mcnn.ConnectionString = BuildCnnStr("(local)", "Northwind") '-- Point to the first lookup table; this fires ' the SelectedIndexChanged event off the list box. Me.lstLookupTables.SelectedIndex = 0 End Sub 8. On the lstLookupTables list box, add the code in Listing 8.10 to the SelectedIndexChanged event. This routine assigns the new table chosen in lstLookupTables as the Select command for the modaLookupData data adapter. The data table called dtData is then filled and set as the data source for dgTableData. Listing 8.10 frmHowTo8_2.vb: Populating the DataGrid Control Private Sub lstLookupTables_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstLookupTables.SelectedIndexChanged Dim dtData As New DataTable() Try '-- Update the data adapter and data table to reflect the new data, ' and reassign the data source of the data grid. modaLookupData = New OleDb.OleDbDataAdapter("Select * From " & Me.lstLookupTables.Text, mcnn) Page 281 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html modaLookupData.Fill(dtData) Me.dgTableData.DataSource = dtData Catch excData As Exception MessageBox.Show(excData.Message) End Try End Sub 9. On the btnUpdate button, add the code in Listing 8.11 to the Click event. This routine performs a task you have seen in one form or another throughout this book. A CommandBuilder object is created off the modaLookupData data adapter, and it is used to update the data table. The Update method of modaLookupData is executed, followed by the AcceptChanges method of the dtFromGrid data table. Listing 8.11 frmHowTo8_2.vb: Populating the DataGrid Control Private Sub btnUpdate_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnUpdate.Click Dim dtFromGrid As DataTable '-- Create the command builder to update (post) the data in the data grid ' back to the server. Dim custCB As OleDb.OleDbCommandBuilder = _ New OleDb.OleDbCommandBuilder(modaLookupData) Try '-- Have to open the connection. mcnn.Open() '-- Grabbing the data table from the DataSource property of the data grid ' saves a bunch of hassles trying to track the data table ' directly. dtFromGrid = CType(dgTableData.DataSource, DataTable) '-- Commands necessary to actually post back to server. modaLookupData.Update(dtFromGrid) dtFromGrid.AcceptChanges() '-- Don't forget to close the connection. mcnn.Close() Catch excp As Exception MessageBox.Show("Couldn't update server") End Try Page 282 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub Tip One interesting thing of note is the way that the DataTable object is derived in this routine. Instead of creating it from a DataSet or DataAdapter object, we get it from the DataGrid object, with the line of code that reads like this: dtFromGrid = CType(dgTableData.DataSource, DataTable) How It Works When the form opens, the initial table's data in the list box is loaded into the DataGrid control by setting the SelectedIndex of the lstLookupTables to 0. When this occurs and when a user selects a new item in the list, a Select statement is generated and loaded into a data adapter, which fills a data table. This, in turn, is used for the data source of the data grid, and the data is displayed. When the user clicks the button with the caption Update, a CommandBuilder object is generated off the DataAdapter object. The Update command for the data adapter is then invoked, with the Update method called. The data table is then referenced from the data source of the DataGrid control, and the AcceptChanges method is called. Comments Creating this kind of utility will save hundreds of hours in some cases, especially if you use it across applications. When starting with something this simple, you can add features to it every time you use it for a new and expanded purpose. [ Team LiB ] Page 283 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.3 Create a Point-and-Click SQL Server Query Tool for Users Using a Windows Form Clients usually want a means of querying the tables, but they do not necessarily know how to create SQL statements. This example describes how to create a point-and-click query interface using a Windows Form and display fields from individual tables as they are chosen. In just about every application you create, your clients need a means to view the data and want to be able to create their own lists. However, most don't want to have to learn how to create SQL statements. In this How-To, you will see a method for not only creating a point-and-click query tool that will allow the users to examine all tables in the database, but also for using the Windows Form in an application without modification. Technique To accomplish the task just presented, you will be using the OleDbCommand and DataReader object. Along with these objects, you will be using some stored procedures that SQL Server supplies. These stored procedures list the various objects within a SQL Server database in this case, Northwind's tables and columns. You will take the elements returned in the DataReader object and load the Add method of the ListBox object. Steps Open and run the VB.NET Chapter 8 solution. From the main Windows Form, click on the command button with the caption How-To 8.3. The first list box you see to the left is populated with the tables from Northwind. Click on the Customer table, and you will see the columns in the next list box labeled Columns. Click on the CompanyName and ContactName, and you will see the SQL String text box filled in. After clicking on the View button, the form will look like the one displayed in Figure 8.5. 1. Create a Windows Form. Then place the controls shown in Figure 8.5 with the properties set forth in Table 8.4. Table 8.4. Labels, ListBoxes, DataGrid, TextBox, and Command Button Controls Property Settings Object Property Setting Label Name Text Label1 Tables Label2 Columns Label3 SQL String Label4 Label Name Text Label Name Text Label Name Page 284 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text ListBox ListBox Name Name SelectionMode TextBox Name MultiLine Button DataGrid 2. Tip Data Display lstTables lstColumns MultiSimple txtSQLString True btnView dgDisplay Name Name Notice that the lstTables list box only allows the user to pick one table at a time, whereas lstColumns allows you to choose multiple columns. A great enhancement to this tool would be to allow the user to select multiple tables and have the application figure out the relation between tables. 3. In the class module for the form, add the following Private declaration just below the line of code that reads Windows Form Designer generated code: 4. 5. Dim mcnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) This line of code declares and assigns an OleDBConnection object that will be used throughout the form. 6. On the form, add the code in Listing 8.12 to the Load event. The first thing this code routine does is create a new OleDbCommand called ocmdTables and assign the built-in SQL Server stored procedure called sp_Tables. After establishing the CommandType as being CommandType.StoredProcedure and then opening the connection, the data reader called odrTables is created by calling the ExecuteReader method off ocmdTables. Listing 8.12 frmHowTo8_3.vb: Executing a SQL Server-Supplied Stored Procedure That Lists the Tables in the Database Private Sub frmHowTo3_8_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load '-- Create the connection and specify the stored procedure to use. Dim ocmdTables As New OleDb.OleDbCommand("sp_Tables", mcnn) Dim odrTables As OleDb.OleDbDataReader Try Page 285 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Specify the type of command being performed ocmdTables.CommandType = CommandType.StoredProcedure mcnn.Open() '-- Create the DataReader object odrTables = ocmdTables.ExecuteReader() '-- Loop through and add table-type object names ' to the lstTables list box. If odrTables.GetString(3) = "TABLE" Then Me.lstTables.Items.Add(odrTables.GetString(2)) End If Loop mcnn.Close() Catch excpData As Exception MessageBox.Show("Error Occurred: " & excpData.Message) End Try End Sub Next, the code loops though each of the items returned by the command. Those of type TABLE are added to the lstTables items. Then the connection is closed. As mentioned, you will see a comparison to the literal "TABLE." The reason for this is that the fourth column returned is the same table type as the current table. The other two types are SYSTEMTABLE and VIEW. To see the data returned by the sp_tables stored procedure, open the Query Analyzer, located on the Start menu, in Programs, Microsoft SQL Server. After opening up the Query Analyzer, highlight the Northwind database, and then type execute sp_tables into the Query Edit window and press F5 to execute the query. The results will be shown in the bottom of the window. Page down through the data until you see some of the type "TABLE" (see Figure 8.6). Figure 8.6. Testing the built-in stored procedure called sp_tables. Do While odrTables.Read Page 286 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 7. On lstTables, add the code in Listing 8.13 to the SelectedIndexChanged event. This routine performs a similar feat to the previous routine in that it calls a built-in stored procedure in this case, sp_Columns. However, the next task in this step is to pass a parameter, TableName, which is the table chosen in lstTables. After the connection is opened, the data reader called odrColumns is loaded with the ExecuteReader command. After the lstColumns.Items.Clear() method is called to clear the list, the new columns are added to lstColumns Items collection. Last, the connection is closed. Listing 8.13 frmHowTo8_3.vb: Executing a SQL Server Built-In Stored Procedure That Lists the Columns of a Supplied Table in the Database Private Sub lstTables_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstTables.SelectedIndexChanged '-- Create the connection and specify the stored procedure to use. Dim ocmdColumns As New OleDb.OleDbCommand("sp_Columns", mcnn) Dim odrColumns As OleDb.OleDbDataReader Try '-- Specify the type of command being performed ocmdColumns.CommandType = CommandType.StoredProcedure ocmdColumns.Parameters.Add("@TableName", Me.lstTables.Text) mcnn.Open() '-- Create the DataReader object odrColumns = ocmdColumns.ExecuteReader() '-- Clear the current items in the list Me.lstColumns.Items.Clear() Page 287 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Loop through and add table type object names ' to the lstTables list box. Me.lstColumns.Items.Add(odrColumns.GetString(3)) Loop mcnn.Close() Catch excpData As Exception MessageBox.Show("Error Occurred: " & excpData.Message) End Try End Sub 8. On lstColumns, add the code in Listing 8.14 to the SelectedIndexChanged event. This routine iterates through the SelectedItems collection of the lstColumns ListBox control, adding the chosen column names to a string variable called strTemp. The length of the string is checked; if the length is greater than 0, the Text property of txtSQLString is set to the following expression: "Select " & strTemp & " From " & Do While odrColumns.Read Me.lstTables.Text. Listing 8.14 frmHowTo8_3.vb: Creating the SQL String Private Sub lstColumns_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstColumns.SelectedIndexChanged Dim strTemp As String Dim intNumColumns As Integer Dim oCurr As Object '-- Cycle through each of the selected columns of the table chosen ' and combine them into a string. For Each oCurr In Me.lstColumns.SelectedItems() If Len(strTemp) > 0 Then strTemp &= ", " End If strTemp &= oCurr Next '-- Take the string created and add it to the table ' ' name for a SQL String if columns are chosen. If Len(strTemp) = 0 Then Me.txtSQLString.Text = "" Else Page 288 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.txtSQLString.Text = "Select " & strTemp & " From " & _ Me.lstTables.Text End If End Sub 9. On btnView, add the code in Listing 8.15 to the Click event. This routine creates the new data adapter called odaDisplay passes the Text property of txtSQLString, and then fills the dtDisplay data table. dtDisplay is then set to the DataSource property of the data grid called dgDisplay. Listing 8.15 frmHowTo8_3.vb: Loading the DataGrid Control with the Specified Data Private Sub btnView_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnView.Click Dim odaDisplay As OleDb.OleDbDataAdapter Dim dtDisplay As New DataTable() Try '-- Take the txtSQLString text and create a data table; then set the ' data source of the data grid. odaDisplay = New OleDb.OleDbDataAdapter(Me.txtSQLString.Text, mcnn) odaDisplay.Fill(dtDisplay) Me.dgDisplay.DataSource = dtDisplay Catch excData As Exception MessageBox.Show(excData.Message) End Try End Sub Figure 8.5. You can set the sorting of the data grid displayed here by clicking on the desired column. Page 289 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html How It Works When the form is opened, the lstTables ListBox control is loaded with the tables from the Northwind database. When the user selects a table from the list, that table name is passed to the stored procedure that lists the columns in a table located in the database specified in the connection in this case, Northwind. These columns are loaded into lstColumns. The user can then click on multiple columns in lstColumns. The columns are then added to the SQL Select string that is created and stored in txtSQLString. When the btnView button is clicked, the string is passed to a DataAdapter control, filling a data table. The data is then displayed when the data source of the DataGrid control is set to the data table. Comments You can enhance this tool in a number of ways:   Allow users to click on multiple tables and automatically create the join. Add a list of columns for the user to choose to use for criteria, and allow the user to input the criteria.   Tip Use this tool as a base for editing or reporting the records that are returned. Let the users specify the sorting order using a combo box. This last enhancement isn't necessary using the DataGrid control because you can click on the column heading and have it sort the columns for you. The goal of this technique, as with others in this book, is to push you into thinking about the Page 290 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html possibilities of what you can accomplish with Visual Studio .NET and your databases. [ Team LiB ] Page 291 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.4 Make a Generic Search Form in a Visual Basic .NET Desktop Application Another useful utility that takes advantage of being data driven is a standard search form that you can use for any number of tables, such as customers, employees, or products. This How-To shows you how to create such a Windows Form so that all you need to use it with different tables is to set four custom properties of the form in code. You like to be able to provide a usable search form for my users, without having the hassle of creating a custom form for every topic that the users are maintaining. In this How-To, you will see how to create a form that provides a quick lookup for records and can be used with various topics, such as Customers and Employees, by setting up only a few custom properties on the search form. Technique The forms package of Visual Basic has a class module behind it where you can add your own properties and methods. The .NET version of it is no exception. In this How-To, you will see a simple use for custom properties that are being added to a form. Properties can be specified on a form by adding the following syntax to your form: Public Property PropertyName() As DataType Get PropertyName = ModuleLevelMemoryVariable End Get Set(ByVal Value As DataType) ModuleLevelMemoryVariable = Value End Set End Property With the ModuleLevelMemoryVariable being declared in the module declaration area of the form's class module, you can see the properties created for the search form, called frmHowTo8_b.vb, in Listing 8.16. Listing 8.16 frmHowTo8_4b.vb: Creating Custom Properties for the Search Form Private Private Private Private Private mstrDisplayName As String mstrRecordSource As String mstrSearchField As String moResultValue As Object mstrKeyField As String Public Property DisplayName() As String Get DisplayName = mstrDisplayName End Get Set(ByVal Value As String) mstrDisplayName = Value End Set End Property Public Property SearchRecordSource() As String Get SearchRecordSource = mstrRecordSource End Get Set(ByVal Value As String) mstrRecordSource = Value Page 292 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Set End Property Public Property SearchField() As String Get SearchField = mstrSearchField End Get Set(ByVal Value As String) mstrSearchField = Value End Set End Property Public Property KeyField() As String Get KeyField = mstrKeyField End Get Set(ByVal Value As String) mstrKeyField = Value End Set End Property Public Property ResultValue() As Object Get ResultValue = moResultValue End Get Set(ByVal Value As Object) moResultValue = Value End Set End Property By assigning values to these properties after initiating an instance of the form, you can utilize the properties and the data stored in those properties from within the forms properties and methods, as well as the procedures assigned to the events within the form. For more information on creating custom classes, properties, and methods for use with your database application, see Chapter 9, "Using Classes with Databases to Make Life Easier." Steps Open and run the VB.NET Chapter 8 solution. From the main Windows Form, click on the command button with the caption How-To 8.4a. This form is a simple one that contains text boxes for the Customer table in Northwind. Click on the Search button to open the search form. Click on the button labeled B. You will see the data grid displayed in the bottom of the form filled with the CompanyName column of the Customer table, beginning with the letter B (see Figure 8.7). Figure 8.7. This form can be used for searching within any of the tables in your databases. Page 293 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Place the cursor in one of the customers displayed in the grid, and then click Accept. The search form will be hidden, and the fields in the first form will be filled in with the data from the chosen record. 1. Create a Windows Form. Then place the controls on the form shown in Figure 8.7, with the properties set forth in Table 8.5. Table 8.5. Label, TextBox, and Command Button Controls Property Settings for the Calling Form Object Property Setting Label Label Label Label Label Label Label Label Label Caption Caption Caption Caption Caption Caption Caption Caption Caption Customer ID Company Name Contact Contact Title Address City Region Country Phone Page 294 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox Button Caption Name Name Name Name Name Name Name Name Name Name Name Name Caption Fax txtCustomerID txtCompanyName txtContact txtContactTitle txtAddress txtCity txtRegion txtPostalCode txtCountry txtPhone txtFax btnSearch &Search 2. On btnSearch, add the code in Listing 8.17 to the Click event. This routine shows the power of creating custom properties. After instantiating an instance of the Search form in this case, frmHowTo8_4b.vb the four custom properties shown in Listing 8.17 are set before the form is displayed. This is powerful in letting you get the form set up exactly the way you want to before the user even sees it. After setting up the custom properties, the ShowDialog method is called off of frmSearch. By calling this method, code execution is halted until the form is closed or hidden. This same line of code compares the DialogResult property of the form to the value; if it matches, the code calls the LoadIndividual routine, passing the ResultValue custom property of frmSearch. Both the DialogResult and ResultValue properties are set in frmSearch and will be shown later in these steps. Listing 8.17 frmHowTo8_4a.vb: Executing a SQL Server-Supplied Stored Procedure That Lists the Tables in the Database Private Sub btnSearch_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSearch.Click '-- Instantiate the search forms. Dim frmSearch As frmHowTo8_4b frmSearch = New frmHowTo8_4b() '-- Set the custom data properties on the search form. ' This is what makes it so data driven. Page 295 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmSearch.DisplayName = "Customers" frmSearch.SearchRecordSource = "Customers" frmSearch.SearchField = "CompanyName" frmSearch.KeyField = "CustomerID" '-- Open the search form as dialog. ' ' ' Based on the DialogResult property, use the custom property ResultValue property and load the requested record. If frmSearch.ShowDialog() = DialogResult.OK Then LoadIndividual(frmSearch.ResultValue) End If End Sub 3. Create the LoadIndividual routine by entering the code shown in Listing 8.18 into the form. Taking the strKeyValue passed from the results of the search, a data adapter is created and a DataSet is filled. Next, the individual data row is created. Last, each of the TextBox controls is loaded with the value from the column with the corresponding name. Notice the use of the Try…Catch…End Try to ignore controls that don't have a like column in the data row. Listing 8.18 frmHowTo8_4a.vb: Loading an Individual Record into Text Boxes on the Form Private Sub LoadIndividual(ByVal strKeyValue As String) Dim strSQL As String Dim strName As String Dim oCtl As Object Dim dsCustIndiv As New DataSet() Dim odaCustIndiv As OleDb.OleDbDataAdapter Dim drCustIndiv As DataRow Try '-- Load the individual record into the dataset strSQL = "Select * from Customers Where CustomerID = '" & strKeyValue & "'" odaCustIndiv = New OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) '-- Fill the dataset odaCustIndiv.Fill(dsCustIndiv, "Customers") '-- Grab the individual data row drCustIndiv = dsCustIndiv.Tables("Customers").Rows(0) Page 296 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Catch oexpData As OleDb.OleDbException MessageBox.Show("Error loading individual data: " & _ oexpData.Message) Exit Sub End Try '-- Run through the text boxes on the form. '-- If they match up with a field from the record, load them. For Each oCtl In Me.Controls If TypeOf oCtl Is TextBox Then strName = Mid(oCtl.Name, 4) '-- By trapping the exception this way, errors are ignored. Try oCtl.text = drCustIndiv(strName).ToString Catch oexp As Exception End Try End If Next End Sub 4. Create the next Windows Form and call it whatever name you referred to in the search form in step 2. Then place the controls shown in Figure 8.7 of the search form, with the properties set as in Table 8.6. Table 8.6. Label, TextBox, DataGrid, and Command Button Controls Property Settings for the Calling Form Object Property Setting GroupBox Name Text GroupBox1 Click on a Letter btnA A btnB B btnC Button Name Caption Button Name Caption Button Name Page 297 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Caption ... Button Name Caption Button Name Caption DataGrid Button Name Name Caption Button Name Caption 5. C btnZ Z btnAll All dgSearch btnAccept &Accept btnCancel &Cancel Create the custom properties discussed in the "Technique" section of this How-To and found in Listing 8.19. Each of the properties is self-explanatory. Listing 8.19 frmHowTo8_4b.vb: Creating Custom Properties for the Search Form Private mstrDisplayName As String Private mstrRecordSource As String Private mstrSearchField As String Private moResultValue As Object Private mstrKeyField As String Public Property DisplayName() As String Get DisplayName = mstrDisplayName End Get Set(ByVal Value As String) mstrDisplayName = Value End Set End Property Public Property SearchRecordSource() As String Get SearchRecordSource = mstrRecordSource End Get Set(ByVal Value As String) mstrRecordSource = Value End Set End Property Page 298 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Public Property SearchField() As String Get SearchField = mstrSearchField End Get Set(ByVal Value As String) mstrSearchField = Value End Set End Property Public Property KeyField() As String Get KeyField = mstrKeyField End Get Set(ByVal Value As String) mstrKeyField = Value End Set End Property Public Property ResultValue() As Object Get ResultValue = moResultValue End Get Set(ByVal Value As Object) moResultValue = Value End Set End Property 6. On the form, add the code in Listing 8.20 to the Load event. This routine ensures that the calling form set the DisplayName custom property; thus, this routine can assume that the others were set as well. If not, a message box is displayed. If so, the Text property of the form, which is displayed in the Title bar, is set to DisplayName. Listing 8.20 frmHowTo8_4b.vb: Executing a SQL Server-Supplied Stored Procedure That Lists the Tables in the Database Private Sub frmHowTo8_4b_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If Len(Me.DisplayName) = 0 Then MessageBox.Show("Form specific properties not set.") Me.Close() Else Me.Text = Me.Text & " " & Me.DisplayName End If End Sub Page 299 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 7. For each of the command buttons that has a single letter, add the first subroutine displayed in Listing 8.21 to each of the Click events. For the btnAll Button control, add the second subroutine to the Click event. Each Button control will pass the letter it represents to the subroutine called SetData, discussed in the next step. The btnAll code simply passes the empty string. Listing 8.21 frmHowTo8_4b.vb: Click Events for Each of the Letter Button Controls Private Sub btnA_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnA.Click SetData("A") End Sub Private Sub btnAll_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAll.Click SetData("") End Sub 8. Add the subroutine in Listing 8.22 to the class module of the form. This routine takes the letter value passed in strFilterLetter as a parameter. A SQL Select string is created that takes the literal values Select, From, and Where and uses the custom properties KeyField, SearchField, and SearchRecordSource. The SearchField property is used with the Like clause, also using the strFilterLetter and the % (wildcard). Note that if "" is passed to strFilterLetter, all the records will be listed. Finally, odtSearch is filled and set as the data source for dgSearch, which is the DataGrid control. Listing 8.22 frmHowTo8_4a.vb: Filling the Results Set Based on the Letter Button That Was Pressed Sub SetData(ByVal strFilterLetter As String) Dim odaSearch As OleDb.OleDbDataAdapter Dim dtSearch As DataTable = New DataTable() odaSearch = New _ OleDb.OleDbDataAdapter("Select " & Me.KeyField & ", " & Me.SearchField & " From " & Me.SearchRecordSource & " Where " & Me.SearchField & " Like '" & strFilterLetter & "%'", (BuildCnnStr("(local)", "Northwind"))) odaSearch.Fill(dtSearch) dgSearch.DataSource = dtSearch End Sub Note This routine more than any in this How-To shows the flexibility of this technique. You can use any table values for these properties. Just think of how many places you can use this form without changing a line of Page 300 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html code in the form. 9. On the buttons called btnAccept and btnCancel, add the code in Listing 8.23 to the appropriate Click event of each. The btnAccept_Click routine creates a DataTable object from the data grid's DataSource property. Then it derives the data row that is currently selected from that data table. The KeyField property is used to store the individual column value of drCurr into the ResultValue custom property. The DialogResult property is set to OK, and the form is hidden with the Hide method. By hiding the form, you can still read the properties of the form without the user seeing it. In the btnCancel_Click routine, the DialogResult is set to No, and the form is closed. This action tells the calling form that the search was canceled. Listing 8.23 frmHowTo8_4b.vb: Storing the Resulting Key Value to the ResultValue Custom Property and Setting the DialogResult Private Sub btnAccept_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAccept.Click Dim dtFromGrid As DataTable Dim drCurr As DataRow Try '-- Using the DataRow and DataTable objects of the DataGrid control, ' ' ' ' get the selected result and assign it to the custom property ResultValue. Then set the DialogResult property to DialogResult.OK, and hide the form so that the calling form can still access it. dtFromGrid = CType(dgSearch.DataSource, DataTable) drCurr = dtFromGrid.Rows(Me.dgSearch.CurrentRowIndex()) Me.ResultValue = drCurr(Me.KeyField).ToString Me.DialogResult = DialogResult.OK Me.Hide() Catch exp As Exception Me.DialogResult = DialogResult.No Me.Close() End Try End Sub Private Sub btnCancel_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCancel.Click Page 301 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.DialogResult = DialogResult.Cancel Me.Close() End Sub How It Works When the user clicks on the search button, the calling form sets the custom properties of the search form, telling it what record source to use, as well as other information used for searching for the specific record and domain desired in this case:     Customers for the property DisplayName Customers for the property SearchRecordSource CustomerID for the property KeyField CompanyName for the property SearchField After the search form is loaded, the user presses one of the letters to narrow down the records to look for, a data adapter is passed a SQL String made up of the properties just mentioned, a data table is filled, and the data grid's DataSource property sets the data table. When the user clicks Accept, the data table is retrieved from the data grid, which then produces the data row that contains the key field. This is stored into the ResultValue property of the search form, the DialogResult property is set to DialogResult.OK, and the form is hidden. Back on the calling form, the LoadIndividual routine is called and passed the ResultValue property from the search form. The text boxes are then loaded with the data row results. Comments This technique shows a number of ways that the various ADO.NET objects can be used. Take a close look at the use of the dialog style form, forcing code execution to halt until you hide or close the form. This is a technique that you will use throughout your applications after you get used to it. Again, you can enhance this tool in a number of ways. One way is to allow the user to enter a string value to type in, narrowing down the choices even more, and another is to add a property that could be used to specify multiple columns to be displayed. [ Team LiB ] Page 302 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.5 Work with Data-Bound Multi-Select List Boxes Using Web Forms As with How-to 8.1, this example will show you how to take advantage of multi-select list boxes, only with a Web Form instead of a Windows Form. You need to be able to manipulate multi-select list boxes in your Web applications using ASP.NET as well as in your Visual Basic .NET desktop applications. This How-To shows you how to use just about the same coding techniques as in How-To 8.1, but with the change of using the Web Form. Technique When you are performing a task in a Web Form that you have created in a Windows Form, you would think it would take the same effort if not more to accomplish the task. However, this is not the case for this How-To. The commands available to the Windows Form ListBox control will give better performance because you have a SelectedIndexes collection to work with, and in the Web Form you iterate through all the items in the ListBox control and check the Selected property. Nonetheless, coding on the Web Form is simpler. Unlike the Windows Form version of the ListBox Control, which has four different settings for the SelectionMode property, the Web Form version has two: Single or Multiple. Another thing to keep in mind when developing with data and the Web Form is that you will need to use the DataBind method off the ListBox control to bind the data at runtime. In the Load event of the page, you will want to use the IsPostBack method of the page to ensure that you perform certain tasks only when the page is initially loaded, and not on a round trip that pages take back to the server. Steps Open and run the VB.NET Chapter 8 solution. From the main Web Form, click on the hyperlink with the caption How-To 8.5: Work with Data-Bound Multi-Select List Boxes Using a Web Form. You will then see the page displayed in Figure 8.8. Figure 8.8. This Web Form uses controls bound at runtime and takes advantage of multi-select list boxes. Page 303 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When the page loads, you will see the Beverages category chosen in the top combo box. The Selected and Unselected Products ListBox controls are filled in with the appropriate products. If you click on a product in the Unselected Products list box and then click on the arrow button pointing to the right (>), the item is moved to the Selected Products list box. If you select items in the Selected Products list box and click on the arrow button pointing to the left (<), those items are moved to the Unselected Products list box. If you click on the Unassigned Products Only check box at the bottom of the form, the Unselected Products list box is filled with products that are not assigned to any category. Note If you check the Unassigned Products Only check box when you are first getting into Northwind and running this example, you probably won't see unassigned items. You will need to unselect products from a category. 1. Create a Web Form. Then place the controls shown in Figure 8.8 with the properties set as seen in Table 8.7. Table 8.7. Label, ComboBox, ListBox, and Command Button Control Property Settings Object Property Setting DOCUMENT Label bgColor Name buttonface Label1 Page 304 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text DropDown Label Name Name Text ListBox Name SelectionMode Label Name Text ListBox Name SelectionMode Command Button Name Text Command Button Name Text CheckBox Label Name Name Text HyperLink Name Text NavigateURL wfrmMain.aspx 2. Note Category: ddCategories Label2 Unselected Products lstUnSelected Multiple Label3 Selected Products lstSelected Multiple btnSelect > btnUnSelect < chkUnAssignedOnly Label4 UnAssigned Products Only hplReturnToMain Return To Main HyperLink is optional. It is just used to get back to the main sample page for this chapter. 3. As with some of the other chapters' projects, before creating the code that will be attached to the Load event of the form, you need to build a support routine to create the Connection string. Called BuildCnnStr, the function can be seen in Listing 8.24. This function takes a server and database names that are passed to it and creates a Connection string. Page 305 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 8.24 modGeneralRoutines.vb: Creating a Connection String Function BuildCnnStr(ByVal strServer As String, _ ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Although you could create a routine that would pass back a Connection object, a more versatile method would be to pass back a string. Some objects ask you for a Connection object, but others just want a string. You will see BuildCnnStr called in the next step. 4. On the form, add the code in Listing 8.25 to the Load event. In this code, the first task is to make sure the code is run only once in the page, when it is first loading. The Not IsPostBack check performs this task. Next, you will create a data adapter called odaCategories and load the categories SQL Statement into it. The dtCategories data table is filled and set as the DataSource property of ddCategories. The DataTextField and DataValueField of ddCategories are then set. After that, the DataBind method of the DropDown is called. This is necessary for binding data to the server controls on Web Forms. Finally, two new subroutines called LoadUnSelectedProducts and LoadSelectedProducts are called to populate the appropriate list boxes. These routines are discussed in the next two steps. Listing 8.25 wfrmHowTo8_5.aspx: Loading Categories into a List Box Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here Dim odaCategories As OleDb.OleDbDataAdapter Dim dtCategories As New DataTable() '-- Make sure this code is only executed when the page is first loaded. If Not Page.IsPostBack Then '-- Load up the Categories DropDown control odaCategories = New _ OleDb.OleDbDataAdapter("Select CategoryID, CategoryName " & _ " From Categories", BuildCnnStr("(local)", "Northwind")) odaCategories.Fill(dtCategories) Me.ddCategories.DataSource = dtCategories Page 306 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.ddCategories.DataTextField = "CategoryName" Me.ddCategories.DataValueField = "CategoryID" '-- This is necessary for Web Forms, but not used on Windows Forms. Me.ddCategories.DataBind() LoadUnSelectedProducts() LoadSelectedProducts() End If End Sub 5. Create the LoadUnSelectedProducts routine, shown in Listing 8.26, by entering the following code in the Web Form that you created for this How-To. This routine starts off by testing the check box called chkUnAssignedOnly. Based on that value, a SQL string is created that grabs the products that are either not assigned to any product, if chkUnAssignedOnly = True, or all products that are not assigned to the chosen category are retrieved. The SQL String is stored in the variable called strSQL. Next, the DataAdapter object called odaUnselected is set to strSQL and the SQL Server connection string. The DataTable object called dtUnSelected is then filled. The Dispose method of the ListBox control is called to remove current items, and dtUnSelected is assigned to the DataSource property of lstUnSelected. Then the DataTextField and DataValueField properties are set. Last, the DataBind and ClearSelected methods are called to bind the lstUnSelected and ensure that no entries are left selected. Listing 8.26 wfrmHowTo8_5.aspx: Populating the List Box That Displays Unselected Products Sub LoadUnSelectedProducts() Dim odaUnSelected As OleDb.OleDbDataAdapter Dim dtUnSelected As New DataTable() Dim strSQL As String '-- If the check box for unassigned only is checked, then ' ' grab the product items where the category is null; otherwise, load it up with those products not assigned to the current category. If chkUnAssignedOnly.Checked Then strSQL = "Select ProductID, ProductName From Products " & "Where CategoryID IS NULL Order By ProductName" Else strSQL = "Select ProductID, ProductName From Products " & _ Where CategoryID <> " & End If '-- Load up the lstUnselected based off the SQL string. ddCategories.SelectedItem.Value & _ " Or CategoryID IS NULL Order By ProductName" Page 307 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html odaUnSelected = New OleDb.OleDbDataAdapter(strSQL, BuildCnnStr("(local)", "Northwind")) odaUnSelected.Fill(dtUnSelected) Me.lstUnSelected.Dispose() Me.lstUnSelected.DataSource = dtUnSelected Me.lstUnSelected.DataTextField = "ProductName" Me.lstUnSelected.DataValueField = "ProductID" '-- Needed on Web Forms. Me.lstUnSelected.DataBind() Me.lstUnSelected.ClearSelection() End Sub 6. Create the LoadSelectedProducts routine by entering the code in Listing 8.27 into the form you created for this How-To. This routine basically performs the same tasks that the routine listed in the previous step does, except that it performs the tasks using the lstSelected ListBox control. This routine also doesn't need to test the CheckBox control. Listing 8.27 wfrmHowTo8_5.aspx: Populating the List Box That Displays Selected Products Sub LoadSelectedProducts() Dim odaSelected As OleDb.OleDbDataAdapter Dim dtSelected As New DataTable() Dim strSQL As String '-- Create the SQL string for the category chosen in the ' ddCategories dropdown. Then load the data table with the data ' and bind the lstSelected list box. strSQL = "Select ProductID, ProductName From Products " & _ "Where CategoryID = " & _ ddCategories.SelectedItem.Value & " Order By ProductName" odaSelected = New _ OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) odaSelected.Fill(dtSelected) Me.lstSelected.Dispose() Me.lstSelected.DataSource = dtSelected Me.lstSelected.DataTextField = "ProductName" Me.lstSelected.DataValueField = "ProductID" Page 308 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.lstSelected.DataBind() Me.lstSelected.ClearSelection() End Sub 7. Add the code in Listing 8.28 to the SelectedIndexChanged event of the ddCategories drop-down. Listing 8.28 wfrmHowTo8_5.aspx: Repopulating the List Boxes Based on the Current Category That Is Selected Private Sub ddCategories_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles ddCategories.SelectedIndexChanged LoadUnSelectedProducts() LoadSelectedProducts() End Sub 8. Add the code in Listing 8.29 to the CheckChanged event of the chkUnAssignedOnly check box. Listing 8.29 wfrmHowTo8_5.aspx: Calling the Routine to Reload the lstUnSelected List Box If This Check box Is Changed Private Sub chkUnAssignedOnly_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkUnAssignedOnly.CheckedChanged LoadUnSelectedProducts() End Sub 9. Add the code in Listing 8.30 to the Click event of the btnSelect command button. This and the next step contain the most code as well as some new objects and properties. First, the number of highlighted items (SelectedIndices.Count) is stored to an Integer variable called intItemsNum. A 1 is subtracted off the figure because the collections in .NET are zero based. Next, the code iterates through the Items collection of the lstUnSelected list box, testing the Selected property for selected items. The Value property of the item is converted to a string and added to a string variable called strItems. strItems is then used to create the criteria for an IN clause of a SQL Update statement, which is passed to the Command object called ocmdSelect. This Command object is executed, and the selected products are updated to reflect the category chosen. Last, both the list boxes are reloaded to reflect the changes. Listing 8.30 wfrmHowTo8_5.aspx: Updating the Server with Products That Are Selected for the Given Category Private Sub btnSelect_Click(ByVal sender As System.Object, Page 309 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ByVal e As System.EventArgs) Handles btnSelect.Click Dim intItemsNum As Integer Dim strItems As String Dim oCurr As Object '-- Iterate through each of the items in lstUnSelected ' ' and check the Selected property. If selected, store into a string with other selected product IDs. For Each oCurr In Me.lstUnSelected.Items If oCurr.Selected() = True Then If Len(strItems) > 0 Then strItems = strItems & ", " End If strItems = strItems & CType(oCurr.Value, String) End If Next '-- Run an update query to assign the category to the desired products, ' Try Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmdSelect As New _ OleDb.OleDbCommand("Update Products Set CategoryID = " & Me.ddCategories.SelectedItem.Value & _ " Where ProductID IN (" & strItems & ")", ocnn) ocmdSelect.CommandType = CommandType.Text ocnn.Open() ocmdSelect.ExecuteNonQuery() Catch excpCommand As Exception End Try LoadUnSelectedProducts() LoadSelectedProducts() End Sub 10. Add the code in Listing 8.31 to the Click event of the btnUnSelect command button. Again, this code is similar to the previous step, but it is used to set the CategoryID column to null if the product was highlighted in the lstSelected list box and btnUnSelect was clicked. using an IN clause in the SQL statement. Page 310 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 8.31 frmHowTo8_5.aspx: Updating the Server with Products That Are Unselected for the Given Category Private Sub btnUnSelect_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUnSelect.Click Dim intItemsNum As Integer Dim strItems As String Dim oCurr As Object '-- Iterate through each of the items in lstSelected ' ' and check the Selected property. If selected, store into a string with other selected product IDs. For Each oCurr In Me.lstSelected.Items If oCurr.Selected() = True Then If Len(strItems) > 0 Then strItems = strItems & ", " End If strItems = strItems & CType(oCurr.Value, String) End If Next Try Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmdUnSelect As New _ OleDb.OleDbCommand("Update Products Set CategoryID = Null " & _\\ "Where ProductID IN (" & _ strItems & ")", ocnn) ocmdUnSelect.CommandType = CommandType.Text ocnn.Open() ocmdUnSelect.ExecuteNonQuery() Catch excpCommand As Exception End Try LoadUnSelectedProducts() LoadSelectedProducts() End Sub How It Works Page 311 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When the user chooses a category, the appropriate items are loaded into the two list boxes. Unselected items are in the list box on the left, and the selected items are in the list box on the right. If the check box is selected, then those only those items that are not currently assigned to categories are displayed in the list box on the left, which is titled Unselected Products. When the btnSelect button is clicked, any items that are highlighted in the lstUnSelected list box are used in a query that updates the server with the new category they now belong to. Similarly, when the btnUnSelect is clicked, items that are listed in the lstSelected list box are used in a query that updates the CategoryID of the products to null. Comments As mentioned in How-To 8.1, this example is not the smartest to create in real life because you want products to be assigned to a category. However, this example does a good job of showing the properties and methods you can use to work with the multi-select features of the ListBox control. [ Team LiB ] Page 312 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.6 Use a Single Web Form to Update Multiple Lookup Tables As with the second tutorial(8.2), this example will show you how to update multiple lookup tables this time using a Web Form. Creating a Web Form for viewing multiple lookup tables would take about the same if not less code than performing the same task using the Windows Form. Updating, adding, and deleting data takes a bit more work, though. This How-To will show you how to accomplish this task by using the DataGrid control and show you how to take advantage of Session variables and paging within the data grid when you're manipulating data. Technique The DataGrid control is a powerful control, as you saw in Chapter 5, "Working with Data on Web Forms," but when programming in Web Forms, it takes some getting used to. Because the Web Forms are stateless, you need to keep reminding the data grid what it is bound to. Also, even though you declare a variable at the module level behind the form, you will notice that whenever the form goes back to the server for information, you lose the values of your variables. The workaround for this is the use of the Session object. Note A full discussion of State management in .NET and the various options is presented in Chapter 5. This also includes how to use the options for the data grid manipulation portion of this How-To. The other major issue with this How-To is managing the paging of the DataGrid control, covered in Chapter 4. You will quickly learn the steps of creating the Web Form that allows users to update Lookup tables. Steps Open and run the VB.NET Chapter 8 solution. From the main Web Form, click on the hyperlink with the caption How-To 8.6: Use a Single Web Form for Updating Multiple Lookup Tables. Click on the first choice, Categories, in the list box labeled Lookup Table to Edit. The data grid will then appear. The grid will be filled in with the data of the table you chose. Your page will then look like the page displayed in Figure 8.9. Figure 8.9. On this page, you can add, edit, and delete information for all your simple lookup tables. Page 313 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You can now add data into the data grid by clicking on the Add New button, located under the Error box. When you click on the Add New button, an entry is added to the data grid, and you are placed in Edit mode, shown in Figure 8.10. Figure 8.10. Adding new data to your lookup tables using the DataGrid control. After entering the data into the fields, you will click Update. The values are then saved back to the server. If you don't want to save the new entry, click the Cancel button, and the data grid makes the entry disappear. Page 314 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Tip You will notice that the look of the columns is a little congested and changes when you go to edit the data. You can avoid this by creating and using templates with the data grid. Of course, if you are using templates with the data grid, you have to change the template based on the lookup table you were using. Tip You will also notice that the CategoryID field has been disabled and can't be edited. This is through the use of a method, FillSchema, which fills data table with schema information from the record source. In this case, FillSchema passed on the information that the CategoryID was an AutoIncrement field, and the data grid was smart enough to handle it. When you click on the Edit button, the page will look similar to Figure 8.10, except that data already will be present in the fields. When you click Delete, the entry is deleted. Any errors that might occur, such as from data integrity errors, will appear in the text box labeled Errors. If you try to delete a current category and Products uses that category, for example, then SQL Server causes an error to occur, and the page reports the error because of code created. 1. Create a Web Form. Then place the controls shown in Figure 8.9 with the properties shown in Table 8.8. Table 8.8. Label, TextBox, ListBox, and Command Button Control Property Settings Object Property Setting DOCUMENT Label bgColor Name Text buttonface Label1 Lookup Table to Edit: lstLookupTables True Label2 Lookup Table Data: dgLookupData ListBox Name AutoPostback Label Name Text DataGrid Name Page 315 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html AllowPaging PageSize Label Name Text TextBox Name ForeColor ReadOnly TextMode Button Name Text HyperLink Name NavigateURL 2. True 5 Label3 Errors: txtError Red True MultiLine btnAdd Add New hplReturnToMain wfrmMain.aspx On the newly created lstLookupTables ListBox control, click the Build button next to the Items property, which is a collection of names of the lookup tables to edit. After you have clicked the Build button, the ListItem Collection Editor opens. Enter the values Categories, Regions, and Territories, as shown in Figure 8.11. Click OK to accept the entries. Figure 8.11. These values allow you to update multiple lookup tables from a single Web Form. Page 316 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Tip To make this truly data driven, you could have these entries in a table in your database. Then you could point the DataSource property of the list box to the table. You could also have the table contain the names of the templates you wanted to use. A different approach was taken here so that you would not have to modify your copy of the Northwind database. 3. On the dgLookupData DataGrid control, click the Build button next to the Columns property. You will then be brought into the Columns tab of the dgLookupData Properties dialog box. Click on the plus sign by the Button column in the Available Columns list. You will then see the list of available button types you can use. Select the Edit, Update, Cancel, and Delete buttons. Set each of these buttons to have the PushButton button type. After you have made these selections, the dialog box will look like Figure 8.12. Click OK to accept the entries. Figure 8.12. Add some buttons to your DataGrid control. Page 317 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Now that you have added some buttons to the DataGrid control, you still have to tell the control how to react to the buttons. You will do that using events in code, but we need to add some tags to the HTML. The tags you will add are as follows: 5. 6. 7. 8. 9. OnUpdateCommand="dgLookupData_Update" OnCancelCommand="dgLookupData_Cancel" OnEditCommand="dgLookupData_Edit" OnDeleteCommand="dgLookupData_Delete" Click on the HTML tab of the Web Form in Visual Studio. Then you can see the HTML and insert the tags. By looking at the HTML shown in Figure 8.13, you can see where to put the tags. Of course, your HTML won't be as nicely laid out as this figure because Visual Studio scrunches it up. Figure 8.13. Add the tags in this step to tie in the events to the buttons in the DataGrid control. Page 318 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 10. Now it's time for the code. The first items to add are the code for the module level DataTable object variable declaration and the code that you want to add for the Load event of the page. Both are shown in Listing 8.32. The load event tests for the Session variable MyLookupData; if the variable exists, the event creates a reference to the data table using the mdtLookupData DataTable object. Listing 8.32 frmHowTo8_6.aspx: Tracking the DataTable Object Between Trips to the Server Private mdtLookupData As New DataTable() Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not (Session("MyLookupData") Is Nothing) Then mdtLookupData = CType(Session("MyLookupData"), DataTable) End If End Sub 11. Add the code in Listing 8.33 to the SelectedIndexChanged event of lstLookupTables. This code starts off by clearing the txtError TextBox control that is used to store the Exception object's Message property that is caught later in the routine. Next, the odaLookupData DataAdapter object is built by creating a SQL Select statement from the currently selected table in lstLookupTables. Now it's time to fill in the dtNew DataTable object, which is done using FillSchema and Fill. Page 319 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You have seen the Fill method before. FillSchema tells .NET to do just that return the Schema to the data table, thus having your DataTable object use properties such as AutoIncrement, DataTypes, and even Constraints. Next, the code reassigns the mdtLookupTable reference to point to dtNew. This works well for using the DataTable and DataGrid objects with different tables, which not only clears the data, but also resets what columns are being used in the data table object. You can see that mdtLookupData is being stored to a Session object entry called MyDataTable, and a Boolean variable called IsAdding is set to False. This last variable will be set to True when the btnAdd is clicked and used for special handling when updating and canceling the editing of the data grid. Tip You really need to watch where you are storing values to the Session object and other state management objects. Make sure you do store these objects before calling methods or accessing properties of server controls such as the DataGrid control. Next, the EditItemIndex property is set to 1 to unselect any item that is being edited. Then the CurrentPageIndex property is reset to 0 to reflect the first page in the data grid. The data grid is then filled and the subroutine BindTheGrid() is called. You can find this subroutine at the bottom of the listing. This routine sets the DataSource property of the DataGrid control to mdtLookupData and calls the DataBind method of the DataGrid control. Listing 8.33 frmHowTo8_6.aspx: Tracking the DataTable Object Between Trips to the Server Private Sub lstLookupTables_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles lstLookupTables.SelectedIndexChanged Dim odaLookupData As OleDb.OleDbDataAdapter Dim dtNew As New DataTable() Me.txtError.Text = "" Try '-- Take the txtSQLString text and create a data table; then set the ' data source of the data grid. odaLookupData = New OleDb.OleDbDataAdapter("Select * From " & _ Me.lstLookupTables.SelectedItem.ToString, BuildCnnStr("(local)", "Northwind")) Page 320 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Test for identity and display any other notes. odaLookupData.FillSchema(dtNew, SchemaType.Source) '-- Get the data and put it in the data table. odaLookupData.Fill(dtNew) '-- Save the data table to a session variable so that ' ' you don't lose it on a trip back to the server. Set the flag for adding new records to False. Session("IsAdding") = False Session("MyLookupData") = dtNew mdtLookupData = dtNew Me.dgLookupData.EditItemIndex = -1 Me.dgLookupData.CurrentPageIndex = 0 '-- Bind the data grid to the data table BindTheGrid() Catch excp As Exception '-- If an error occurs, stash the error message to a text box. Me.txtError.Text = excp.Message End Try End Sub Sub BindTheGrid() '-- Bind the data grid Me.dgLookupData.DataSource = mdtLookupData Me.dgLookupData.DataBind() End Sub 12. Add the code in Listing 8.34 to the Edit command of dgLookupData. This is one of the events specified in step 4. This code sets the EditItemIndex of the DataGrid object to the selected item and then binds the data. Listing 8.34 frmHowTo8_6.aspx: Telling the DataGrid Object to Use the Selected Item and Go into Edit Mode (Display Wise) Sub dgLookupData_Edit(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) '-- The data grid does most of the work; just set the EditItemIndex ' to the ItemIndex and bind the grid again. Page 321 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.txtError.Text = "" dgLookupData.EditItemIndex = e.Item.ItemIndex BindTheGrid() End Sub 13. Add the code in Listing 8.35 to the Click event of btnAdd. Notice that the first task invokes the BeginLoadData method for mdtLookupData. This turns off the schema checking that will occur when adding the new row to the DataTable object. You need to turn this off because you don't want to have it check for required fields until you actually edit the record. The editing of the record is started by the line of code setting the EditItemIndex property of the DataGrid object. The GetPageNum() routine helps to synchronize the DataGrid page with the position the pointer is in the DataTable object. If you add a record, you have to know whether to have it be on the current page or on a new page in the data grid. You can see GetPageNum after btnAdd_Click in Listing 8.35. GetPageRows(), found at the bottom of Listing 8.35, returns the number of actual rows based on the page in the data grid. Note GetPageRows() returns the current page number ( dgLookupData.CurrentPageIndex) times the page size (dgLookupData.PageSize). In this case, GetPageRows() returns 5, as set in step 1. If EditItemIndex were used alone, it would return only the position of the item that was being edited for the current page. Last, the EditItemIndex of dgLookupData is set. The data grid is bound to the data table using the BindTheGrid routine. Listing 8.35 frmHowTo8_6.aspx: Adding a Record to the Data Table and Having the Data Grid Reflect It Private Sub btnAdd_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAdd.Click Dim intColCnt As Integer Dim drCurr As data row Me.txtError.Text = "" mdtLookupData.BeginLoadData() '-- Add the row to the data table via the data row drCurr = mdtLookupData.NewRow Page 322 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html mdtLookupData.Rows.Add(drCurr) '-- Set the Adding flag. Session("MyLookupData") = mdtLookupData Session("IsAdding") = True '-- Set the current page based on the new number of rows dgLookupData.CurrentPageIndex = GetPageNum(mdtLookupData) '-- Set the item index based on the rows on this page only. dgLookupData.EditItemIndex = mdtLookupData.Rows.Count - _ GetPageRows() - 1 BindTheGrid() End Sub Function GetPageRows() As Integer '-- This helps synchronize the data table rows ' with the DataGrid page and row. GetPageRows = dgLookupData.PageSize * dgLookupData.CurrentPageIndex End Function Function GetPageNum(ByVal dt As data table) As Decimal Dim decTemp As Decimal '-- Calculate the number of pages decTemp = ((dt.Rows.Count - 1) / dgLookupData.PageSize) GetPageNum = decTemp.Truncate(decTemp) End Function 14. Add the code shown in Listing 8.36 to the Cancel command of dgLookupData. This is one of the events specified in step 4. If the code is in the middle of adding an entry, it uses the EditItemIndex of the DataGrid object to the selected item and adds this to the value returned by GetPageRows(), shown just after the dgLookupData_Cancel subroutine. The value that EditItemIndex and GetPagerows() returns is used to position the pointer in mdtLookupData so that the Delete method can be called. After accepting the changes, the session variables are resaved. Then the page index for the DataGrid object is cleaned up by comparing the current page number relative to the pointer of the data table position to the CurrentPageIndex property. Regardless of whether the item is being added or edited, the EditItemIndex is cleared by setting it to 1. The data grid is bound again by calling BindTheData(). Page 323 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 8.36 frmHowTo8_6.aspx: Canceling Editing/Adding a Record in the DataGrid Object Sub dgLookupData_Cancel(ByVal sender As Object, ByVal e As DataGridCommandEventArgs) Dim blnAdding As Boolean '-- If you're canceling while adding a record, you need to back the ' ' ' row out of the data table and data grid. You don't have to send it to the server because it really was never added to it. Me.txtError.Text = "" If CType(Session("IsAdding"), Boolean) Then mdtLookupData.Rows(dgLookupData.EditItemIndex + _ GetPageRows()).Delete() mdtLookupData.AcceptChanges() Session("IsAdding") = False Session("MyLookupData") = mdtLookupData '-- Reset the paging if it has been affected If GetPageNum(mdtLookupData) < dgLookupData.CurrentPageIndex Then dgLookupData.CurrentPageIndex -= 1 End If End If dgLookupData.EditItemIndex = -1 BindTheGrid() End Sub 15. Add the code in Listing 8.37 for the Delete command of dgLookupData. This is one of the events specified in step 4. This code is a lot like the code in the previous step when the record was added. The big difference in this step's code listing is that the deletion is posted back to the server, and in the previous step, it wasn't. It wasn't posted back to the server in the previous step because the server never knew anything about the record. The record had only been added to the data table and was not sent back to the server. You can see that in the next step. Another item to note is the RejectChanges method called in the Catch of the exception handling code. If an error occurs, the change is undone, the message is noted, and life goes on. The rest of this code pretty closely follows what was done in the previous step. Listing 8.37 frmHowTo8_6.aspx: Deleting a Record from the Data Grid and Posting It Back to the Server Page 324 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Sub dgLookupData_Delete(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) Dim intColCnt As Integer Dim cnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) '-- Create the command builder to update (post) the data ' ' in the data grid back to the server. Dim odaTableData As OleDb.OleDbDataAdapter Me.txtError.Text = "" Try '-- Take the txtSQLString text and create a data table. Then set the ' data source of the data grid. odaTableData = New OleDb.OleDbDataAdapter("Select * From " & _ Me.lstLookupTables.SelectedItem.ToString, cnn) Dim ocbTableData As OleDb.OleDbCommandBuilder = _ New OleDb.OleDbCommandBuilder(odaTableData) '-- Delete the row from the data table. mdtLookupData.Rows(e.Item.ItemIndex + GetPageRows()).Delete() '-- Commands are necessary to actually post back to the server. cnn.Open() odaTableData.Update(mdtLookupData) mdtLookupData.AcceptChanges() cnn.Close() Session("MyLookupData") = mdtLookupData Session("IsAdding") = False '-- This is just in case they were editing and press Delete, Clear. dgLookupData.EditItemIndex = -1 '-- Adjust the page according to the number of rows. If GetPageNum(mdtLookupData) < dgLookupData.CurrentPageIndex Then dgLookupData.CurrentPageIndex -= 1 End If Catch excp As Exception Page 325 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.txtError.Text = excp.Message mdtLookupData.RejectChanges() End Try BindTheGrid() End Sub 16. Add the code in Listing 8.38 for the Update command of dgLookupData. This is one of the events specified in step 4. This routine starts off by declaring DataAdapter and CommandBuilder objects to update your data back to the server. Before the actual update, however, the current row that is being edited in the data grid is assigned to a DataRow object. Then each of the items in the row is saved from the data grid cells to the column in the data row. Thanks to using the FillSchema method when filling the data table, the AutoIncrement property will reflect whether a column was an Identity column. If the FillSchema method were not used, you would have to handle the exception that would occur when you tried to write the value to the column. When writing the cells into the columns in the data row, the Trim function is used; because of using the FillSchema method, the values are padded out as SQL Server columns generally are. The rest of the code pretty well runs like it does in step 9. The changes are accepted, written back to the server, and so forth. Listing 8.38 frmHowTo8_6.aspx: Deleting a Record from the Data Grid and Posting It Back to the Server Sub dgLookupData_Update(ByVal sender As Object, _ ByVal e As DataGridCommandEventArgs) Dim intColCnt As Integer Dim intColCurr As Integer Dim drCurr As DataRow Dim cnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim blnAdding As Boolean Dim strCurrValue As String '-- Create the command builder to update (post) the data ' ' in the data grid back to the server. Dim odaTableData As OleDb.OleDbDataAdapter Me.txtError.Text = "" Try Page 326 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Take the txtSQLString text and create a data table. Then set the ' data source of the data grid. Me.lstLookupTables.SelectedItem.ToString, cnn) Dim ocbTableData As OleDb.OleDbCommandBuilder = _ New OleDb.OleDbCommandBuilder(odaTableData) drCurr = mdtLookupData.Rows(dgLookupData.EditItemIndex + _ GetPageRows()) '-- Update the fields in the rows. intColCnt = e.Item.Cells.Count For intColCurr = 2 To intColCnt - 1 If mdtLookupData.Columns(intColCurr - 2).AutoIncrement = _ False Then drCurr.Item(intColCurr - 2) = _ Trim(CType(e.Item.Cells(intColCurr).Controls(0), _ TextBox).Text) End If Next '-- Commands are necessary to actually post back to the server. cnn.Open() odaTableData.Update(mdtLookupData) mdtLookupData.AcceptChanges() cnn.Close() Session("MyLookupData") = mdtLookupData Session("IsAdding") = False dgLookupData.EditItemIndex = -1 BindTheGrid() Catch excp As Exception Me.txtError.Text = excp.Message End Try End Sub 17. Add the code in Listing 8.39 for the PageIndexChanged command of dgLookupData. This code simply sets the CurrentPageIndex property of the data grid to the page that is odaTableData = New OleDb.OleDbDataAdapter("Select * From " & _ Page 327 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html chosen. The code then calls BindTheGrid(). Listing 8.39 frmHowTo8_6.aspx: Updating the Data Grid Page Index Private Sub dgLookupData_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles dgLookupData.PageIndexChanged '-- Set the current page in the data grid. Me.dgLookupData.CurrentPageIndex = e.NewPageIndex BindTheGrid() End Sub How It Works When the form opens, the user clicks on an entry in the Lookup Table to Edit list box. When this occurs and when a user selects a new item in the list, a Select statement is generated and loaded into a data adapter, which fills a data table. This, in turn, is used for the data source of the data grid, and the DataBind method is called. The data is then displayed. If the user clicks on the Edit button, the controls in the data grid are put into Edit mode. If the user clicks the Add button, a data row is added to the data table, and the data grid reflects this, including handling the paging of row locations. When the user clicks the button with the caption Update, a CommandBuilder object is generated off the DataAdapter object. The Update command for the data adapter is then invoked, with the Update method called. The data table is then referenced from the data source of the data grid control, and the AcceptChanges method is called. If the user clicks Cancel, then the changes are ignored if a record is being edited, but the data row is deleted if the record was in the middle of being added. When the user clicks Delete, the DataAdapter and CommandBuilder objects are created to remove the data row from the data table and reflect the changes back to the server. The data grid is also re-bound to the data table, and the paging is adjusted. Comments Whew, this was a long one. The good news is that the code is already created for you with the book. Remember, though, as with other techniques and examples, this is a starting point for you to run with and expand on. This example doesn't provide all the error trapping that is necessary, but it definitely gives a good start. Before spending too much time enhancing this example, make sure you get the performance out of it, just as you should when trying different data-driven techniques. [ Team LiB ] Page 328 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.7 Create a Point-and-Click Query Tool for Users Using a Web Form As useful if not more so than the example shown in the 8.3 How-to, this exercise will show you how to add a data-driven query tool to your ASP.NET application. When creating database applications, even on the Web, one of your clients inevitably wants to be able to examine the data in his database, and not necessarily in edit pages. The client wants to be able to list his data out and examine the data at his leisure. Giving the user the flexibility to do this via the Web is not as big of a hassle as it sounds. This How-To will show you how to create a page to view the tables in your database, using a nice point-and-click interface. Technique To accomplish the task just presented, you will be using the OleDbCommand and DataReader objects. Along with these objects, you will be using some stored procedures that SQL Server supplies. Those stored procedures list the various objects within a SQL Server database in this case, Northwind's tables and columns. You will take the elements returned in the DataReader object and load the Add method of the ListBox object. You will also use the Session object as you did in the previous How-To to save a DataTable object for use over trips to the server. Finally, the ViewState object will be used to store a string variable when going to the server and back. The ViewState object is a good .NET state object to use for small pieces of data, such as strings. Steps Open and run the VB.NET Chapter 8 solution. From the main Web Form, click on the hyperlink with the caption How-To 8.7: Create a Point-and-Click SQL Server Query Tool for Users Using a Web Form. When the new page opens, the first list box you see to the left is populated with the tables from Northwind. Click on the Customer table, and you will see the columns listed in the list box labeled Columns. Click on the CompanyName and ContactName, and you will see the SQL String text box filled in. After clicking on the View button, the Web page will look like the one displayed in Figure 8.14. 1. Create a Web Form. Then place the controls shown in Figure 8.14 with the properties set forth in Table 8.9. Table 8.9. Property Settings for Controls on the Point-and-Click Web Form Object Property Setting DOCUMENT Label bgColor Name Text buttonface Label1 Tables Page 329 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label Name Text Label2 Columns Label3 SQL String Label4 Data Display lstTables True lstColumns Multiple True ddSortBy True txtSQLString True btnView dgDisplay True hplBackToMain Return To Main wfrmMain.aspx Label Name Text Label Name Text ListBox Name AutoPostback ListBox Name SelectionMode AutoPostback DropDown Name AutoPostback TextBox Name MultiLine Button DataGrid Name Name AllowPaging Hyperlink Name Text NavigateURL 2. Tip Notice that the lstTables list box allows the user to choose only one table at a time, whereas lstColumns allows the user to choose multiple columns. A great enhancement to this tool would be to allow the user to choose multiple tables and have the application figure out the relationship between tables and create Page 330 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html joins automatically. 3. In the class module for the form, add the following Private declaration just below the line of code that reads Web Form Designer Generated Code: 4. 5. 6. Private mdtDisplay As DataTable On the Web Form, add the code in Listing 8.40 to the Load event. The first task is to load the tables list box, performed by the subroutine LoadTables(), which is also in this listing. The form only calls this routine if it is the first time into the page, by checking for Not Me.IsPostBack. The form then tests to see whether the Session object has an entry called MyDisplayDataTable. If the entry exists, then mdtDisplay is referenced to it, meaning that this time through the Load event is probably occurring on a trip back from the server. The entry exists, and the code needs to set a reference to it. In LoadTables, the routine first creates a new OleDbConnection object called ocnn, an OleDbCommand object called ocmdTables. It then assigns the built-in SQL Server stored procedure called sp_Tables when instantiating ocmdTables. After establishing the CommandType as being CommandType.StoredProcedure and then opening the connection, the data reader called odrTables is created by calling the ExecuteReader method off ocmdTables. Listing 8.40 frmHowTo8_7.vb: Executing a SQL Server-Supplied Stored Procedure That Lists the Tables in the Database Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If Not Me.IsPostBack Then LoadTables() End If If Not (Session("MyDisplayDataTable") Is Nothing) Then mdtDisplay = CType(Session("MyDisplayDataTable"), DataTable) End If End Sub Sub LoadTables() '-- Create the connection and specify the stored procedure to use. Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmdTables As New OleDb.OleDbCommand("sp_Tables", ocnn) Dim odrTables As OleDb.OleDbDataReader '-- Specify the type of command being performed. Page 331 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ocmdTables.CommandType = CommandType.StoredProcedure ocnn.Open() '-- Create the DataReader object. odrTables = ocmdTables.ExecuteReader() '-- Loop through and add table type object names ' to the lstTables list box. If odrTables.GetString(3) = "TABLE" Then Me.lstTables.Items.Add(odrTables.GetString(2)) End If Loop End Sub Next, the code loops through each of the items returned by the command. Those of type TABLE are added to the lstTables items. Then the connection is closed. As mentioned, you will see a comparison to the literal TABLE. This is because the fourth column returned matches the current table type. The other two types are SYSTEMTABLE and VIEW. To see the data returned by the sp_tables stored procedure, open the Query Analyzer, as described in How-To 8.3. 7. On lstTables, add the code in Listing 8.41 to the SelectedIndexChanged event. This routine performs a similar feat as the previous routine; it will call a built-in stored procedure in this case, sp_Columns. However, the next task in this step is to pass a parameter, Do While odrTables.Read TableName, which is the table chosen in lstTables.SelectedItem.Text. After the connection is opened, the DataReader called odrColumns is loaded with the ExecuteReader command. After the lstColumns.Items.Clear() method is called to clear the list, the new columns are added to the lstColumns Items collection. Then the connection is closed. Listing 8.41 frmHowTo8_7.vb: Executing a SQL Server Built-In Stored Procedure That Lists the Columns of a Supplied Table in the Database Private Sub lstTables_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstTables.SelectedIndexChanged '-- Create the connection and specify the stored procedure to use. Dim ocnn As New OleDb.OleDbConnection(BuildCnnStr("(local)", _ "Northwind")) Dim ocmdColumns As New OleDb.OleDbCommand("sp_Columns", ocnn) Dim odrColumns As OleDb.OleDbDataReader '-- Specify the type of command being performed ocmdColumns.CommandType = CommandType.StoredProcedure ocmdColumns.Parameters.Add("@TableName", Me.lstTables.SelectedItem.Text) ocnn.Open() Page 332 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-- Create the DataReader object odrColumns = ocmdColumns.ExecuteReader() '-- Clear the current items in the list Me.lstColumns.Items.Clear() '-- Loop through and add table type object names ' to the lstTables list box. Do While odrColumns.Read Me.lstColumns.Items.Add(odrColumns.GetString(3)) Loop End Sub 8. On lstColumns, add the code in Listing 8.42 to the SelectedIndexChanged event. After clearing the items from ddSortBy, this routine iterates through the Items collection of the lstColumns ListBox control, adding the chosen column names (those items with the Selected property set to True) to a string variable called strTemp. The DropDown control called ddSoryBy adds the column name to its Items collection. After the string is finished iterating through the lstColumns Items, it is stored to a ViewState entry called SQLFields. The LoadSQLString routine is then called, which is also in this listing. In the routine LoadSQLString, the length of the string is checked. If the length is greater than 0, the Text property of txtSQLString is set to the following expression: "Select " & strTemp & " From " & Me.lstTables.Text & " Order By " & Me.ddSortBy.SelectedItem.ToString. If the length is 0, then the Text property of txtSQLString is set to the empty string. Listing 8.42 frmHowTo8_7.vb: Creating the SQL String Private Sub lstColumns_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lstColumns.SelectedIndexChanged Dim intNumColumns As Integer Dim oCurr As Object Dim blnIsSelected As Boolean Dim strTemp As String Me.ddSortBy.Items.Clear() '-- Cycle through each of the selected columns of the table chosen ' and combine them into a string. For Each oCurr In Me.lstColumns.Items If oCurr.Selected() = True Then If Len(strTemp) > 0 Then strTemp &= ", " Page 333 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End If strTemp &= oCurr.ToString Me.ddSortBy.Items.Add(oCurr.ToString) End If Next ViewState("SQLFields") = strTemp LoadSQLString() End Sub Sub LoadSQLString() '-- Take the string created and add it to the ' table name for a SQL String, if columns are chosen. If Len(ViewState("SQLFields")) = 0 Then Me.txtSQLString.Text = "" Else Me.txtSQLString.Text = "Select " & ViewState("SQLFields") & _ " From " & Me.lstTables.SelectedItem.ToString & _ " Order By " & Me.ddSortBy.SelectedItem.ToString End If End Sub 9. On btnView, add the code in Listing 8.43 to the Click event. This routine creates the new data adapter called odaDisplay, passes the Text property of txtSQLString, and then fills the dtDisplay DataTable. The public variable, called mdtDisplay, references dtDisplay so that it will be seen in other routines. The code then stores a new entry in the Session object called MyDisplayDataTable, which is loaded back into mdtDisplay upon reloading of the page. Last, the routine BindTheGrid is called to set to the DataSource property of the data grid called dgDisplay. Listing 8.43 frmHowTo8_7.vb: Loading the DataGrid Control with the Specified Data Private Sub btnView_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnView.Click Dim odaDisplay As OleDb.OleDbDataAdapter Dim dtDisplay As New DataTable() Try '-- Take the txtSQLString text and create a data table. Then set the ' data source of the data grid. odaDisplay = New OleDb.OleDbDataAdapter(Me.txtSQLString.Text, _ Page 334 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BuildCnnStr("(local)", "Northwind")) odaDisplay.Fill(dtDisplay) mdtDisplay = dtDisplay Session("MyDisplayDataTable") = mdtDisplay BindTheGrid() Catch excData As Exception End Try End Sub Sub BindTheGrid() Me.dgDisplay.DataSource = mdtDisplay '-- Must databind for ASP.NET Me.dgDisplay.DataBind() End Sub 10. On the ddSortby control, attach the first routine in Listing 8.44 to the SelectedIndexChanged event. Then add the second routine to the PageIndexChanged event of dgDisplay. Figure 8.14. You can set the sorting of the data grid that is displayed here by choosing from the drop-down list. Page 335 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 8.44 frmHowTo8_7.vb: Loading the DataGrid Control with the Specified Data Private Sub ddSortBy_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ddSortBy.SelectedIndexChanged LoadSQLString() End Sub Private Sub dgDisplay_PageIndexChanged(ByVal source As Object, _ ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles dgDisplay.PageIndexChanged '-- Set the current page in the data grid Me.dgDisplay.CurrentPageIndex = e.NewPageIndex BindTheGrid() End Sub How It Works When the form is opened, the lstTables ListBox control is loaded with the tables from the Northwind database. When the user selects a table from the list, that table name is passed to the stored procedure. That procedure lists the columns in a database table that is specified in the connection in this case, Northwind. These columns are loaded into lstColumns. The user can click on multiple columns in lstColumns. Those columns then are added to the SQL Select string that is created and stored in txtSQLString. When the btnView button is clicked, the string is passed to a DataAdapter control, filling a data table. From there, the data is displayed when the data source of the DataGrid control is set to the data table. Users can change the sort order by changing the value in the DropDown object. Comments You can enhance this tool in several ways:   Let users click on multiple tables and automatically create the join. Add a list of columns for the user to choose to use for criteria, and allow the user to input the criteria.  Use this tool as a base for editing or reporting the records that are returned. This technique's goal, as with others in this book, is to push you into thinking about the possibilities of what you can accomplish with Visual Studio .NET and your databases. [ Team LiB ] Page 336 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 8.8 Make a Generic Search Form in an ASP.NET Web Application This tutorial will show you how to add a unique search Web Form to your Web application that can be set up using session variables and used for various tables. Creating search forms for Web applications is pretty common. You would like to be able to use the same Web Form for different tables in the same application. This How-To will demonstrate using the same Web Form for searching various tables, taking advantage of the Session object. Technique This How-To will use the Session object with a Web Form, something that has been done throughout the book. You will see a good example of using the Session object to pass values in this case, the record source, the key search field, and the display search field to the search form. Finally, the return value will be passed back to the calling Web Form using the Session object. One new control that is used in this How-To is the Panel control. It will be used to group the controls on the search Web Form. The Panel control will be used simply by throwing controls into it and letting it control the layout. You will see the paging used with the DataGrid control as well. Steps Open and run the VB.NET Chapter 8 solution. From the main Web Form, click on the hyperlink with the caption How-To 8.8: Make a Generic Search Form Using a Web Form. This page is a simple one that contains text boxes for the Customer table in Northwind (see Figure 8.15). Figure 8.15. This Customers page is a common one used to demonstrate calling the search form. Page 337 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Click on the Search button to open the search page, and then click on the button labeled B. You will see the DataGrid object displayed in the bottom of the form filled with the CompanyID and CompanyName fields of the Customer table, which begin with B (see Figure 8.16). Figure 8.16. This form can be used for searching within any of the tables in your databases. Click the Select button for one of the customers who is displayed in the grid, and then click Accept. The customer page will be displayed, and the fields will be filled in with the data from the chosen record. 1. Create a Web Form. Then place the controls shown in Figure 8.16 of the form calling the search form, with the properties set forth in Table 8.10. Table 8.10. Label, TextBox, and Command Button Controls Property Settings for the Calling Form Object Property Setting DOCUMENT Label Label Label Label Label Label bgColor Caption Caption Caption Caption Caption Caption buttonface Customer ID Company Name Contact Contact Title Address City Page 338 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label Label Label Label TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox TextBox Button Caption Caption Caption Caption Name Name Name Name Name Name Name Name Name Name Name Name Caption Region Country Phone Fax txtCustomerID txtCompanyName txtContactName txtContactTitle txtAddress txtCity txtRegion txtPostalCode txtCountry txtPhone txtFax btnSearch &Search 2. On btnSearch, add the code in Listing 8.45 to the Click event. This sets up the search Web Form as far as telling it what it needs to know, including how to get back to this page, which is the calling page. The search page, in this case "wfrmHowTo8_8b.aspx," is then opened. Listing 8.45 frmHowTo8_8a.vb: Storing Values to the Session Object for Use on Another Page Private Sub btnSearch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSearch.Click Session.Item("SearchRecordSource") = "Customers" Session.Item("SearchField") = "CompanyName" Session.Item("KeyField") = "CustomerID" Session.Item("CallingPage") = "wfrmHowTo8_8a.aspx" Server.Transfer("wfrmHowTo8_8b.aspx") End Sub Page 339 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Add the code in Listing 8.46 to the Load event of the Web Form. If the Session object has an entry for ResultValue, then the LoadIndividual routine is executed and the ResultValue is passed. The LoadIndividual routine is described in the next step. This routine is coded so that when the page is reloaded after the search form has been used, the Session object entry will exist. When you first come into the page, the entry doesn't exist. Listing 8.46 frmHowTo8_8a.vb: Loading an Individual Record into Text Boxes on the Form Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If Not (Session("ResultValue") Is Nothing) Then LoadIndividual(Session("ResultValue")) End If End Sub 4. Create the LoadIndividual routine by entering the code shown in Listing 8.47 in the form. Taking the strCustID passed from the results of the search, a data adapter is created, and a data table is filled. Last, each of the TextBox controls is loaded with the value from the column with the corresponding name. Listing 8.47 frmHowTo8_8a.vb: Loading an Individual Record into Text Boxes on the Form Private Sub LoadIndividual(ByVal strCustID As String) Dim odaCustIndiv As New _ OleDb.OleDbDataAdapter("Select * From Customers Where CustomerID = '" & strCustID & "'", BuildCnnStr("(local)", "Northwind")) Dim dtCustIndiv As New DataTable() odaCustIndiv.Fill(dtCustIndiv) With dtCustIndiv.Rows(0) Me.txtCustomerID.Text = .Item("CustomerID").ToString Me.txtCompanyName.Text = .Item("CompanyName").ToString Me.txtContactName.Text = .Item("ContactName").ToString Me.txtContactTitle.Text = .Item("ContactTitle").ToString Me.txtAddress.Text = .Item("Address").ToString Me.txtCity.Text = .Item("City").ToString Me.txtRegion.Text = .Item("Region").ToString Me.txtCountry.Text = .Item("Country").ToString Me.txtPostalCode.Text = .Item("PostalCode").ToString Me.txtPhone.Text = .Item("Phone").ToString Me.txtFax.Text = .Item("Fax").ToString End With Page 340 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 5. Create the next Web Form, and call it whatever name you referred to in the search Web Form in step 2. Then place the controls shown in Figure 8.16 of the search page, with the properties set forth in Table 8.11. Table 8.11. Label, TextBox, DataGrid, and Command Button Controls Property Settings for the Calling Form Object Property Setting DOCUMENT TextBox bgColor Name Text buttonface Label1 Click on a Letter Panel1 btnA A btnB B btnC C Panel Button Name Name Caption Button Name Caption Button Name Caption ... Button Name Caption Button Name Caption DataGrid Name AllowPaging Button Name Caption Button Name Caption btnZ Z btnAll All dgSearch True btnAccept &Accept btnCancel &Cancel Page 341 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. In the class module for the Web Form, add the following Private declaration just below the line of code that reads Web Form Designer Generated Code: 7. 8. 9. Private mdtSearch As New DataTable() On the Web Form, add the code in Listing 8.48 to the Load event. This routine loads the data table stored in the Session object if it exists. Listing 8.48 frmHowTo8_8b.vb: Executing a SQL Server-Supplied Stored Procedure That Lists the Tables in the Database Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load If Not (Session("SearchDataTable") Is Nothing) Then mdtSearch = CType(Session("SearchDataTable"), DataTable) End If End Sub 10. For each of the command buttons that has a single letter, add the first subroutine displayed in Listing 8.49 to each of the Click events. For the btnAll Button control, add the second subroutine to the Click event. Each Button control will pass the letter it represents to the subroutine called SetData, discussed in the next step. The btnAll code simply passes the empty string. Listing 8.49 frmHowTo8_8b.vb: Click Events for Each of the Letter Button Controls Private Sub btnA_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnA.Click SetData("A") End Sub Private Sub btnAll_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAll.Click SetData("") End Sub 11. Add the subroutine in Listing 8.50 to the class module of the form. This routine takes the letter value passed in strFilterLetter as a parameter. A SQL Select string is created that takes the literal values Select, From, and Where and uses the Session object entries KeyField, SearchField, and SearchRecordSource. The SearchField property is used with the Like clause, also using the strFilterLetter and the % (wildcard). Note that if " is passed to strFilterLetter, all the records will be listed. Finally, mdtSearch is filled in the routine BindTheGrid set as the data source for dgSearch, which is the DataGrid control. The routine called BindTheGrid is located at the end of the listing. Listing 8.50 frmHowTo8_8a.vb: Filling the Results Set Based on the Letter Button Page 342 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Pressed Sub SetData(ByVal strFilterLetter As String) Dim odaSearch As OleDb.OleDbDataAdapter odaSearch = New _ OleDb.OleDbDataAdapter("Select " & Session.Item("KeyField") & ", " & Session.Item("SearchField") & " From " & _ Session.Item("SearchRecordSource") & " Where " & _ Session.Item("SearchField") & " Like '" & _ strFilterLetter & "%'", (BuildCnnStr("(local)", "Northwind"))) mdtSearch.Clear() odaSearch.Fill(mdtSearch) Session("SearchDataTable") = mdtSearch BindTheGrid() End Sub Private Sub BindTheGrid() dgSearch.DataSource = mdtSearch dgSearch.DataBind() End Sub Note This routine, more than any in this How-To, shows the flexibility of this technique. You can use any table values for these properties. This is a major benefit when you think of how many places you can use this form without changing a line of code in the form. 12. Right-click on the data grid and choose Property Builder. Go to the Columns tab and add a Select button. Set the Button Type to be PushButton (see Figure 8.17) and click OK. Figure 8.17. There is no code required for this button. Page 343 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 13. On the buttons called btnAccept and btnCancel, add the code in Listing 8.51 to the appropriate Click event of each. The btnAccept_Click routine derives the data row that is currently selected from mdtSearch using the data grid's SelectedIndex property and adding the paging that has to occur using GetPageRows(), which returns the actual rows given the current page that the user is on in the DataGrid object. You can see the GetPageRows() routine at the bottom of the listing. The KeyField Session object entry is then used to store the individual column value of drCurr in the ResultValue Session object entry. The calling page is reloaded. The ResultValue is not set in the btnCancel_Click routine. The calling page is simply reloaded. Listing 8.51 frmHowTo8_8b.vb: Storing the Resulting Key Value to the ResultValue Session Object Entry and Returning to the Calling Page Private Sub btnAccept_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnAccept.Click Dim drCurr As DataRow Try drCurr = mdtSearch.Rows(dgSearch.SelectedIndex + GetPageRows()) Session("ResultValue") = drCurr.Item(Session("KeyField")).ToString Catch exc As Exception Page 344 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Try Server.Transfer(Session("CallingPage")) End Sub Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click Server.Transfer(Session("CallingPage")) End Sub Function GetPageRows() As Integer '-- This helps synchronize the data table rows ' with the data grid page and row. GetPageRows = dgSearch.PageSize * dgSearch.CurrentPageIndex End Function 14. The last step is to add the code in Listing 8.52 for synching up pages in the data grid when the user switches pages. Listing 8.52 frmHowTo8_8b.vb: Updating the Data Grid with the New Page Number Private Sub dgSearch_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles dgSearch.PageIndexChanged '-- Set the current page in the data grid. Me.dgSearch.CurrentPageIndex = e.NewPageIndex BindTheGrid() End Sub How It Works When the user clicks on the Search button, the calling page stores values in the Session object for use in the search page, telling it what record source to use, as well as other information used for searching for the specific record and table desired:     "Customers" for the Session object entry SearchRecordSource "CustomerID" for the Session object entry KeyField "CompanyName" for the Session object entry SearchField "wfrmHowTo8_8a" for the Session object entry CallingPage After the search page is loaded, the user clicks one of the letters to narrow down the records to look for. A data adapter is passed a SQL String made up of the Session object entries just Page 345 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html mentioned, a data table is filled, and the data grid's DataSource property sets the data table. When the user clicks Accept, the DataTable is retrieved from the data grid, which then produces the data row that contains the key field. The key field is then stored in the ResultValue Session object entry of the search form, and the calling page is reloaded. Back on the calling form, the LoadIndividual routine is called. Then the routine is passed the ResultValue Session object entry from the search form. The text boxes are loaded with the data row results. Comments This technique shows a number of ways that the various ADO.NET objects can be used. Using the Session object and other State management methods is handy for creating pages that you want to use for more than one table. You will find use for this technique throughout your applications after you become accustomed to it. Again, you can enhance this tool in several ways. One way is to allow the user to enter a string value to type in, and narrow down the choices even more. Another way is to add a property that could be used to specify multiple columns to be displayed. [ Team LiB ] Page 346 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 9. Using Classes With Databases to Make Life Easier In this chapter you will        Define a class in Visual Basic .NET Create a class that implements the interface you defined Use Visual Studio .NET tools to speed up writing ADO.NET code Control the creation and behavior of classes Implement the methods that update the database Validate data passed to properties and communicate errors to developers Write data validation code that can be reused in other classes Writing database-access code is never a simple task, whether you use ADO.NET, DAO, RDO, db-lib, ct-lib, or OCI. Although ADO.NET makes life much easier, data still needs to be validated for size, type, or range; referential integrity must be maintained; business rules must be obeyed; exceptions must be handled; and so on. Moreover, writing the code can be tedious. Think of how many lines of code are needed to set up a DbCommand object with ten parameters and maintaining different code bases that access the same database objects can turn into weeks of busywork. The solution for any complex programming problem is to place all the related code into a flexible, reusable code component, or class. This chapter shows you how easy it is to create a class that handles all the common tasks you need to access data in the table, and more important, how this will simplify writing code for the rest of your application. This chapter also touches on several of Visual Basic .NET's objects-oriented features. Because Microsoft has made every .NET language including Visual Basic a fully object-oriented language, no book on .NET programming is complete without some discussion of object-oriented programming. This book, however, is all about database access using .NET technologies, so we shouldn't get bogged down with discussions filled with words like polymorphism, encapsulation, and inheritance. In fact, this chapter will do its best to avoid using these terms (at least until the concept is already explained) because, frankly, if you're new to object-oriented programming (OO), these terms can be confusing and intimidating. This chapter uses three terms frequently that need definition. A class is a software component that combines related data, function, and type definitions into a new type. In other words, it is a description of some properties and methods, but nothing more. The properties, methods, types, data, and so on of a class are referred to jointly as members. To use a class, you need to instantiate it with a specific set of data. An instance of a class is called an object. This chapter takes for granted that you understand how DataAdapter, DataSet, and Command objects interact to assist client applications and databases communicate. Instead, it focuses on the tools that Microsoft has provided for you to automatically generate code that creates these objects for use with specific database tables, as well as the basic principles for creating data access classes. [ Team LiB ] Page 347 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Page 348 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 9.1 Define a Class in Visual Basic .NET Before writing code, you should take a moment to decide what data the class needs to contain and what actions a developer (whether it is you or a teammate) would want to perform on that data. For the moment, we'll keep it fairly simple by limiting the class to properties representing the columns in the Customers table and to methods that insert, delete, and update data. Technique Visual Basic .NET has a specific kind of code file that you can use to describe the public members of a class: an interface. An interface simply lists all the public variables, methods, and properties that any class implementing that interface must expose. Interfaces are an enormously powerful and flexible feature of object-oriented programs, and this chapter just scratches the surface. Because of the fact that an interface has no code, you can focus on the design of your application without the clutter of hundreds of lines of source code. Steps 1. 2. First, create a new Windows Application project and name it CustomerClasses. To create a new interface, add a new class to your project by right-clicking on the Solution Explorer window and selecting Add Class. Name the new file CustomerInterface9_1.vb. 3. Change the class block declaration so that it reads interface instead of class, and name the class ICustomer. You should have a code file like that shown in Listing 9.1. Listing 9.1 CustomerInterface9_1.vb: An Empty Interface Public Interface ICustomer End Interface Add Properties to the Interface The first items you need to add to your interface are properties to represent the columns in the Customers table. 1. Using the Server Explorer, drill down to the Customers table in the Northwind database so that you have an easy reference to the Customers table. 2. To make your code more readable, add a #Region/#End Region block with the name Properties so that you can expand and collapse your property declarations as needed. 3. For each column in the table, add a property declaration to your interface that matches the datatype of the column and its name(see Listing 9.2). Listing 9.2 CustomerInterface.vb: The ICustomer Interface with Properties Public Interface ICustomer #Region "Properties" 'Define properties for this interface 'that match the table structure in name and data type Page 349 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Property CustomerID() As String Property CompanyName() As String Property ContactName() As String Property ContactTitle() As String Property Address() As String Property City() As String Property Region() As String Property PostalCode() As String Property Country() As String Property Phone() As String Property Fax() As String #End Region End Interface More About Properties ICustomer is a simple interface. It has only one kind of datatype a string and all of the properties are read/write. When you begin to write more complex classes, you might need more than just read/write properties. Visual Basic .NET also has read-only and write-only properties, parameterized properties, and default properties. Read-Only and Write-Only Properties If you have written classes in Visual Basic 6, you might be scratching your head, wondering how the code sample in Listing 9.2 declares your properties read/write. In Visual Basic 6, all that mattered was whether you wrote the appropriate Property Get and Property Let/Set blocks in your class. If you did not have a Public or Friend Property Let/Set, the property was read-only. If you did not have a Public or Friend Property Get, the property was write-only. In Visual Basic .NET, you must explicitly declare a property as read-only or write-only using the ReadOnly and WriteOnly keywords (see Table 9.1). Table 9.1. Visual Basic .NET Property Modifiers Object Purpose ReadOnly The property cannot be modified outside of the class. WriteOnly The property can only be modified, but only methods that are internal to the class can read the property. In our example, a developer who is using this class could change the CustomerID. Without the original CustomerID, the class won't be able to find that record in the database when updating the table, so perhaps you should make the CustomerID property read-only. To do this, simply add the ReadOnly keyword to the beginning of the property declaration as in Listing 9.3. Listing 9.3 CustomerInterface9_1.vb: Using the ReadOnly Keyword 'Adding the ReadOnly keyword before the property 'declaration makes the property read-only. ReadOnly Property CustomerID() As String Parameterized Properties You can also create properties that accept a parameter. For example, in the Northwind database, a Page 350 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html customer might have many orders. A parameterized property would be a perfect way to access Orders information from the Customer class. A parameterized property (see Listing 9.4) takes one or more parameters that can be used to qualify the data that the property returns. Listing 9.4 A Parameterized Property 'The nIndex parameter would be used to determine which 'item from a collection of orders should be returned. Property CustomerOrders(ByVal nIndex As Integer) As COrder Tip One of the advantages to interfaces is the ability to rapidly define all of the classes you plan to use in your application. For the previous code example, you could create an interface called IOrder that was similar to the ICustomer interface in Listing 9.2. Instead of returning an actual class from the CustomerOrders property, you could return the IOrder interface. The interface would act as a placeholder for any object that implemented the interface. This way, you could program the Customer class and put off writing code for the Order class until later. Default Properties In Visual Basic 6, any property in a class could be defined as the default property for that class. For example, if the CustomerID property were declared the default property, both of the examples in Listing 9.5 would return the customer ID. Listing 9.5 Default Properties in Visual Basic 6 Dim oCustomer As CustomerData Dim strCustomerID As String 'Example 1: This code places the value of the customer ID property 'into a variable. strCustomerID = oCustomer.CustomerID 'Example 2:This code does the same thing. strCustomerID = oCustomer In Visual Basic .NET, the only kind of property that you can declare as the default property for a class is a parameterized property. To declare a property as the default property, simply add the Default keyword prior to the property declaration, as shown in Listing 9.6. Listing 9.6 Declaring a Default Property 'Adding the Default keyword before the property declaration 'makes this parameterized property the default property for 'the class. Default Property CustomerOrders(ByVal nIndex As Integer) As COrder Add Methods to the Interface Now that you have added all the properties you need, you need to add the various methods that a developer uses to retrieve, insert, update, and delete data from the Customers table. Page 351 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 1. To make your code more readable, add a #Region/#End Region block with the name Methods so that you can expand and collapse your method declarations as needed. 2. The point in wrapping a table in a class is to make access to this table as simple as possible. You could have one method to insert new rows to the database and one to update existing rows, leaving the task of determining the state of the object to the code that instantiates it. The actions of the class, however, should be as transparent to other developers as possible. To this end, the interface should only define two methods: save and delete. (The retrieve method will be defined in a subsequent section.) Add the save and delete methods to your interface, as in Listing 9.7. Listing 9.7 CustomerInterface9_1.vb: Declaring the Delete and Save Methods #Region "Methods" 'To update or delete a record, a user would have needed to 'retrieve data before modifying any of the properties. Function Save() As Boolean Function Delete() As Boolean #End Region As I mentioned in the introduction to this chapter, one of the great advantages to wrapping up all access to a database table within a class is that you only have to write complex error-handling code once. To keep things simple, we are returning a Boolean value from each of these methods, letting other developers know whether the action failed without requiring them to write complex error-handling code. 3. Finally, add a ToString method to output all the data of the class in a string. This is extraordinarily useful for debugging. Your finished interface should look like Listing 9.8. Listing 9.8 CustomerInterface9_1.vb: The Final ICustomer Interface Public Interface ICustomer #Region "Properties" 'Define properties for this interface 'that match the table structure in name and data type ReadOnly Property CustomerID() As String Property CompanyName() As String Property ContactName() As String Property ContactTitle() As String Property Address() As String Property City() As String Property Region() As String Property PostalCode() As String Property Country() As String Property Phone() As String Property Fax() As String #End Region #Region "Methods" 'To update record, a user would have needed to Page 352 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 'retrieve data before modifying any of the properties. Function Save() As Boolean Function Delete() As Boolean Function ToString() As String #End Region End Interface How It Works You might have noticed that an interface has no actual code. An interface is designed for one purpose: to define a set of public methods and interfaces that are related to a specific entity. To put this in object-oriented terminology, an interface represents an abstraction of an entity in this case, a customer. Interfaces can't function by themselves; a class must implement all of its properties and methods, which is what you will do in the next sections. Comments Of course, you don't really need to write an interface before writing the class, and in our current example, it might be overkill. The power of an interface really comes into play when you have multiple classes that might implement the same interface in different ways. An interface cannot exist as an object: It has no code and no place to store object data. A class that implements an interface has an explicit contract with the interface: The class must implement all the properties and methods of the interface. If you declare a variable typed to an interface, that variable could represent any object of any class that implements the interface. You've already seen several examples of interfaces in this book, such as the DataAdapter, DataReader, Connection, Command, and other ADO.NET objects. Take, for example, the Command interface. At present, two types of Command classes exist: the OleDbCommand and the SqlCommand. Both of these classes implement the IDbCommand interface. The OleDbCommand is responsible for handling data access to any database provider with an OleDB driver, and the SqlCommand connects directly to SQL Server. If you wrote a function that processed Command objects such as a debugging function that wrote all the properties of a Command to an error log you might need to handle both kinds. Instead of writing two functions, one for each Command type, Public Sub WriteCommandErrorToLog(ByVal pCommand as SqlCommand) Public Sub WriteCommandErrorToLog(ByVal pCommand as OleDbCommand) you could simply declare a function that takes a variable of type IDbCommand, which would accept an instance of either command type: Public Sub WriteCommandErrorToLog(ByVal pCommand as IDbCommand) The second solution is far more elegant because, before long, you could end up with Commands for Oracle, Sybase, MySql, SqlAnywhere, DB2, and so on, all of which would implement the IDbCommand interface. It might look like you're missing a few items in ICustomer. What method do you call to add new records or retrieve data from the database? If you're working with a new customer row, how does a developer set the CustomerID? A new type of method called a constructor is executed when a class is instantiated. Because constructors can't be declared in an interface, we will cover this subject in section 9.4. [ Tea Page 353 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html m LiB ] Page 354 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 9.2 Create a Class That Implements the Interface You Defined Now that you have defined the public interface of your class, you need to create a class that will implement that interface, along with all of its methods and properties. The place to start is with the properties of your class. You'll also need to create some code to test your class, so you'll need to create a form that interacts with the instances of the class. Technique This section uses a form with text boxes that mirror the properties of the CCustomer class. Visual Basic .NET allows you to have classes and forms within the same .vb file, so this section will have both in one file to make editing and debugging easier. After setting up the form, you need to implement the class properties. If you have worked with Property statements before, this technique will be old hat (although the syntax will be new). If you have not worked with properties and classes, you will need the following:   Steps 1. A private variable for each property to store class data Code to modify and return that data Create a Windows Form and name it frmHowTo9_2. Then place text boxes for each of the properties of the class, naming the text boxes with the property name, prefaced by txt. For example, the postal code text box should be named txtPostalCode. Next add command buttons called cmdDelete, cmdSave, cmdRetrieve, and cmdNew. Finally, add a RichTextBox control called rtbToString to contain the output of the ToString method. (This enables you to see how the Form maps to the data of the class. See Figure 9.1) Figure 9.1. Arrange the controls on the form you created to look like this form. 2. Add a class declaration block to frmHowTo9_2 and name the class CCustomer. After the line Public Class CCustomer, type Implements ICustomer. This tells Visual Basic that the CCustomer class includes all of the properties and methods of the ICustomer interface as shown in Listing 9.9. Page 355 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Listing 9.9 frmHowTo9_2.vb: The Empty Customer Class Public Class CCustomer Implements ICustomer End Class 3. Copy all of the property and method declarations in the ICustomer interface, and paste them within the CCustomer class block. 4. Visual Basic .NET requires that you specify which property or method in your class implements which public member of your interface. After each property or method declaration that you just pasted into the CCustomer class block, you must add Implements ICustomer.[Property/Method Name]. Note Visual Basic .NET allows you to have property and method names in your class that differ from the public member names listed in your interface. This feature exists because one class can implement many interfaces, and those interfaces can have public members of the same name. Although typing Implements ICustomer.[Property/Method Name] after a property and method with the same name as in our example might seem frustrating, it will come in handy when you write more complex code. 5. By default, all methods, properties, and module-level variables are Public unless an access modifier, such as Private or Protected, is used (see Table 9.2). It is, however, good programming practice to use the Public access modifier, so be explicit and add Public before each member. Table 9.2. Visual Basic .NET Access Modifiers Object Purpose You can only access the member within the class. You can only access the member from classes that are derived from (inherit from) the member's class. You can only access the member by objects within the same project. You can only access the member by derived classes within the same project. You can access the member by any object. Private Protected Friend Protected Friend Public Page 356 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. Public ReadOnly Property CustomerID() As String _ Implements ICustomerData.CustomerID Public Property CompanyName() As String Implements ICustomerData.CompanyName Public Property ContactName() As String Implements ICustomerData.ContactName Public Property ContactTitle() As String _ Implements ICustomerData.ContactTitle Public Function Delete() As Boolean Implements ICustomerData.Delete Public Class Customer Implements ICustomer When you are finished, your code should look like Listing 9.10. Listing 9.10 frmHowTo9_2.vb: The Empty CCustomer Class 19. Note Copying and pasting the code from the interface will result in code with an invalid syntax because of the lack of End Property and End Function/Sub lines. Although this doesn't matter for the moment, it does disable Intellisense, which normally appears after typing both Implements and the period after the Interface name. If you want to enable Intellisense, press Enter at the end of each property and method declaration. Doing so inserts the appropriate End tag. When all the tags are in the class, Intellisense is reenabled. 20. Add private variables directly below the class declaration to store class data, as shown in Listing 9.11. You should have one variable for each property. As mentioned in Chapter 3, "Viewing Data with ADO.NET," prefacing class-level variables with "m" is a Visual Basic programming convention. Listing 9.11 frmHowTo9_2.vb: Class Variable Declarations Public Class CCustomer Implements ICustomer #Region "Class Variables" Private mstrCustomerID As String Private mstrCompanyName As String Private mstrContactName As String Private mstrContactTitle As String Private mstrAddress As String Private mstrCity As String Private mstrRegion As String Private mstrCountry As String Private mstrPostalCode As String Private mstrPhone As String Page 357 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Private mstrFax As String #End Region 21. Write code to set and return data for the properties. Place your cursor at the end of a property declaration line, and press Enter. Visual Studio .NET automatically inserts code blocks for setting and getting your property. If you have worked with properties before, you might notice that Microsoft has changed the syntax. Listing 9.12 shows Visual Basic 6 property get and let declarations, each with its own separate block. Listing 9.12 Property Declarations in Visual Basic 6 Public Property Get PropertyName() As String PropertyName = mstrClassVariable End Property Public Property Let PropertyName(ByVal strValue As String) mstrClassVariable = strValue End Property In Visual Basic .NET, the property declaration has been combined in the format shown in Listing 9.13. Listing 9.13 Property Declarations in Visual Basic .NET Public Property PropertyName() As String Get Return mstrClassVariable End Get Set(ByVal Value As String) mstrClassVariable = Value End Set End Property For each of your properties, add Return and the variable you declared in step 1 in the Get block. In the Set block, type the name of a variable from step 1 and = Value. All of your property declarations should now look like Listing 9.14. Listing 9.14 frmHowTo9_2.vb: Some Property Declarations for the CCustomer Class Public ReadOnly Property CustomerID() As Customers.CCustomerID Implements ICustomer.CustomerID Get Return mCustomerID End Get End Property Public Property CompanyName() As String Implements ICustomer.CompanyName Get Return mstrCompanyName End Get Set(ByVal Value As String) mstrCompanyName = Value End Set Page 358 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Property 22. To test your properties, you need to write a bit more code. First, you might want to implement the ToString method that returns all the object's properties as a string. Also, you will want a method that clears the form for use with a new object. Listing 9.15 shows one way to implement ToString, with each property printing on a separate line, as well as a ClearAllTextBoxes method. Listing 9.15 frmHowTo9_2.vb: The ToString Method Outputting Property Information Public Overrides Function toString() As String Implements ICustomer.ToString Dim strReturn As String strReturn = Me.CustomerID & vbCrLf strReturn = strReturn & "Company: strReturn = strReturn & "Contact: strReturn = strReturn & "Title: strReturn = strReturn & "Address: strReturn = strReturn & "City: strReturn = strReturn & "Country: strReturn = strReturn & "Phone: strReturn = strReturn & "Fax: strReturn = strReturn & "Region Return strReturn End Function Protected Sub ClearAllTextBoxes() Me.txtAddress.Text = "" Me.txtCity.Text = "" Me.txtCompanyName.Text = "" Me.txtContactName.Text = "" Me.txtContactTitle.Text = "" Me.txtCountry.Text = "" Me.txtCustomerID.Text = "" Me.txtFax.Text = "" Me.txtPhone.Text = "" Me.txtRegion.Text = "" Me.txtPostalCode.Text = "" Me.rtbToString.Text = "" End Sub The Overrides keyword is necessary because your class already has a ToString method. You didn't write that method, but it's there. This is because every class inherits from the Object class, which defines a ToString method. Don't worry about this: You'll learn about inheritance and overriding methods later in this chapter. Now you need to add three pieces of code to the form that will instantiate the CCustomer class, and you need to allow its properties to be modified through the text boxes. 23. First, add a form-level variable called mCustomer of type CCustomer to the form. Use the new keyword in the declaration to create a new instance of CCustomer. " & Me.CompanyName & vbCrLf " & Me.ContactName & vbCrLf " & Me.ContactTitle & vbCrLf " & Me.Address & vbCrLf " & Me.City & vbCrLf " & Me.Country & vbCrLf " & Me.Phone & vbCrLf " & Me.Fax & vbCrLf " & Me.Region & vbCrLf strReturn = strReturn & "Postal Code: " & Me.PostalCode & vbCrLf Page 359 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 24. Next, add code to each TextBox control's TextChanged event that updates property values in mCustomer. Note that Listing 9.16 does not actually refer to mCustomer. Instead, Listing 9.16 calls an as-yet-undefined method called TextBoxChange that handles changes to mCustomer. This method is defined and explained in step 11. Listing 9.16 frmHowTo9_2.vb: The TextChanged Event of the txtPostalCode Text Box That Calls the TextBoxChange Method Protected Sub txtPostalCode_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtPostalCode.TextChanged TextBoxChange("PostalCode", txtPostalCode.Text) End Sub 25. Finally, add the TextBoxChange method that takes the value passed from each text box's TextChanged event and writes it to the appropriate property of the mCustomer object. Listing 9.17 shows a sample of this code, although it does not list a case for each text box. Centralizing all access to the mCustomer object in one method allows you to have one exception-handling area. Listing 9.17 frmHowTo9_2.vb: An Excerpt of the TextBoxChange Method That Writes Values in Text Boxes to Object Properties Protected Sub TextBoxChange(ByVal pstrProperty As String, _ ByVal pstrValue As String) Try Select Case pstrProperty Case "Address" mCustomer.Address = pstrValue Case "CompanyName" mCustomer.CompanyName = pstrValue Case "PostalCode" mCustomer.PostalCode = pstrValue End Select ' Write the class' properties to the RichTextBox ' to aid debugging. Me.rtbToString.Text = mCustomer.ToString() Catch ex As Exception MsgBox(ex.Message) End Try End Sub How It Works Page 360 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html An instance of the CCustomer class is created when frmHowTo9_2 is created. When the user types in a text box, the TextChanged event fires, calling the TextBoxChange method. The TextBoxChange method sets the corresponding property of the class handles any exceptions, and then writes the output of the CCustomer.ToString method to the RichTextBox. Note In the samples for this chapter, I want to use the same form for each section's code samples without having to re-create the form each time. To this end, I have used frmHowTo9xBase as a base form class, and all the frmHowTo9_x forms inherit from this class. Some common methods, including the TextChanged events, are defined in frmHowTo9xBase rather than in each child form. Comments Microsoft has made several changes to property declarations, and it's worth enumerating them here. First, the Get and Set code blocks are wrapped up in one Property declaration, making neater and easier-to-read code. Second, the Return keyword is now used instead of the Property name in the Get block. Remember that no code is executed after the Return keyword. Third, there is no longer a distinction between Set and Let. In Visual Basic 6, Set was used for Object properties, and Let was used for base datatypes, such as Strings and Integers. Microsoft has eliminated this confusing distinction, and now Set is used in all cases. Just like Visual Basic 6, however, read-only properties will have only a Get block, whereas write-only properties will have only a Set block. [ Team LiB ] Page 361 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 9.3 Use Visual Studio .NET Tools to Speed Up Writing ADO.NET Code The code you've written up to this point doesn't do that much. It doesn't even access the database. The next task is to write code that populates the class with data from the database, and the first step in doing this is setting up database access objects. Technique In Chapter 3, you learned how to fill a dataset to store data in a disconnected fashion. In this chapter, you will use a strongly typed dataset that is, a dataset with data rows that match the name and datatypes of the columns. You will learn how to use the DataAdapter Configuration Wizard to autogenerate code that initializes Command and DataAdapter objects for use with a specific table. Steps 1. Right-click on your project and select Add New Item from the Add menu. Choose DataSet and name it dsCustomers.xsd. 2. Visual Studio .NET opens dsCustomers.xsd in Design mode. Expand the Server explorer and drill down to Data Connections, Northwind, Tables. Drag the Customers table onto the Design view. 3. Visual Studio might process for a few seconds, but afterward, you'll have a strongly typed dataset. The result? Instead of writing dataset code like this: strCustomerID = CType(ds.Tables("Customers").Rows(0).Item("CustomerID"), String) you'll have code that looks like this: strCustomerID = ds2.Customers(0).CustomerID A strongly typed dataset is a combination of two documents. One is a .vb file with the same name as the dataset. Visual Studio .NET will not show you the contents of this file (unless you step into it while debugging), and the contents don't appear in the Solution Explorer. The other file is an .xsd file, or a XML Schema Definition (XSD), which defines a data structure. The .vb file reads the XSD to properly instantiate a strongly typed dataset. You should always take a look at any code that is generated automatically by a tool because the tool might generate code that doesn't do precisely what you want it to do. If you have never seen an XSD, this is also a good time to learn something new. Listing 9.18 shows the XSD for the dsCustomers dataset. You can view the XSD you created by opening dsCustomers.xsd from the Solution Explorer and then clicking the XML button at the bottom of left corner of the screen. Listing 9.18 dsCustomers.xsd: The Customers XSD It is beyond the scope of this chapter and this book to fully explain an XSD. The subject requires an entire book of its own. But it's important to point out a few areas of this XSD. The element tags are really nothing more than the properties you have already declared. Each element has a name that corresponds to a column in the Customers table, as well as a type that loosely corresponds to the datatype of the column. The element tag also has a minOccurs attribute. This attribute actually defines whether a value is required for that element. The default for the minOccurs attribute is 1, which means that the element does not allow Null values. Also, take a close look at the lines at the end of the XSD that begin with 0 Then If txtCompanyName.Text.Length > 0 Then mCustomer = New CCustomer(txtCustomerID.Text, txtCompanyName.Text) Else MsgBox("A company name is required for a new Customer.") End If Else MsgBox("A CustomerID is required for a new Customer.") Page 387 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Exit Sub End If GetProperties() Me.rtbToString.Text = mCustomer.ToString Catch ex As Exception MsgBox(ex.Message) End Try End Sub Private Sub btnSave_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnSave.Click Try If mCustomer.Save() Then MsgBox("Save succeeded.") Else MsgBox("Save failed.") End If Catch ex As Exception MsgBox(ex.Message) End Try End Sub Private Sub btnDelete_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnDelete.Click Try If mCustomer.Delete() Then MsgBox("Delete succeeded.") mCustomer = Nothing ClearAllTextBoxes() Else MsgBox("Delete failed.") End If Catch ex As Exception MsgBox(ex.Message) End Try End Sub How It Works Page 388 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html When a consumer of the CCustomer class instantiates an object using the new constructor, the required properties of the object (the CustomerID and CompanyName) are set using the parameters of the constructor, whereas the optional properties are all set to zero-length strings. This constructor also sets an internal flag saying that the current instance is a new record. When the Save method is called, the internal flag tells the class that a new data row should be added to the dsCustomer dataset. Finally, the WriteChangesToDB is called and a new row is inserted into the Customers table. If the Save method is called with an existing record, the internal flag lets the class know that the data row already exists in the dsCustomer dataset, so the WriteChangesToDB method is called to update that row in the Customers table. The behavior of the Delete method also changes based on the value of the internal new-record flag. If the object instance is a new record, you don't need to delete the row from the database; therefore, the only necessary action is to dispose of the class-level variables. If the object instance is an existing record, the delete method of the data row is called. Finally, the WriteChangesToDB method is called to physically delete the row from the Customers table. Both the Save and Delete methods use the AcceptChanges and RejectChanges methods of the data row to react to exceptions thrown when making changes to the database. Comments One thing to note is that the Delete and WriteChangesToDB methods only return Boolean values and do not throw exceptions. The data validation code that you will see in the next section should prevent most of the exceptions that could be thrown when updating the database, so a Boolean return value is sufficient. Depending on your needs, however, this might to be too simple of an implementation. In the next section, you will learn how to create custom exceptions that will provide more error detail to consumers of your classes. [ Tea m LiB ] Page 389 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 9.6 Validate Data Passed to Properties and Communicate Errors to Developers To make a class that wraps up access to a table, it is critical that the class and not the developer who is using the class makes sure that all data is valid before writing it to the database. For example, in the Customers table, the CustomerID field must be five characters in length more, no less and, of course, it must be unique. no Phone numbers and fax numbers must also be validated. Although we don't necessarily know how many digits are in a phone number (France has eight-digit numbers, Spain has nine, and the U.S. has ten), we do know that only numbers and characters such as periods, parentheses, and hyphens are allowed. You also need to communicate with other developers when their data is not valid. It is the data class's job to make sure that invalid data doesn't make it to the database. This section presents three tasks: adding code to make sure that data passed to an object matches the column properties in the database, adding code that validates complex data types and business rules, and communicating errors to the class's consumers. Technique First, you need to pass errors back up the call stack. In Visual Basic 6, the accepted method was to use Err.Raise, which propagates an error number and an error message. This technique is still available to Visual Basic developers, but it retains all the old problems. If you aren't careful, programmers who are working on different components can raise the same error numbers, making error handling a potential nightmare. (If you aren't careful, you can end up raising the same error number in your own code.) You learned how to use structured exception handling in earlier chapters, but the beauty is that you can define your own exceptions as needed, with almost no code. Also, because exceptions have a name as opposed to a number, it is far easier for developers to work with your code. Finally, because exceptions are defined with a Namespace, even if two projects define an InvalidCustomerIDException, each exception will be unique. Second, you need to write code to check whether a value is valid. For the CustomerID, you simply need to check the length of the string. (Later on, you'll need to add code to check whether the ID already exists.) For phone numbers, you'll need to examine the string for invalid characters. Steps Because validating the maximum allowable length for all of our properties is simplest, tackle this task first. 1. Define a new exception class by inheriting from System.ApplicationException. As mentioned before, Microsoft recommends that all custom exceptions inherit from ApplicationException rather than Exception. System.ApplicationException has most of the methods and properties that you will need to communicate an exception to consumers of this class. The only property that a consumer might find useful is one that exposes what the maximum length of the property is. This would allow the consumer to communicate the error back to the user or truncate the string without having to hard-code the maximum length into his code. Adding the name of the property and the value is also a good idea. Some developers who are using your class might write one long Try...Catch block, so this information will help debug going forward. Paste the code in Listing 9.33 Page 390 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html defining the MaximumStringLengthExceededException into your code. Listing 9.33 frmHowTo9_6.vb: Class Declaration for the MaximumStringLengthExceededException Public Class MaximumStringLengthExceededException Inherits System.ApplicationException Private nMaxLen As Integer Public Sub New(ByVal pMaxLen As Integer, ByVal pPropertyName As String, ByVal pValue As String) ' You need to initialize the base class of this exception. ' If you do not specifically call a constructor of the base ' class, the default constructor (the one without parameters) ' will be called, if it exists. MyBase must precede the call to ' the base class's constructor so that the .NET runtime knows not ' to call a constructor in the derived class. MyBase.new("The value specified, " & pValue & _ ", exceeds the maximum " & "length of " & pMaxLen & " allowable by the " & _ pPropertyName & " property.") End Sub Public ReadOnly Property MaxLength() As Integer Get Return nMaxLen End Get End Property End Class 2. Next, modify the set block of each property in the class to check the length of the new value to see if it exceeds the maximum length of the column in the Customers table. If the length of the new value does exceed the maximum length, throw a new instance of the MaximumStringLengthExceededException. To do this, simply create an If...Then block that checks the maximum length into your class. When you have modified all of your properties, they should look like the ContactName property in Listing 9.34. Listing 9.34 frmHowTo9_6.vb: The ContactName Property Validates for the Maximum Length of the Column and Throws an Exception if the Value Passed to the Property Exceeds That Maximum Value Public Property ContactName() As String Implements ICustomer9_6.ContactName Get Return mstrContactName End Get Set(ByVal Value As String) If Value.Length <= 30 Then mstrContactName = Value Page 391 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Else Throw New MaximumStringLengthExceededException(30, "ContactName", Value) End If End Set End Property 3. Validating a phone number or fax number requires more than just checking the maximum length of the column. You need to make sure that only numbers and other allowable characters are in the value. First, create a new exception for invalid phone numbers by adding the code from Listing 9.35 to frmHowTo9_6.vb. Listing 9.35 frmHowTo9_6.vb: The InvalidPhoneNumberException Public Class InvalidPhoneNumberException Inherits System.ApplicationException Public Sub New(ByVal pstrPhone As String) MyBase.New("The phone number specified, " & pstrPhone & ", is not valid.") End Sub End Class 4. Next, add a private method called ValidatePhoneNumber to check a phone number string for invalid characters, such as letters or punctuation marks, as shown in Listing 9.36. Listing 9.36 frmHowTo9_6.vb: A Function That Validates Phone Numbers Private Function ValidatePhoneNumber(ByVal pstrPhone As String) As Boolean ' Create a string array that contains the numbers 0 to 9, as well as ' a hyphen, period, space, and parentheses. Dim cValidChars() As String cValidChars = New String(14) {"1", "2", "3", "4", "5", _ "6", "7", "8", "9", "0", "(", ")", "-", " ", "."} Dim i As Integer = 0 Dim nUBound As Integer = cValidChars.GetUpperBound(0) Dim nLBound As Integer = cValidChars.GetLowerBound(0) ' Loop through the array of valid characters and remove them ' from a phone number string. If characters are left ' in the string, the phone number is invalid. For i = nLBound To nUBound Step 1 pstrPhone = pstrPhone.Replace(cValidChars(i), "") Next pstrPhone = pstrPhone.Trim() If pstrPhone.Length > 0 Then Return False Else Return True End If Page 392 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Function 5. Modify the set blocks of the Fax and Phone properties to call the ValidatePhoneNumber method and throw an InvalidPhoneNumberException if the phone number is not valid. Your code should look like Listing 9.37. Listing 9.37 frmHowTo9_6.vb: The Phone Property That Validates Phone Numbers Public Property Phone() As String Implements ICustomer.Phone Get Return mstrPhone End Get Set(ByVal Value As String) If Value.Length <= 24 Then If ValidatePhoneNumber(Value) Then mstrPhone = Value Else Throw New InvalidPhoneNumberException(Value) End If Else Throw New MaximumStringLengthExceededException(24, "Phone", Value) End If End Set End Property 6. The last piece of data that you need to validate is the CustomerID. You need to validate for the string length, and for new customers, you need to validate for the uniqueness of the proposed CustomerID. Validating for the proper length of a CustomerID is simple. First, add a new exception called InvalidCustomerIDException, as shown in Listing 9.38. Listing 9.38 frmHowTo9_6.vb: Declaration of the InvalidCustomerIDException Public Class InvalidCustomerIDException Inherits System.ApplicationException Public Sub New(ByVal pstrID As String) MyBase.New("The customer ID specified, " & pstrID & ", is not valid") End Sub End Class 7. Then add the method from Listing 9.39, which checks the length of a CustomerID string and ensures that the string has no whitespace. Listing 9.39 frmHowTo9_6.vb: The ValidateCustomerID Method Private Function ValidateCustomerID(ByVal pstrID As String) As Boolean ' Strip out any leading or trailing spaces. pstrID = pstrID.Trim Page 393 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ' A CustomerID must have five characters. If pstrID.Length = 5 Then Return True Else Return False End If End Function 8. Now add code like that in Listing 9.40 to your constructor that validates the CustomerID, and, if that value is invalid, throws an InvalidCustomerIDException. Listing 9.40 frmHowTo9_6.vb: An If...Then Block to Wrap Around Your Constructor Code If ValidateCustomerID(pCustomerIDToRetrieve) Then ' Your original constructor code goes here. Else Throw New InvalidCustomerIDException(pCustomerIDToRetrieve) End If 9. The final piece of validation code you need to add is a function that checks for the existence of a CustomerID before a new Customer object is instantiated. You could use the data access objects you defined in CCustomerData, but for performance purposes, you should create a new command object and use the ExecuteScalar method as shown in Listing 9.41; this method requires less interaction with the database. Listing 9.41 frmHowTo9_6.vb: The DoesCustomerIDExist Function Private Function DoesCustomerIDExist(ByVal pstrID As String) As Boolean Dim strSQL As String = "SELECT COUNT(*) FROM Customers " & _ "WHERE CustomerID = '" & pstrID & "'" Dim cmd As New System.Data.OleDb.OleDbCommand(strSQL, oleCnn) Dim fExists As Boolean oleCnn.Open() fExists = CBool(cmd.ExecuteScalar()) oleCnn.Close() Return fExists End Function Add an extra If...Then block in the constructor used to create a new Customer row and you're ready to start testing your new code. Your existing code for frmHowTo9_6 should suffice for testing. You made sure to handle exceptions thrown from properties in section 9.2. How It Works Page 394 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Much of the code in this section qualifies and extends the properties you have already defined and implemented. This section has two key concepts. Validating data is a critical part of any application, although the examples in this section use validation techniques you should already be familiar with. The next section will take data validation to a new level. The most important concept is declaring your own exceptions. Communicating errors to other parts of the application is, perhaps, more important than the business logic you implement. When it works, it works, but when something goes wrong, providing enough information about the error is far more important. Creating new exceptions is an elegant and readable way to communicate and handle errors. Comments Hardcoding the maximum column length into the property set block as recommended in this section isn't necessarily the best solution to this problem. If you decide to increase or decrease the length of the column in the database, you must search through all of your source code to find every place that value was hard coded. Using constants is one way around this, but your options still are fairly limited. The strongly typed dataset you created earlier has the potential to provide an elegant solution to this problem. The XSD that underlies the dataset could define many of the data rules in your tables, including the maximum length of columns. Also, the actual dataset exposes this information in its properties and methods. The problem is that Visual Studio .NET does not generate XSDs with such strict definitions. [ Tea m LiB ] Page 395 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 9.7 Write Data Validation Code That Can Be Reused in Other Classes As you were writing the PhoneNumber and CustomerID validation code in the previous section, you might have thought that this code would be extraordinarily useful in other parts of the Northwind application. For example, the Suppliers and Employees tables also have Phone and Fax fields, and the CustomerID column is also defined in the Orders table. Technique In this section, you will pull the data validation code you wrote for both the PhoneNumber and CustomerID columns and create independent objects that encapsulate your existing validation logic. Then you will update the CCustomer class to make use of these new classes. The CCustomerID class will be a simple class that performs two functions: checking the length of the ID and looking in the database to see if the CustomerID exists. For the PhoneNumber data validation, you will learn how to create an entire object model that will provide you with data validation for different types of phone numbers with a bare minimum of code. And, just for the fun of it, you will learn how to use the same base class you use to validate phone numbers to validate Social Security numbers. Steps 1. Add a new class file to your project by right-clicking on the project in the Solution Explorer window and selecting Add Class from the Add submenu. Name the new class CCustomerID.vb. 2. Copy the DoesCustomerIDExist and ValidateCustomerID methods from the CCustomer class into the CCustomerID class. Rename them Exists and Validate, respectively. 3. Copy the InvalidCustomerIDException from CustomerClass.vb and paste it inside the CCustomerID class. This makes your exceptions directly related to the CCustomerID. 4. One gap in splitting off the CustomerID property into its own class is that some parts of your application might want a read/write CustomerID property, whereas others, such as the CCustomer class, need a ReadOnly property. Instead of having a Boolean set to lock the property, a more flexible way is to add an event to your class that is called before setting the property, allowing a containing class to cancel the change. 5. 6. Public Event BeforeUpdate(ByVal pstrCustomerID As String, ByRef pfCancel As Boolean) 7. Now add a new property called CustomerID to the CCustomerID class, as shown in Listing 9.42. This property should raise the BeforeUpdate event, and if the changes are not cancelled, call the Validate method and throw an InvalidCustomerIDException if the CustomerID is invalid. Listing 9.42 CCustomerID.vb: The CustomerID Property of the CCustomerID Class Property CustomerID() As String Get Return mstrCustomerID Page 396 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Get Set(ByVal Value As String) Dim fCanceled As Boolean RaiseEvent BeforeUpdate(Value, fCanceled) If Not fCanceled Then mfValid = Validate(Value) If mfValid Then mstrCustomerID = Value Else Throw New InvalidCustomerIDException(Value) End If End If End Set End Property 8. Then add a new constructor that accepts a CustomerID as a parameter. That constructor, shown in Listing 9.43, should call the property statement, which will handle validation. Listing 9.43 CCustomerID.vb: The Constructor for the CCustomerID ClassPublic Sub New(ByVal pID As String) Me.CustomerID = pID End Sub 9. You're almost finished with the CCustomerID class, except for one subtle issue: pointers. Everything you've written in this chapter so far has used base datatypes, so you haven't had to worry about copying values between function calls. But objects work differently than base datatypes do. The issue is with ByVal and ByRef. With base datatypes, the distinction is fairly straightforward: ByVal passes a copy of the value of the variable to the function. The called function could do whatever it pleased to the passed value without impacting the value of the variable in the calling function. ByRef passes the called function a pointer instead of the value, so any change made to the variable in the called function is made to the variable in the calling function. With objects such as CCustomerID, it's completely different. Whether you use ByVal or ByRef, you're still working with a pointer. The called function will always modify the object that the calling function passes. The difference is in reassigning the pointer. ByVal passes a pointer to an object. If the called function changes the pointer to a new object, the calling function will still point at the original object. ByRef passes a pointer to a pointer to an object. If the called function changes the pointer to a new object, the calling function will now point at the new object instead of the original object. The point(er) here is in the constructors. You want to provide a way for other developers to create copies of the class easily, or you might end up with the same CCustomerID object being used simultaneously in a potentially conflicting fashion. The solution? Add a Page 397 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html constructor to the CCustomerID class that accepts a CCustomerID object as a parameter, as shown in Listing 9.44. Listing 9.44 CCustomerID.vb: An Object-Based Constructor for the CCustomerID Class Public Sub New(ByVal pID As CCustomerID) ' Both ByVal and ByRef pass object pointers, so if you ' want to create a new CustomerID instance based on an ' existing instance, you need to copy the values of the ' base datatypes to a new instance. Me.CustomerID = pID.CustomerID End Sub 10. Updating the CCustomer class is not difficult, but it does require many small, similar changes, including the following: o o o Retyping variables Removing code validating CustomerIDs and related exception throwing Calling CCustomerID's object-based constructor from Listing 9.43 each time a CCustomerID object is passed into a CCustomer object o Adding .CustomerID after every CCustomerID variable where the string value is needed The constructor in Listing 9.45 that you use to create new customers in the database is a good example of all of these changes. Listing 9.45 CCustomerID.vb: An Excerpt of a CCustomer Constructor as Modified to Use the CCustomerID Class Public Sub New(ByVal pCustomerID As CCustomerID, ByVal pCompanyName As String) ' Change A: retyping variables ' Instead of accepting a string that has to be validated, ' this constructor accepts a CCustomerID object that by ' definition is valid. If pCustomerID.Exists Then ' Change B: removing code validating CustomerIDs ' If you recall, there used to be an additional condition ' in this If... Then that checked the length of the CustomerID. ' Now, the CCustomerID guarantees a valid CustomerID. mdsCust = New dsCustomers() mfNew = True ' Change C: using the object-based constructor ' Just to make sure, create a new CCustomerID object. If you ' don't, consumers of this class will retain a pointer to this ' object instance, allowing that consumer to change the value ' of the shared CCustomerID object unbeknownst to the CCustomer object. Page 398 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html mCustomerID = New CCustomerID(pCustomerID) Me.CompanyName = pCompanyName Else ' Change D: calling the CustomerID property when you need a string. ' When you throw an InvalidCustomerIDEException, you won't necessarily ' have a valid CustomerID, so this exception has to accept a string ' instead of an object. This InvalidCustomerIDException is used to express ' that the CustomerID for the new customer already exists in the database. Throw New CCustomerID.InvalidCustomerIDException(pCustomerID.CustomerID) End If End Sub Tip One way to identify all these changes is to change the type of the CustomerID property in the ICustomer interface, as well as the name of the class-level variable in the CCustomer class that holds CustomerID values. Because this will invalidate much of the code utilizing CustomerIDs, Visual Studio .NET will put a wavy blue line under the code you need to modify. 11. You will also need to redeclare the mCustomerID variable using the WithEvents keyword and add an event handler that cancels the change, as shown in Listing 9.46. Listing 9.46 frmHowTo9_7.vb: Adding Event Handlers to CCustomer to Handle the CCustomerID BeforeUpdate Event Private WithEvents mCustomerID As CCustomerID Private Sub mCustomerID_BeforeUpdate(ByVal pstrCustomerID As String, ByRef fCancel As Boolean) Handles mCustomerID.BeforeUpdate fCancel = True End Sub The next task in this section is to provide similar validation functionality for phone numbers that can be used throughout your application. At the end of this task, you will have four separate classes, all of which extend the functionality of a fifth base class. Before you begin coding so many classes, it is always a good idea to plan precisely what you want to write. Figure 9.8 is a class diagram that describes the classes you're going to write and their relationship to each other. The class at the top of the diagram is our base class. The base class has only one purpose: It contains a method that checks a string of numbers to see whether the string has invalid characters. All of the other classes will inherit this validation method, but each class will change the definition of valid characters in the string. Figure 9.8. A class diagram describing the classes to be developed in section 9.7. Page 399 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html According to the class diagram, this class has only seven members: two variables ( cValidChars and mstrValue), one property (StringValue), three methods (IsValid, ThrowException, and DefineValidChars), and one member class ( InvalidNumberStringException). You might have noticed a symbol before each member declaration. This symbol refers to the accessibility of the member. A minus sign ( ) means the member is Private, a number sign (#) means Protected, and a plus sign (+) means Public. If this doesn't make sense at the moment, don't worry. It will be much clearer when you see the code. 12. Because all of the classes rely on code in the base class, you should start by defining the CNumberString class. This class will be the most complex in this hierarchy, so you will walk through it step-by-step. First, right-click on your project in the Solution Explorer and select Add Class from the Add submenu. Name the class PhoneDatatypes.vb. 13. Declare the CNumberString class block, as well as the InvalidNumberStringException member class, using the MustInherit keyword, as shown in Listing 9.47. The MustInherit keyword means that the CNumberString class cannot be instantiated directly. Instead, the class must be inherited by another class for its members to be accessed. Listing 9.47 PhoneDatatypes.vb: Declaration of the CNumberString Abstract Class Public MustInherit Class CNumberString Page 400 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Public MustInherit Class InvalidNumberStringException Inherits System.ApplicationException Protected Sub New(ByVal pstrMessage As String) MyBase.New(pstrMessage) End Sub End Class End Class A class that is declared with the MustInherit keyword is known as an abstract class, and it is best described as a hybrid between an interface and a class(see Table 9.3). Like an interface, instances of an abstract class cannot be created directly, and its methods and properties need not have code. Like a regular class, an abstract class does contain some implemented methods and properties, and even though it cannot be instantiated, it can have constructors. Table 9.3. Visual Basic .NET Class Inheritance Permission Keywords Keyword Definition Instances of the class cannot be created directly, and the class must be inherited to be used. MustInherit NotInheritable The class is in a finalized state and cannot be used as a base class. 14. Declare the two class-level variables: cValidChars and mstrValue. Note that both variables are declared as protected. This means that the variables will only be accessible to derived classes because those classes will need to modify the list of valid characters and might need to access the string value. 15. Declare the DefineValidChars, IsValid, and ThrowException methods as shown in Listing 9.48. You might also want to add an Event declaration that fires before updating the StringValue property. (If you do not, you won't be able to catch changes made to properties in CCustomer; thus, you won't be able to check for the maximum length of the Phone and Fax properties.) Listing 9.48 PhoneDatatypes.vb: Declaration of the IsValid, DefineValidChars, and ThrowException Methods Public Sub New() DefineValidChars() End Sub Public Event StringValueBeforeUpdate(ByVal pstrValue As String, _ ByRef pCancel As Boolean) Page 401 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Protected Overridable Sub DefineValidChars() cValidChars = New String(9) {"1", "2", "3", "4", "5", _ "6", "7", "8", "9", "0"} End Sub Public Overridable Function IsValid(ByVal pstrNumber As String) As Boolean Dim i As Integer = 0 Dim nUBound As Integer = cValidChars.GetUpperBound(0) Dim nLBound As Integer = cValidChars.GetLowerBound(0) For i = nLBound To nUBound Step 1 pstrNumber = pstrNumber.Replace(cValidChars(i), "") Next pstrNumber = pstrNumber.Trim() If pstrNumber.Length > 0 Then Return False Else Return True End If End Function Public MustOverride Function ThrowException() As InvalidNumberStringException The IsValid method is the key to the whole thing, and is really just the ValidatePhoneNumber method from the previous section. The DefineValidChars method populates the list of valid characters. It has been separated from the IsValid method so that derived classes can easily redefine the list of valid characters without having to rewrite the IsValid method. Both of these methods have been declared as Overrideable. This means that a derived class has the option of redefining either of these methods. In previous sections, you regularly overrode constructors when you created custom exceptions based on the ApplicationException. (Actually, constructors of a base class are never exposed as constructors of a derived class, so they are overridden by default). If you recall, you can still access the overridden constructor within your class by using the MyBase keyword. The same goes for methods: You can call the overridden method within your class by using the MyBase keyword. The ThrowException method is declared using the MustOverride keyword (see Table 9.4 ), and it is an abstract method. Any class that inherits from the CNumberString class must implement this method. This works just like a method that is declared in an interface, except that you do not need to use the Implements keyword in the method declaration. Table 9.4. Visual Basic .NET Member Override Keywords Keyword Definition The method overrides the member of the base class with the same signature. Overrides Page 402 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Overrideable MustOverride The method can be overridden in a derived class. The method must be overridden in every derived class. NotOverrideable The method can never be overridden by a derived class. 16. The last member to implement is the StringValue property defined in Listing 9.49. Note that properties cannot be overridden. Listing 9.49 PhoneDatatypes.vb: The StringValue Property Public Property StringValue() As String Get Return mstrValue End Get Set(ByVal Value As String) Dim fCancelChange As Boolean If isValid(Value) Then RaiseEvent StringValueBeforeUpdate(Value, fCancelChange) If Not fCancelChange Then mstrValue = Value End If Else Throw ThrowException(Value) End If End Set End Property It doesn't look like much is going on here, but this is the most interesting member in the class. Why? This member is responsible for all data validation, including validation kicked that constructors kick off. All of the methods called in this member are overrideable, though. In other words, the IsValid method that it looks like you're calling could be any IsValid method from any derived class. And the ThrowException method isn't even defined in this class. The actual method called always will be defined in a derived class. 17. The simplest derivation of the CNumberString class is a class that handles phone number extensions. (You will use this as part of a BusinessPhone number class later.) A phone extension contains only numbers, so you don't need to modify the IsValid method or the DefineValidChars method. As you can see in Listing 9.50, all you need is to define an exception, a method to throw it, and a constructor that calls the constructor of the CNumberString class and the StringValue property. Listing 9.50 PhoneDatatypes.vb: A Simple Class for Phone Number Extensions Derived from the CNumberString Class Page 403 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Public Class CExtension Inherits CNumberString Public Class InvalidPhoneExtensionException Inherits CNumberString.InvalidNumberStringException Public Sub New(ByVal pstrPhoneNumber As String) MyBase.New("The phone extension specified, " & pstrPhoneNumber & ", contains invalid characters.") End Sub End Class Sub New(ByVal pstrExtension As String) MyBase.New() Me.StringValue = pstrExtension End Sub Public Overrides Function ThrowException(ByVal pstrInvalidExt As String) As InvalidNumberStringException Throw New InvalidPhoneExtensionException(pstrInvalidExt) End Function End Class So what's going on? The CExtension constructor calls the constructor of the CNumberString class, which calls CNumberString.DefineValidChars. Then, the string value is passed to the CNumberString.StringValue property, where its validity is checked. (If that doesn't make sense, create an instance of the class and step through it line by line.) 18. To take the example a step further, create a phone number class that inherits from the CNumberString class. As in the CExtension class from Listing 9.50, , you will need to declare an exception, a method to throw it, and a constructor to create the class. The only substantive change in Listing 9.51 is the addition of several new valid characters including parentheses, periods, and hyphens to the list of valid characters. Listing 9.51 PhoneDatatypes.vb: An International Phone Number Extension of the CNumberString Class Public Class CPhoneNo Inherits CNumberString Public Class InvalidPhoneNumberException Inherits CNumberString.InvalidNumberStringException Public Sub New(ByVal pstrPhoneNumber As String) MyBase.New("The phone number specified, " & pstrPhoneNumber & _ ", contains invalid characters.") End Sub End Class Page 404 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Sub New(ByVal pstrPhoneNo As String) MyBase.new() Me.StringValue = pstrPhoneNo End Sub Sub New(ByVal pPhoneNo As CPhoneNo) Me.New(pPhoneNo.StringValue) End Sub Public Overrides Function ThrowException(ByVal pstrInvalidPhone As String) _ As InvalidNumberStringException Throw New InvalidPhoneNumberException(pstrInvalidPhone) End Function ' This is the only substantive change. This sub redefines the DefineValidChars ' method so that when this method is called in the base class's constructor, it will ' call this method instead of the original method. Protected Overrides Sub DefineValidChars() cValidChars = New String(14) {"1", "2", "3", "4", "5", _ "6", "7", "8", "9", "0", _ "(", ")", " ", ".", "-"} End Sub End Class What's going on? The CPhoneNo constructor calls the constructor of the CNumberString class, but because you overrode DefineValidChars, CNumberString.New actually calls CPhoneNo.DefineValidChars instead of CNumberString.DefineValidChars. Tip You can combine the CExtension and CPhoneNo classes to create a CBusinessPhone class that would be far more useful in an application of this sort. A sample of this code is included in PhoneDatatypes.vb. 19. Utilizing the phone number class in your existing code is a process similar to what you did to integrate the CCustomerID class in earlier in this section. Again, you will need to do the following: o o o Retype variables. Remove code validating phone numbers and related exception throwing. Add .StringValue after every CPhoneNo variable where the string value is needed. o Calling CPhoneNo's object-based constructor from Listing 9.51 each time a Page 405 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CCustomerID object is passed into a CCustomer object. 20. More important, you will need to move the maximum length validation to event handlers, as shown in Listing 9.52. The value of the phone number contained in the CphoneNo class can be changed without changing the phone number property, which is just a pointer. Listing 9.52 PhoneDatatypes.vb: An Event Handler for the mFax Variable in the CCustomer Class Private Sub mFax_StringValueBeforeUpdate(ByVal pstrValue As String, ByRef pCancel As Boolean) Handles mFax.StringValueBeforeUpdate If pstrValue.Length <= 24 Then pCancel = False Else pCancel = True Throw New MaximumStringLengthExceededException(24, "Fax", pstrValue) End If End Sub 21. The final code example of this chapter will take another look at the CNumberString base class and suggest another potential use for it: Social Security numbers. A Social Security number is similar to a phone number in that it is a string of numbers formatted with a limited set of characters. In the Northwind database, you did not have the option of strictly validating a phone number because you could not be sure of the specific format that the customer's country might use. A Social Security number is a different story: Two hyphens must be present at specific locations in the string. The complete CsocialSecurityNo class is defined under Listing 9.53. Listing 9.53 PhoneDatatypes.vb: Another Extension of the CNumberString Class, This Time for SSNs Public Class CSocialSecurityNo Inherits CNumberString Public Class InvalidSSNException Inherits CNumberString.InvalidNumberStringException Sub New(ByVal pstrSSN As String) MyBase.New("The SSN specified, " & pstrSSN & ", is not valid.") End Sub End Class Sub New(ByVal pstrSSN As String) MyBase.new() StringValue = pstrSSN End Sub Sub New(ByVal ssn as CSocialSecurityNo) Page 406 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html MyBase.New(ssn.StringValue) End Sub Public Overrides Function IsValid(ByVal pstrSSN As String) As Boolean If MyBase.IsValid(pstrSSN) Then Dim nFirstHyphen As Integer = pstrSSN.IndexOf("-") ' An SSN must have a hyphen at index 3 and 6. If nFirstHyphen = 3 Then If pstrSSN.IndexOf("-", nFirstHyphen + 1) = 6 Then If pstrSSN.Chars(0) = "0" Then Return False Else Return True End If Else Return False End If Else Return False End If End If End Function Public Overrides Function _ ThrowException(ByVal pstrInvalidSSN As String) As InvalidNumberStringException Throw New InvalidSSNException(pstrInvalidSSN) End Function Protected Overrides Sub DefineValidChars() cValidChars = New String(10) {"1", "2", "3", _ "4", "5", "6", "7", "8", "9", "0", _ "-"} End Sub End Class Just like the CPhoneNo example, the DefineValidChars is overridden to allow a hyphen to be valid character. The real change is in the overridden IsValid method. First, the IsValid method for the base class (CNumberString.IsValid) is called to verify that the string only contains numbers and hyphens. Then, the string is checked to verify that the hyphens are in the proper location. When the StringValue property is set, the overridden IsValid method in CSocialSecurityNo is called, which in turn calls the IsValid method in CNumberString. Page 407 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html How It Works The CCustomerID example in the beginning of this section is a perfect example of encapsulation and a simple example of the goal of object-oriented code. One piece of business logic the definition of a CustomerID and a way to determine its uniqueness and/or existence is wrapped up in one piece of small, reusable code. Any other class that represents a table containing a CustomerID can utilize the CCustomerID class and is guaranteed to always have a valid value whose existence in the database can be verified painlessly. The CNumberString class, in combination with its derived classes, extends the reusability concepts exhibited in the CCustomerID class. Inheritance might be a new concept and a new way of thinking about code, but the implementation of inheritance is simple. Any time that you inherit from another class, all the code in that base class is immediately available to you. Comments Inheritance is a powerful, flexible way to write code, not only quickly, but in a way that is much easier for other developers to understand. If the earlier samples make sense, you might be tempted to design extraordinarily complex object models utilizing a substantial amount of inheritance, polymorphism, and abstraction. Two notes of caution:  There is slightly more runtime overhead with derived classes because the CLR must resolve which members of the object must actually be called. This cannot be done at compile time, because in many cases, the specific type of the object is ambiguous in static source code.  The clarity and readability of object-oriented code can be countered by an overly complex object model. Always keep it simple. If that means a bit of "editor inheritance" here and there, so be it. It's better than object-oriented spaghetti code. [ Team LiB ] Page 408 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 10. Creating Reports Using Crystal Reports In this chapter you will     Create a report using Crystal Reports report expert Display a report that was created Add calculated fields to the Crystal Reports report Select whether the report will be displayed, printed, or exported using Visual Basic .NET code    Determine which records will be printed at runtime Print labels and control the order in which records will be printed Create an onscreen report that contains hyperlinks Crystal Reports is the report writer that has been included in Visual Basic since 1993. It uses a banded approach, as do many other report designers, such as Access's report writer and dBASE. Crystal Reports is included in Visual Studio .NET for use with both Windows Forms and Web Forms. You can deploy your reports and have them store locally or even using a Report Web Service. This chapter uses Windows Forms to show how to create and run Crystal Reports. Note Be sure to verify the licensing before deploying reports that were created using Crystal Reports. In Visual Studio help, look up Crystal Reports and then licensing. [ Team LiB ] Page 409 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.1 Create a Report Using Crystal Reports Report Expert I have created quite a few applications that allow the users to manipulate data in various ways. Now I need to create some reports so that I can present information for my clients and users. How do I create a report with Crystal Reports using one of these Experts I have heard about? Technique You can create a report and include it in your projects as needed. Getting Started Creating a Crystal Report After right-clicking on your project in the Solution Explorer, you need to choose Add New Item from the Add menu item. You then can pick Crystal Report from the templates and name it appropriately. Note If you name your reports with the prefix of rptReportName, you will be able to find all your reports in one location. After you have clicked the Open button on the dialog box, you are presented with the Crystal Report Gallery dialog box, shown here in Figure 10.1. Figure 10.1. These Experts can save you time when you're creating reports. Page 410 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Crystal Reports includes wizards called Experts. These Experts assist you in performing certain tasks, from creating a whole report to creating an individual formula for a field. Experts are actually made up of other Experts. For instance, the Report Expert utilizes the Formula Expert within itself; however, you also can take advantage of the Formula Expert from within the Report Designer. Types of Reports You Can Create with the Report Expert This How-To will discuss the Report Expert. This Expert creates various types of reports, listed in Table 10.1, in alphabetical order. Table 10.1. Types of Reports Created by the Report Expert Report Type Crosstab Description Crosstab reports give you a cross-tabulation of your data, such as sales of customers by years. Drill Down This report is broken down into sections that start out as hidden, and then allow the user to "drill down" further into the information. An example of this would be a report that lists customers. When the user clicks on a particular customer, the invoices for that customer are displayed. Next, when you click on a particular invoice, its line items (or details) can be displayed. Form This report helps to create preprinted forms that use company logos and forms. Examples of this type include invoices. Forms letters, such as late notices and sales letters, are created using this expert. Form Letter Mail Labels This expert allows you to create mailing labels that are any size and any number of columns. Standard The standard report is just that a standard list report that lists your information. It allows you to group and sort information, include formulas, and set an overall format for the report. This is the report that will be demonstrated for this How-To. SubReport This report helps you to create main reports that utilize subreports. An example is invoices for customers. If the Standard report type is highlighted, click OK, and the Standard Report Expert dialog opens, as shown in Figure 10.2. Figure 10.2. The tabs on this dialog box are actually experts in their own rights. Page 411 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Tabs Included in the Standard Report Wizard Included on the Standard Report Wizard are the following tabs:  Data. Specify the database and table that you will be using for this report. You will have a number of different choices from datasets within the current application to OLEDB connections. For this chapter, you will be creating an OLEDB connection to the Northwind database.  Fields. After you have selected your record source, you then get a list of the fields from within your record source (see Figure 10.3). Figure 10.3. Besides fields from your table, you can create formulas (expressions) as well. Page 412 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html In addition to creating formulas, you can view the data using the Browse Data option and locate fields using the Find Field option.  Group. This tab allows you to specify the group levels you want to include. An example you will see here groups the customer by region (see Figure 10.4). Figure 10.4. It is often useful to be able to organize your reports based on groupings, such as the Region field in this report. Tip Page 413 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html If you want to have a field used for grouping, then you will most likely not want to have it listed in the detail section. It is important that you do not choose it back on the Field tab; just choose it from the Group tab. Of course, if you accidentally include it in the detail section after the report is created, you can always delete it later from the report while you're in the Design view.  Total. This tab allows you to specify which fields you want to summarize in the group footers and report footer.  Top N. You can set how you want the groups sorted, based on the totals set by the last tab, Total.   Chart. Create a chart of your data. Select. Filter which records you want to have reported based on field values. You will see how to do this at runtime in How-To 10.5.  Style. You can give your report a number of different looks. You also can specify the title of your report (see Figure 10.5.) Figure 10.5. This chapter will stick to using the Red/Blue border style. After you have finished specifying your report features, click Finish. Your report will now be displayed in Design view (see Figure 10.6). Figure 10.6. The finished product. Page 414 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html For this How-To, you want to get to the point where you have the report created. The next How-To describes how to actually view the report on a Windows Form. You can find all the examples in this chapter in the Solution called Visual Basic .NET the Web site. Chapter 10 on Steps Open the Visual Basic .NET Chapter 10 solution. In the Solution Explorer, you see the report rptHowTo10_3.rpt. You then see a report that looks similar to the one in Figure 10.7. 1. Right-click on your project in the Solution Explorer, and choose Add New Item menu item from the Add menu item. Type a name for the report in the Name field, and click Open. The Crystal Report Gallery dialog box opens. 2. Leaving the defaults as they are, which is to use the Report Export and create a Standard report, click the OK button. You are taken to the Report Expert, with the Data tab displayed. 3. Double-click on the OLE DB (ADO) node in the Available Data Sources tree if you haven't chosen a data source before. The OLE DB (ADO) dialog box opens the option and asks you to choose an OLE DB provider. Choose Microsoft OLE DB Data Provider for SQL Server (see Figure 10.7) and click Next. You are requested to enter connection information. For this page, type (Local) for the server, check Integrated Security, and type Northwind for the database (see Figure 10.8). Click Finish. Your Available Data Sources will now include (Local) under the OLE DB (ADO) node and Northwind under the local connection. Figure 10.8. Information that is needed to create the Northwind connection. Page 415 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Expand the tree under Northwind to get to the first DBO, and then expand Tables. You then see the tables listed, including the Customers table. Highlight the Customers table, and click Insert Table. The table is displayed in the Tables in Report list (see Figure 10.9.) Click Next. Figure 10.9. After you have the Tables node expanded, it is easy to tell where your record sources come from. 5. From the Fields tab, add the fields as displayed in Figure 10.10, and then click Next. You are Page 416 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html taken to the Group tab. Figure 10.10. These fields will be displayed in the Details section of the report. 6. Under the (local) node in the field tree, select Region from the Customers table, and click Add. Now you're ready to choose the style. Skip over to the Style tab by clicking on it directly. 7. Type My First Report for the title of the report, and then select Red/Blue Border for the style. Click Finish, and your report is displayed in Design mode. Figure 10.7. Choosing the OLE DB (ADO) Data provider. Page 417 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments The next How-To explains how to display your report. You can modify your report by both clicking on controls and changing them in the Design mode, or right-clicking on one of the section bodies (not the gray bands), and choosing Report, Report Expert. This takes you right back into the Report Expert to let you make some tweaks when you have to. You will also see the various tabs of the Report Expert as you right-click and choose some of the individual Experts to give you a hand. Try these right now. Take some time to right-click on some of the section bodies, and select some of the choices from the pop-up menu to play with, such as Report, then Style Expert. [ Team LiB ] Page 418 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.2 Display a Report That Was Created The report doesn't do me much good in Design mode. How do I go about viewing the report? Technique You can review a report in a couple of ways. You can view a report either using a Windows Form or a Web Form. Either way, you will also use a control called the Crystal Report Viewer. Introducing the Crystal Report Viewer The Crystal Report Viewer is a control that is available in the Toolbox. It is the last control by default. Crystal Report Viewer does far more than just let you view your document on the form. With the Viewer, you can do any of the following:        View the report on the form. Zoom in and out on the document. Expand and collapse groupings on the document. Print from the Viewer. Export from the Viewer. Move around in the document Search for text within the report. You can see an example of the Crystal Report Viewer on a Windows Form in Figure 10.11, where the example form from this How-To is displayed. Figure 10.11. The Crystal Report Viewer provides the user with several features, but most of the features can be disabled if necessary. Page 419 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Sometimes you might not want the user to have all the features that come with the Viewer. The good news is that the Viewer actually has its own object model whereby you can set some of the properties at design time or runtime. The Viewer even has an event model that you can program. You can see the object model for the Windows Form CrystalReportViewer in Figure 10.12. Figure 10.12. Using the object model displayed here, you have almost complete control over the Viewer behavior. Page 420 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Although you can make the Viewer stand on its head using the object model, to get started, you really only have to set one property: the ReportSource. Just as it sounds, the ReportSource tells the Viewer which report to display. You can set the ReportSource in a variety of ways. You can set the ReportSource property to the file path and name of a report, or you can create what is called a strongly typed report document. Specifying the ReportSource by Using the Report To specify a report file, click on the down arrow in the ReportSource property, and choose (Browse). The Open an Existing Crystal Report dialog box opens. There, you can look for the report that you want to assign within your project folder. The bad part about assigning the report file directly is that when you move the application, the file path is not updated. A better way to assign the ReportSource is to use a Report Document to strongly type the report. Specifying the ReportSource Using a Strong Typed Report When you're using strong typed reports, you can move your application and the report file without having to re-establish the file path to the report. To accomplish this, you use what is called a Report document. You can find the Report document in the Component list. In there, it is called ReportDocument. When you pull the ReportDocument component onto your form, you are asked to supply a report to be strong typed. After you have chosen your report, the ReportDocument appears in your Component tray. When you assign the ReportSource, the ReportDocument appears first in the list (see Figure 10.13). Figure 10.13. Using the ReportDocument is the way to go when you're assigning reports to Viewers. Steps Page 421 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Open and run the Visual Basic .NET Chapter 10 solution. Click on the button labeled How-To 10.2. You immediately see the report show up that was created in the last How-To. Play with the toolbar buttons on the Viewer to see how they work. When you maximize the form, you the Viewer expands as well. That is because the Viewer is anchored (see Figure 10.14). 1. 2. 3. Create a Windows Form. Drag a CrystalReportViewer control from the toolbox onto the form. Drag a Report document from the Component list onto the form. Type the report name you created in the first How-To (see Figure 10.15). Figure 10.15. This report is strongly typed. Tip After you have clicked OK to accept the Report document, you might want to set the Name property of the control to a name with an rd prefix. I named mine rdHowTo10_2. That way, in later code, I know I am dealing with a ReportDocument control. 4. Set the ReportSource property of the CrystalReportViewer control to the name of your Report document. 5. Set the Anchor property of the Viewer to be Top, Bottom, Left, Right. This ensures that the Viewer fills the form, regardless of the size of the form. Figure 10.14. The report displayed in the Crystal Report Viewer. Page 422 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments That's it, if you open the form now, you will see the report displayed in the form. You get so many features with the Crystal Report Viewer just by dumping it on the form with no code. [ Team LiB ] Page 423 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.3 Add Calculated Fields to the Crystal Reports Report Although creating reports based on given fields in tables is fine, it just does not give the flexibility I need. To have that, I need to know how to add calculated fields to my reports. Technique In Crystal Reports, calculated fields are known as formulas. To create and edit formulas, you will use the Formula Editor (see Figure 10.16). Figure 10.16. You can display this Formula Editor from either the Report Expert or the Report design. When you're in the Report Expert, you can add a new formula by clicking on the Formula button, located on the Fields tab. In Report design, you can add a field by opening the Field Explorer, located to the left of the IDE with the toolbox, and expanding the Formula Fields tree. You can also right-click on the Formula Fields base node and choose New to add a new formula. Formulas are similar to T-SQL expressions in that you can combine fields or values with operators to create a Formula field. For example, a formula called @TotalPricePerUnit is being created for this How-To. You saw it displayed in Figure 10.16. The expression used is this: {Invoices.UnitPrice}*{Invoices.Quantity} You can use Formula fields in summary sections and grand totals. The best way to verify a formula is to create it when you use the Report Expert to create a report. Steps Open the Visual Basic .NET Chapter 10 solution. In the Solution Explorer, you will see the report Page 424 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html rptHowTo10_3.rpt. Scroll over to the left so that the last column is visible. This is the Formula field. 1. Right-click on your project in the Solution Explorer and choose Add New Item from the Add menu item. Type the name of the report in the Name field and click Open. The Crystal Report Gallery dialog box opens. 2. Leaving the defaults as they are, which is to use the Report Export and create a Standard report, click the OK button. You are taken to the Report Expert, with the Data tab displayed. 3. Double-click on the OLE DB (ADO) node in the Available Data Sources tree. If you haven't chosen a data source before, the OLE DB (ADO) dialog box opens asking you to choose an OLE DB provider. Choose Microsoft OLE DB Data Provider for SQL Server and click Next. You are requested to enter connection information. For this page, type (local) for the server, check Integrated Security, and type Northwind for the database. Click Finish. Your Available Data Sources will now indicate (Local) under the OLE DB (ADO) node and Northwind under the local connection. 4. Expand the tree under Northwind to get to the first DBO, and then expand Views. You will see the views listed, including the Invoices view. Highlight the Invoices view and click Insert Table. The view is displayed in the Tables in Report list (see Figure 10.17). Click Next. Figure 10.17. The Report Expert considers both tables and views as tables. 5. From the Fields tab, add the following fields: Invoices.CustomerName, Invoices.OrderID, Invoices.UnitPrice, and Invoices.Quantity. 6. Click on the Formula button. Type TotalPricePerUnit. Crystal Reports puts the @ before the formula name from now on. You are then brought into the Formula Editor, shown back on Figure 10.16. 7. Type the formula {Invoices.UnitPrice}*{Invoices.Quantity}; then press Ctrl+S to Page 425 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html save and close the dialog box. An alternative is to double-click on the fields you want to include. 8. 9. Now select the formula you just created, and add it to the fields to include. You can now go on to select how you want the columns totaled and what you want the style of the report to be. Click Finish when you are done. Comments The Formula Editor works similarly to other builders, and it's pretty straightforward to use. Formulas are another step to making sure you can give your clients the full-featured reports they want. [ Team LiB ] Page 426 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.4 Select Whether the Report Will Be Displayed, Printed, or Exported Using Visual Basic .NET Code I know I can use the Crystal Report Viewer to print and export my reports, but I want to be able to have control over that, and maybe not even include the Viewer in some cases. Technique For this How-To, you will use a Tab control to display the three options for the user: Print, Export, and View (see Figure 10.18). Figure 10.18. You have flexibility when it comes to letting your users work with reports. The first tab, Print, allows you to specify the number of copies to print, along with the starting and ending pages. Printing Using the Report Document This page will use the PrintToPrinter method shown here: Me.rdHowTo10_4.PrintToPrinter(Me.txtNumOfCopies.Text, False, Me.txtStartPage.Text, Me.txtEndPage.Text) The PrintOptions object, found on the ReportDocument, is very useful. The PrintOptions object has the following properties: PaperOrientation, PaperSize, PaperSource, PrinterDuplex, and PrinterName. You can set these properties either at design time using the property sheet, or at runtime using code. Exporting Using the Report Document When you're exporting using the Report document, you will be using the ExportOptions object. The ExportOptions object is made up of four other properties/objects: Page 427 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html  DestinationOptions. This is made up of one of three possible objects: DiskFileDestinationOptions, ExchangeFolderDestinationOptions, or MicrosoftMailDestinationOptions. ExportDestinationType. This gets or sets the export destination type. This will be DiskFile, ExchangeFolder, MicrosoftMail, or NoDestinationType. ExportFormatType. This gets or sets the export format type. It can be one of the following: Excel, HTML32, HTML40, NoFormat, PortableDocFormat, RichText, or WordForWindows. FormatOptions. This gets or sets the FormatOptions. It can be ExcelFormatOptions, HTMLFormatOptions, or PdfRtfWordFormatOptions.    To execute the export, you use the Export method of the DocumentReport object. You can see the page for exporting in Figure 10.19. Figure 10.19. You can control which types of files you want the user to export. The View tab uses a CrystalReportViewer object on the tab page. Steps Open and run the Visual Basic .NET Chapter 10 solution. Click on the button labeled How-To 10.4. Clicking on the tabs, you can see the three options you have to work with. Clicking on the Print button prints your report to the default printer. When you go to the Export tab and click the Export button, a message appears stating that the data has been exported. The last tab, View, displays the report in a Viewer. 1. 2. Create a Windows Form. Then place a Tab control on your form. Add pages for Print, Export, and View, using the TabPages property of the Tab control. Page 428 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Drag on a ReportDocument object, and set it to point to the report you created in How-To 10.1. Then name your report document rdHowTo10_4. 4. Place the controls shown in Figure 10.18 and 10.19 onto the tab page with the properties set forth in Table 10.3. Table 10.3. Controls for the Tab Pages Tab Page Object Property Setting Print Label Label Label TextBox Text Text Text Name Text # of Copies Start Page End Page txtNumOfCopies 1 txtStartPage 0 txtEndPage 0 btnPrint Export Type File Path txtExportFilePath File Name txtExportFileName lstExportType btnExport Top, Bottom, Left, Right TextBox Name Text TextBox Name Text Button Export Label Label TextBox Label TextBox ListBox Button View Name Text Text Name Text Name Name Text CrystalReportViewer Anchor ReportSource rdHowTo10_4 Page 429 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 5. 6. Type Excel and Word Document into the Items collection of lstExportType. Add the code in Listing 10.1 to the Click event of btnPrint. Listing 10.1 frmHowTo10_4.vb: Printing the Report Private Sub btnPrint_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnPrint.Click Dim po As PrintDialog Me.rdHowTo10_4.PrintToPrinter(Me.txtNumOfCopies.Text, False, _ Me.txtStartPage.Text, Me.txtEndPage.Text) End Sub 7. Add the code in Listing 10.2 to the Click event of btnExport. This code tests the value of lstExportType and assigns the appropriate ExportFormatType and file extension (strExt). The DiskFileDestinationOptions information is supplied, and the Export method is called to complete the export. Listing 10.2 frmHowTo10_4.vb: Exporting the Report Private Sub btnExport_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnExport.Click Dim strExt As String Try With Me.rdHowTo10_4.ExportOptions Select Case lstExportType.SelectedItem Case "Excel" .ExportFormatType = _ CrystalDecisions.[Shared].ExportFormatType.Excel strExt = ".xls" Case "Word Document" .ExportFormatType = __ CrystalDecisions.[Shared].ExportFormatType.WordForWindows strExt = ".Doc" End Select .ExportDestinationType = _ CrystalDecisions.[Shared].ExportDestinationType.DiskFile Dim ddo As New CrystalDecisions.Shared.DiskFileDestinationOptions() ddo.DiskFileName = Me.txtExportFilePath.Text & _ Page 430 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Me.txtExportFileName.Text & strExt .DestinationOptions = ddo End With Me.rdHowTo10_4.Export() MessageBox.Show("Report Exported!") Catch excp As Exception MessageBox.Show(excp.Message) End Try End Sub Comments As you can see, very little code is needed to provide a great deal of functionality. Sometimes when you're using tools such as the Viewer in a tabbed form, the tab pages can become cluttered. If you want to limit the power of the Viewer or make it more streamlined, you can turn off the toolbar and group display by setting DisplayToolbar and DisplayGroupTree to False on the CrystalReportViewer. [ Team LiB ] Page 431 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.5 Determine Which Records Will Be Printed at Runtime I can use the Select Wizard to help limit the records that I want to be displayed on the report, but that doesn't do my users much good when they want control over that when the application is running. How do I determine which records are displayed at runtime? Technique To handle this, use the SelectionFormula of the CrystalReportsViewer. When you use the SelectionFormula to limit your records, you are taking advantage of Crystal Report's Database optimization. This means that the query you generated by setting the SelectionFormula and the original record source for the report will be "pushed down" to the server. SelectionFormula Syntax You can see the syntax for the SelectionFormula here: CrystalReportViewer1.SelectionFormula = "{Table.Field} = value" Value can be various data types, delimited by the usual delimiters, such as single quotes for strings. For the new criteria to take effect, after setting the SelectionFormula, you need to call the RefreshReport method of the CrystalReportViewer. Setting Report Options To get optimal use out of the SelectionFormula, you need to keep some things in mind. You need to set an option of the report that will ensure it uses the record source indexes if possible. To do this, you right-click on the report and choose Report Options from the Report menu. On the Options page, make sure to check Use Indexes or Server for Speed (see Figure 10.20). Figure 10.20. Customize your report by using the Report Options dialog box. Page 432 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Another tip is to make sure you use indexed fields whenever possible. Tip Take some time now to check out some of the other report options. Steps Open and run the Visual Basic .NET Chapter 10 solution. Click on the button labeled How-To 10.5. You can select Regions from the ComboBox control on the top of the form; the report then reflects the selection (see Figure 10.21). 1. 2. Create a Windows Form. Drag on a ReportDocument object, and set it to point to the report you created in How-To 10.1. Then name your report document rdHowTo10_5. Place the controls shown in Figure 10.21 onto the form with the properties set in Table 10.4. 3. Table 10.4. Label, Combo, and CrystalReportViewer Controls and Their Property Settings Object Property Setting Label Text Pick a Region Page 433 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ComboBox CrystalReportViewer Name Name Anchor cboRegions cvwRegionReport Top, Bottom, Right, Left rdHowTo10_5 ReportSource 4. Add the code in Listing 10.3 into the Load event of the form. This code performs a DISTINCT SQL statement to get all of the regions used in the Customers table. The data adapter then fills dtRegions. Before binding dtRegions to the combo box cboRegions, a new data row is added to allow the user to specify All Regions. Listing 10.3 frmHowTo10_5.vb: Populating the Selection Combo Box Private Sub frmHowTo10_5_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim odaRegions As New _ OleDb.OleDbDataAdapter("SELECT DISTINCT Region FROM Customers", BuildCnnStr("(local)", "Northwind")) Dim dtRegions As New DataTable() odaRegions.Fill(dtRegions) '-- Add the All Regions feature Dim drAll As DataRow = dtRegions.NewRow drAll(0) = "<< ALL Regions >>" dtRegions.Rows.Add(drAll) With Me.cboRegions .DataSource = dtRegions .ValueMember = "Region" End With End Sub Note As with a number of other examples, the BuildCnnStr() function has been created in the modGeneralRoutines module to create a connection string. 5. Add the report in Listing 10.4 to the SelectedIndexChanged event of cboRegions. One of the values that is in the Region field of the Customer table is NULL. This code tests for that first by testing this: Page 434 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. 7. Me.cboRegions.SelectedItem(0) Is System.DBNull.Value If the selected item is NULL, which uses System.DBNull.Value for the comparison, then the value of IsNull({Customers.Region}) is stored in the SelectionFormula. If All Reasons was chosen, then the SelectFormula is set to the empty string so that all items are chosen. Otherwise, the Customers.Region field is compared to the literal region, supplied by cboRegions. The last task performed is refreshing the report. Listing 10.4 frmHowTo10_5.vb: Setting the SelectionFormula Property Private Sub cboRegions_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cboRegions.SelectedIndexChanged With Me.cvwRegionReport If Me.cboRegions.SelectedItem(0) Is System.DBNull.Value Then .SelectionFormula = "IsNull({Customers.Region})" ElseIf Me.cboRegions.SelectedItem(0) = "<< ALL Regions >>" Then .SelectionFormula = "" Else .SelectionFormula = "{Customers.Region} = '" & _ Me.cboRegions.SelectedItem(0) & "'" End If .RefreshReport() End With End Sub Figure 10.21. You can let your user control how much data he sees in the report. Page 435 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments You can limit the selection displayed on the report in other ways, too. This How-To presented just one way to get you started. Letting your user choose the records gives him the perceived control he wants. [ Team LiB ] Page 436 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.6 Print Labels and Control the Order in Which Records Will Be Printed I need to be able to have my application print labels for my user's customer list. Sometimes my user needs to print labels based on the postal code, and other times he needs to print labels alphabetically by company name. How do I do this at runtime? Technique To accomplish this task, you will use the Report Expert to create mailing labels. You then will use code to update the sort order at run-time. Creating the Mailing Labels To create the mailing labels, you create a new report and choose Mailing Labels for the type of Expert to use. You then fill in the Data tab, which uses Customers for the table, and grab the following fields: CompanyName, ContactName, ContactTitle, Address, Formula (@CityRegionPostal= { Customers.City} & ", " & { Customers.Region} & " "& { Customers.PostalCode} ), and Country. You can see how this will look in Figure 10.22. Figure 10.22. Fields that will be used in the mailing labels. After clicking Next, you are taken to the tab that allows you to choose which type of label you want to use. For this How-To, the Address (Avery 5160) is used. Everything else on the page is chosen for you (see Figure 10.23). Figure 10.23. You have control over how your labels look. Page 437 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Now you can just click Finish, and the final mailing label report is created (see Figure 10.24). Figure 10.24. These appear in nice mailing label format when they're viewed on a form. Controlling the Sort Order at Runtime To control the sort order at runtime, you use properties, methods, and objects of the ReportDocument. Specifically, you traverse down the ReportDocument object model, looking at the Database object and moving down to the Fields level. You do this first when you're loading up a combo box with fields that are being used in the report. The following lines of code accomplish Page 438 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html this: For Each dfCurr In Me.rdHowTo10_6.Database.Tables.Item(0).Fields Me.cboSortFields.Items.Add(dfCurr.Name) Next dfCurr is a FieldDefinition object, which means it is a field definition for a given field in the report. The other object that will be used from the Report definition is the DataDefinition object, and the SortFields collection off of that. You can see this with the following lines of code, which set the sorting for the report based on which field they chose in the combo box: With Me.rdHowTo10_6 dfSort = .Database.Tables.Item(0).Fields.Item(Me.cboSortFields.Text) .DataDefinition.SortFields.Item(0).Field = dfSort End With Me.cvwCustomerLabels.RefreshReport() You can see once again that the RefreshReport method is called after updating the SortFields item. Steps Open and run the Visual Basic .NET Chapter 10 solution. Click on the button labeled How-To 10.6. You can select fields from the ComboBox control on the top of the form, and the report reflects the sorting selection (see Figure 10.25). 1. 2. Create a new Crystal Report. Choose Mail Labels for the Report Expert to use. Fill in the Data tab, choosing Northwind for the database, and Customers for the table to use. 3. Choose the fields as specified by the "Technique" section: CompanyName, ContactName, ContactTitle, Address, Formula (@CityRegionPostal= { Customers.City} & ", " & { Customers.Region} & " " & { Customers.PostalCode} ), and Country. 4. 5. 6. On the Label tab, choose Address (Avery 5160) for the mailing label type. Click Finish. Create a Windows Form. Drag on a ReportDocument object, and set it to point to the report you created in the past few steps. Then name your report document rdHowTo10_6. 7. Place the controls shown in Figure 10.22 onto the form with the properties set forth in Table 10.5. Table 10.5. Label, Combo, and CrystalReportViewer Controls and Their Property Settings Object Property Setting Label ComboBox Text Name Pick a Field to Sort cboSortFields Page 439 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CrystalReportViewer Name Anchor cvwCustomerLabels Top, Bottom, Right, Left rdHowTo10_6 ReportSource 8. Add the code in Listing 10.5 to the Load event of the form. As described in the "Technique" section, this code iterates through each of the fields in the table that the report is based on and loads them into the Items collection of cboSortFields. Listing 10.5 frmHowTo10_5.vb: Populating the Selection Combo Box Private Sub frmHowTo10_6_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim dfCurr As CrystalDecisions.CrystalReports.Engine.FieldDefinition ' ' Iterate through the table that the report is based on and load the fields into a combo box. For Each dfCurr In Me.rdHowTo10_6.Database.Tables.Item(0).Fields Me.cboSortFields.Items.Add(dfCurr.Name) Next End Sub 9. Add the code in Listing 10.6 to the SelectedIndexChanged event of cboSortFields. This code takes the selected item from cboSortFields and locates it in the table that the report is based on. The DataDefinition object is retrieved and then assigned to the first items in the SortFields collection. Last, the report is redisplayed using the RefreshReport method. Listing 10.6 frmHowTo10_5.vb: Populating the Selection Combo Box Private Sub cboSortFields_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles cboSortFields.SelectedIndexChanged Dim dfSort As CrystalDecisions.CrystalReports.Engine.FieldDefinition ' ' Use the field that is picked in the combo box in the SortFields collection. With Me.rdHowTo10_6 dfSort = .Database.Tables.Item(0).Fields.Item(Me.cboSortFields.Text) .DataDefinition.SortFields.Item(0).Field = dfSort End With Me.cvwCustomerLabels.RefreshReport() End Sub Page 440 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 10.25. Let your user sort the mailing labels as needed. Comments If you have more than one field you want to sort on, then you could use the same technique, just adding code such as this: dfSort = .Database.Tables.Item(0).Fields.Item(Me.cboSortFields2.Text) .DataDefinition.SortFields.Item(1).Field = dfSort The 0 is replaced by 1, and you have another combo box from which you must pick the second sort field. [ Team LiB ] Page 441 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 10.7 Create an Onscreen Report That Contains Hyperlinks My user has a text field in his Customers table that is actually customers' Web sites. Users want to be able to access the site as a hyperlink on an onscreen report. How can I use Crystal Report to create a report that uses hyperlinks? Technique For this How-To, you won't be doing coding. You'll just adjust the formatting of a report field to tell it that it needs to treat the field like a hyperlink. Before doing this, you need to modify Northwind. Adding a Web Site Field to Northwind To accomplish this, you open the Northwind database in the Server Explorer. You then add a field called Website to the Customers table, with the Data Type of nchar and a size of 50. You then modify the first two records in the Customers table so that the Website field contains www.appsplus.com and www.microsoft.com respectively, as shown in Figure 10.26. Figure 10.26. These will be displayed as hyperlinks on the new report you will create. Now you are ready to create the report. Telling the Report That a Field Is a Hyperlink You create a simple report that is based off the Customers table and contains the fields CompanyName, ContactName, and Website. Then you right-click on the Website field in the report and choose Format. The Format dialog box opens, where you can click on the Hyperlink tab. For the hyperlink type, you should choose Current field value (see Figure 10.27). Figure 10.27. These are the options that you can have for hyperlink actions. Page 442 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Now that you have told the field to act like a hyperlink, you need to have it look like one. To perform this task, you set the following properties:    BorderColor. This is set to RoyalBlue to give it the color of a hyperlink. BottomLineStyle. This is set to crLSSingleLine. EnableTightHorizontal. This is set to True so that it doesn't highlight the full length of the field just to the text. That's it! When you display this in a Viewer, as shown in Figure 10.28, you can click on the Website field, and the Viewer will bring you to the Web site you chose. Figure 10.28. This is a real-time hyperlink. Page 443 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Steps Open and run the Visual Basic .NET Chapter 10 solution. Click on the button labeled How-To 10.7. You can click on the hyperlinks, displayed for the Web site, to go to the Web site. 1. Modify Northwind as described in the "Technique" section, adding the Website field to the Customers table. 2. 3. Create a new Crystal Report. Choose Standard for the Report Expert to use. Fill in the Data tab, choosing Northwind for the database, and Customers for the table to use. 4. Choose the fields as specified by the "Technique" section: CompanyName, ContactName, and Website. Click Finish. 5. With the report open in Design mode, right-click on the Website field in the Details section, and choose Format. 6. Make the modifications to the format of the field as described in the "Technique" section, setting the hyperlink type. Then click OK. 7. Make the rest of the format changes as described, setting the BorderColor, BottomLineStyle, and EnableTightHorizontal. 8. 9. Create a Windows Form. Drag on a ReportDocument object, and set it to point to the report you created in the past few steps. Then name your report document rdHowTo10_7. 10. Place a CrystalReportViewer on the form, setting the Anchor property to Top, Bottom, Right, Left and the ReportSource property to rdHowTo10_7. Comments Now when you run the report, you get your hyperlinks. You could have performed additional tasks with hyperlinks, such as using the report for reviewing those you want to email, and having the Page 444 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html field be clickable that way. [ Team LiB ] Page 445 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 11. Managing SQL Server Security In this chapter you will               Create Windows NT/2000 users Create Windows NT/2000 groups Establish a Windows NT/2000 authentication mode Establish mixed-mode authentication Create a standard login Create a Windows NT/2000 login Use a fixed server role Create a database user account Use statement permissions Use object permissions Use fixed database roles Create custom database roles Create application roles Set permission states on tables This chapter discusses the SQL erver security scheme and explains the options available to you as a Visual Basic developer. It starts by discussing authentication modes and then moves on to the various permissions you can set on SQL Server objects. SQL Server supports a layered security system. From bottom to top, these layers add to the overall protection of the database objects and the data they contain. Keep in mind how SQL Server works. SQL Server is an engine that maintains an environment for database objects and data. Through this environment, SQL Server provides services for searching and sorting data, adding or updating records, and performing other data-oriented tasks. If you look at SQL Server as a multilayered or multidimensional entity, the role played by each of the security layers becomes clear. Each layer and each data-management task has its own set of rules that must be followed. For instance, simply entering the SQL Server environment does not automatically grant access to database. Similarly, the ability to read data stored in the table does not imply the ability to add new records or change existing data. Security is an important issue, and a certain amount of complexity is the price for the high degree of data security and integrity that SQL Server provides. [ Team LiB ] Page 446 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.1 Create Windows NT/2000 Users Although it might seem odd to begin a discussion of SQL Server security by describing the process of adding users to Windows NT/2000, it's important to note that SQL Server security is tightly integrated with the Windows security registry. SQL Server administrators are pleased with the fact that SQL Server automatically recognizes Windows NT and Windows 2000 users, saving a considerable amount of administrative time. This section explains the process of adding new users to Windows 2000. The next section describes how to add functional groups to Windows. Although these sections deal with Windows 2000, the process is nearly identical for Windows NT. Windows must recognize users before they can log in to the network and use the computer's resources. You need to add a number of users to the Windows user registry. How do you make sure that all users are required to provide a network password before they can access the network? Technique Windows users cannot be added to the system from within SQL Server's Enterprise Manager. You'll have to use the Windows Control Panel applets to add new users and groups. Note The settings you choose on this page of the Add New User dialog box do not affect the SQL Server settings you establish for the user. The settings you see in Figure 11.4 relate only to Windows and not SQL Server or the database data. Figure 11.4. Most of your users will be set up as Standard Users with no special capabilities. Note Page 447 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html The first step in the following example is different on Windows NT 4.0 and Windows 2000. For Windows NT 4.0, you go to Start, Programs, Administrative Tools, User Manager. For Windows 2000, you go to Start, Settings, Control Panel, Administrative Tools, Computer Management; then you right-click on Users. Also, you must have administrative rights on the computer to add users to it. Steps SQL Server security is tightly integrated with Windows NT/2000 security. SQL Server recognizes the users and groups that are added to a Windows NT or Windows 2000 domain. The first step toward security for SQL Server, of course, is to add users to the computer system. This section describes how to add individual users to a Windows NT or Windows 2000 computer. SQL Server consults the registered users on the computer when you create logins, discussed in How-To 11.5. The user's name and description are accessible from the SQL Server security dialog boxes and help you recognize each user as you create SQL Server logins and establish security profiles. 1. Choose Start, Settings, Control Panel and open the Users and Passwords Control Panel applet. 2. Make sure the check box labeled Users Must Enter a User Name and Password to Use This Computer is checked, as shown in Figure 11.1. Figure 11.1. This dialog box allows you to add new Windows users and manage their group membership. Page 448 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. 4. Click the Add button to open the Add New User dialog box. Fill in the username, the full name of the user, and a description for the new user, as shown in Figure 11.2. Figure 11.2. The information you enter in the Add New User dialog box will be accessible from the SQL Server security dialog boxes. 5. After you have provided the required user information, click the Next button to move to the Page 449 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html second page of the dialog box. 6. Enter the new user's initial password into the password text box. Then type the password a second time in the Confirm Password text box (see Figure 11.3). When you're ready, click the Next button. Figure 11.3. Specify the user's initial password in this dialog box. The user will be able to change it later, if necessary. 7. On the third page of the Add New User dialog box (see Figure 11.4), you specify the type of Windows access you want to provide this user. Although this information is not directly related to SQL Server, most often you will want to leave this setting at its default to Standard User. In most cases, you do not want to provide a user with more access than necessary. Note The settings you choose on this page of the Add New User dialog box do not affect the SQL Server settings you establish for the user. The settings you see in Figure 11.4 relate only to Windows and not SQL Server or the database data. 8. When all settings are complete, click the Finish button to add the new user to the collection of users on your computer. Comments SQL Server's integration with Windows security is one of the major reasons that SQL Server has grown in popularity. Its ability to cooperate with Windows when authenticating users and providing database services dramatically reduces the administrative burden that is normally associated with server database engines. Caution Page 450 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Be sure to remove your temporary users after you are finished with them so that you do leave them hanging around. [ Team LiB ] Page 451 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.2 Create Windows NT/2000 Groups Windows 2000 recognizes individual users as well as functional groups. You can, for instance, set up a group called Marketing or Sales, and then add new users to the computer. In addition, each user can be added to any of the groups that you've created. Therefore, you might have a marketing manager who belongs to both the Marketing and Management groups. One advantage of using groups is that SQL Server automatically recognizes the registered Windows users. SQL Server is tightly integrated with Windows security, and you are able to use this integration as you set up SQL Server security. This means, for instance, that you can provide the marketing group with access to tables and stored procedures that are related to marketing data, yet deny the salespeople access to those same tables and procedures. The marketing manager mentioned earlier in this chapter is able to work with marketing and management data (such as employee human resources data). Because you are treating multiple users as a single group, the administrative effort is considerably less than if you had gone to the trouble of providing access to each individual user. As you'll soon see, treating users as members of groups greatly simplifies the security administration task. Handling individual users is a real hassle. In large installations with hundreds of users, you spend inordinate amounts of time managing SQL Server security on a user-by-user basis. Instead, you'd like to use Windows groups to add groups of users to the database. Technique Use the Administrative Tools in the Control Panel to create groups and add the users you've created to those groups. Steps Most often, users are arranged into logical groupings. For instance, all the people in the marketing department are likely to belong to a group named Marketing. Similarly, managers probably belong to a Management group. In this section, you'll learn how to specify the groups on your computer and add the user accounts you've created to those groups. Later, as users log in to SQL Server, they'll be able to log in as themselves or as a group. Although this might sound a bit strange, to SQL Server, an individual user is the same as a group of users. All that SQL Server sees is an identifier ("TonyS" or "Marketing"), and it matches that identity with a Windows network login. 1. 2. Choose Start, Settings, Control Panel to open the Control Panel. Double-click on the Administrative Tools applet to access the Windows 2000 administration options. 3. Select the security settings by double-clicking on the Computer Management option and opening the dialog box you see in Figure 11.5. Figure 11.5. Each Windows group usually contains a number of individual users. Page 452 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Use the + next to Local Users and Groups to reveal the Users and Groups icons. Right-click on the Groups icon and select New Group from the shortcut menu that appears. (Alternatively, use the New Group menu item under the Action menu). You'll see the New Group dialog box as shown in Figure 11.6. Provide a name for the new group, such as Shift Supervisors, in the Group Name text box at the top of the New Group dialog box. Figure 11.6. Fill in the Group name and Description text boxes. You'll add users to this Windows group in a minute. 5. Provide a verbose description for the group in the Description text box. Near the bottom left of the New Group dialog box, you'll see two buttons labeled Add and Page 453 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Check Names (see Figure 11.7). Click on the Add button to open the list of all users who are registered on this computer. Figure 11.7. This list shows all the users within the local Windows domain. The red X indicates disabled Windows accounts. 6. The top half of the Select Users or Groups dialog box contains an alphabetically sorted list of all the users in the local domain. Use the scrollbar if necessary to locate the user you want to add to the group. Select the user and use the Add button (or double-click on the user) to add the user to the group. As users are added to the group, their names appear in the lower half of the Select Users or Groups dialog box. When you have completed the selection process, click the OK button. You'll be returned to the New Group dialog box. You should see the users you've added to the group displayed in the list at the middle of the dialog box. 7. When you're finished adding groups to the computer, click the Close button to dismiss the New Group dialog box. Comments Normally, as a database developer, you won't be creating Windows 2000 groups. However, in many small environments, developers are required to take on more than a single role. Also, you might find it useful to create a group login just for the applications you write. [ Team LiB ] Page 454 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.3 Establish a Windows NT/2000 Authentication Mode SQL Server is a much more complex database engine than desktop systems such as Jet. SQL Server is a true server engine; it provides access to multiple databases or even hundreds of users simultaneously. Furthermore, unlike Jet, which is tightly bound into Microsoft Access, SQL Server exists as a separate entity on a computer, which most often is located across a network from the user's desktop computer. A building that contains multiple offices is a good analogy for the way that SQL Server is built. The building is secured, and each office within the building is locked. Carrying the analogy further, each office contains locked desk drawers and filing cabinets. A person who wants to use information in one of those file cabinets must enter the building, gain entrance to a locked office, and have a key or other permission to open a locked file cabinet. SQL Server requires each user to be authenticated before it permits the user to open a database. Authentication is somewhat like having to show an employee ID card to a guard at the front door of a building. Without proper credentials, you don't get into the building. Similarly, you don't get "into" SQL Server unless you have been properly authenticated. SQL Server supports two different authentication modes:  Windows NT/2000 authentication. This mode means that SQL Server explicitly trusts Windows to authenticate the user. Anyone who has a valid Windows user ID and password is allowed to access SQL Server. This is known as a trusted connection because SQL Server trusts Windows to allow only qualified people into the computer system and onto SQL Server. Windows NT/2000 Authentication works only with Windows NT or Windows 2000, and it has the distinct advantage of being quite simple to administer. Furthermore, the Windows NT/2000 security provides for expiration and other controls over password usage. In fact, SQL Server even recognizes the user's membership in Windows security groups.  SQL Server and Windows NT/2000 authentication. Using this mode means that both SQL Server and Windows are involved in authenticating the user. The user is not able to access SQL Server unless both Windows and SQL Server are able to verify the user's identity and password. SQL Server and Windows NT/2000 Authentication mode is often referred to as mixed-mode authentication. The selected authentication mode simply directs SQL Server where to look for the user's credentials. In other words, authentication is performed by SQL Server, and describes how SQL Server verifies the user's identity. You've decided that mixed-mode authentication is too much work, and users are likely to forget either their Windows password or their SQL Server password. In fact, some users have resorted to writing down their passwords on sticky notes attached to their computer monitors. Obviously, this creates a security risk. You'd like to make it as easy as possible for users to get into SQL Server so that they can use the databases you've created for them. Technique Enterprise Manager includes all the dialog boxes that are required to set SQL Server's authentication mode. Changing the authentication mode takes only a few moments, and it affects all databases that SQL Server manages. Steps Page 455 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SQL Server takes a layered approach to securing the data in its tables. These layers include authentication whereby a user is identified by username and password and permissions on the objects (such as tables and views) stored in the database. As a developer or SQL Server administrator, you must choose which authentication mode your users use to access SQL Server. In Windows NT/2000 authentication mode, any user who is able to log in to Windows is able to access SQL Server.Windows NT/2000 Authentication mode is the easiest possible way for users to access SQL Server. As long as a user is an authorized user of Windows NT or Windows 2000, he'll be able to get into SQL Server. No extra password or user identity is required for admittance to SQL Server, which reduces the risk that a user will store a password in an insecure place. 1. Choose Start, Programs, Microsoft SQL Server, Enterprise Manager to open Enterprise Manager. 2. 3. Open the SQL Server group and right-click on the server you want to configure. Select Properties from the context menu that appears. (The Properties command should be highlighted in the context menu.) 4. 5. Select the Security tab. Select Windows Only from the authentication options near the top of the Security tab, as shown in Figure 11.8. Figure 11.8. Select Windows Only from the Authentication options in the Properties dialog box. Page 456 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. Click the OK button to complete the process and close the Properties dialog box. Comments Windows NT/2000 authentication simply means that SQL Server trusts Windows to authenticate users. Windows determines the user's identity and group member as the user logs into his computer. From that point on, the user has full access to SQL Server installations that are configured to accept Windows NT/2000 authentication. The main problem with Windows NT/2000 authentication mode is that it doesn't work with Windows 95, Windows 98, or non-Windows computers. Anyone who is connected to your network from a Unix or Apple Macintosh computer will not be able to use Windows NT/2000 authentication. You'll have to set up mixed-mode authentication for these users. Another problem with Windows NT/2000 authentication is that in many environments, more than one person shares the same computer. For instance, consider a point-of-sale terminal in a retail environment or an industrial computer located on a factory floor. Multiple users typically access these computers, and because SQL Server admits anyone logged into the computer, SQL Server can't distinguish between individual users. This can be a problem in environments where some users must be prevented from viewing certain tables or accessing certain data within a database. Note Although this discussion makes it sound as though SQL Server is passive when working under Windows NT/2000 authentication mode, there is more to the story than discussed here. SQL Sever actually calls Windows Page 457 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html NT or 2000 to retrieve the user's Windows login identity and group membership. If the user's group membership changes while he is logged into Windows, SQL Server sees the changes as soon as the user tries to access SQL Server. [ Team LiB ] Page 458 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.4 Establish Mixed-Mode Authentication The alternative to Windows NT/2000 authentication is mixed-mode authentication. In this arrangement, a user is first authenticated by Windows, and is again authenticated by SQL Server as he tries to access a database. Mixed-mode is the only authentication for users who are working on Windows 98 computers or Macintoshes, Unix, and other non-Windows machines. My network includes a number of non-Windows computers, such as Apple Macintoshes. In addition, several users are working from Windows 98 computers. I discovered that these users are unable to access the SQL Server databases that I created. It appears that mixed-mode authentication might be the only way for these users to access SQL Server. Technique Again, Enterprise Manager provides the dialog boxes that are necessary to set mixed-mode authentication. After mixed-mode is set, users must first log in to Windows (or, at least, access the SQL Server machine from a Windows network) and then provide a username and password to SQL Server before using a database. Steps In mixed-mode authentication, the user first logs into Microsoft Windows and then into SQL Server. At each step, the user's credentials are authenticated. Mixed-mode authentication means that SQL Server keeps a record of users who are allowed to log in to SQL Server. It matches their password with the password that is stored with their user record. SQL Server stores the user's login information in a system table named syslogins in the master database. This table includes an encrypted security ID (SID) and the user's encrypted password. The other information that is stored in the syslogins table is discussed in the next two sections. 1. 2. 3. Use Start, Programs, Microsoft SQL Server, Enterprise Manager to open Enterprise Manager. Open the SQL Server group and right-click on the server you want to configure. Select Properties from the context menu that appears. (The Properties command should be highlighted in the context menu.) 4. 5. Select the Security tab. Select SQL Server and Windows (for Windows 2000 and NT, SQL Server and Windows NT is displayed) from the authentication options near the top of the Security tab (see Figure 11.9 ). Figure 11.9. Setting mixed-mode authentication is similar to setting Windows NT/2000 authentication. Page 459 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 6. Click the OK button to complete the process and close the Properties dialog box. Comments Although it might sound bothersome to provide two passwords before accessing SQL Server, most often the SQL Server password is provided by the front-end application with which the user is working. Users rarely, if ever, actually open Enterprise Manager or Query Analyzer and directly access the data in SQL Server databases. Instead, they'll use front-end applications that are written in Visual Basic, Access, or another database tool. Most often, the user opens the application and the application passes the user's identity and password to SQL Server as the database connection is made. Although mixed-mode authentication might be more of a hassle to your users, it results in considerably better security for your database. Just because a user is able to access your network by using mixed-mode authentication does not mean that he is able to access SQL Server. The paradox is that some users might write down their network or SQL Server password in a location where unauthorized people can see it. However, the same could be said of any security system, and such security breaches must always be avoided. [ Team LiB ] Page 460 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.5 Create a Standard Login The previous sections discussed authentication, which is nothing more than the process of how SQL Server recognizes users. Authentication is much like the method used to allow people to get through the front door of an office building. The building may use a simple key card lock, or the company may use a guard to check IDs as people enter the building. In either case, the person's identity is verified before entry is granted. Earlier in this chapter, you read about the Windows NT/2000 authentication process. When using Windows NT/2000 authentication, a trusted connection is established between SQL Server and the user's computer. However, trusted connections cannot be established between SQL Server and Windows 95 or 98 machines, or Apple Macintoshes, Unix, or other non-Windows computers. After you determine which type of SQL Server authentication to use, you must establish a login for each of your users. A login is how the user gains access to SQL Server after the authentication process. A login is how SQL Server establishes your identity within SQL Server and how SQL Server determines your permissions to use data and database objects. You can choose from two different types of logins:   Standard SQL Server login Windows NT/2000 login When no trusted connection exists between the user's computer in SQL Server, SQL Server has no way of obtaining the user's identity from the operating system. Therefore, mixed mode application must be used to validate the user, and a standard SQL Server login must be created so that SQL Server recognizes the user. The login you establish only provides access to SQL Server; it does not provide access to databases, data, or database objects. Not every SQL Server user will be working with Windows NT and Windows 2000. Some users might be connected to the network from a Unix or Macintosh machine. These users will not be able to use a Windows NT/2000 login, and you have to establish a standard SQL Server login for them. This is also true of users who are working under Windows 95 and Windows 98. Technique SQL Server Enterprise Manager provides the dialog boxes that are necessary to set up standard logins. This section describes these dialog boxes and how to provide the information necessary to create standard SQL Server logins. Creating a login can affect only one person or a group of people; it does not affect how SQL Server operates. Steps If the user is connecting to SQL Server from a Unix, Macintosh, or other non-Windows machine, or if the user is running Windows 98, you must create a standard login for him. SQL Server maintains a record of each person's logins and a table named sysxlogins in the master database. This table stores the user's login ID, encrypted password, and other critical information. If you'd like to view the data in this table, use the syslogins view in the master database. The syslogins view uses a SQL statement to arrange the data in a more readable format. Page 461 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html As the user logs in, regardless of which authentication mode he uses, his user information is compared against the data that is stored in the syslogins table. As long as the user appears to be valid, SQL Server allows him to try to access tables, stored procedures, and data. 1. 2. Open Enterprise Manager and select your server. Use the plus sign (+) next to your server's name to expand the server's object list. Then expand the security icon. 3. 4. Right-click on the Login icon and select New Login from the shortcut menu. You'll now see the new Login dialog box (see Figure 11.10). Enter the new login name in the Name text box. Figure 11.10. Add new Windows NT/2000 logins with the SQL Server Login Properties dialog box. 5. 6. Select the SQL Server Authentication option button, and enter a password for the login. Select which database this login will normally use from the Database drop-down list in the Default section near the bottom of the New Login dialog box. Comments The SQL Server standard login does not permit you to use the user's NT/2000 identity. Therefore, you cannot take advantage of a user's membership in a Windows group to simplify login creation. You can, however, create a shared login. (CS would be named something like Marketing for accounting practices used by everyone who is a member of that group.) The problem is that everyone within that group will use the same password in login name, which might make security Page 462 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html an issue. [ Team LiB ] Page 463 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.6 Create a Windows NT/2000 Login Any user who is accessing SQL Server from a Windows NT or Windows 2000 computer (but not Windows 98 or ME) can be given a SQL Server Windows NT/2000 login. Although setting up the NT/2000 login is almost the same process as creating a standard login, you have the option of adding the user as any of the following:    An individual user A member of an NT/2000 group A member of the SQL Server built-in group I want to take advantage of the fact that the users on my system have all been assigned to functional groups (such as marketing and sales) in Windows NT or Windows 2000. Because these groups parallel the user's SQL Server activity, I'd like to use each person's network identity as his SQL Server login. Using a person's Windows NT/2000 group saves a lot of administrative time. Rather than creating a custom login for each user, I can assign a login to a Windows NT/2000 group, and SQL Server can recognize any individual as valid who belongs to the group. Technique You first create a Windows 2000 user or group, and then create a SQL Server login for that user or group. Earlier in this chapter, you read how to add users and groups to Windows NT/2000. You'll now use the Windows Enterprise Manager dialog boxes to establish SQL Server logins for those users and groups. Steps If the user is working with Windows NT or 2000, you are able to establish a Windows NT/2000 login identity for him. As you'll see, using a Windows NT/2000 login is less work than using standard logins. When a user logs in to a SQL Server or Windows NT/2000 account, his identity is verified against the account information that Windows manages. SQL Server security is tightly integrated with Windows login information, and SQL Server knows and understands the user's identity. SQL Server recognizes the user's personal identity as well as his Windows group membership. Even if no personal SQL Server login is established for the user, as long as a SQL Server login is established for at least one of the Windows groups to which he belongs, he will be able to access SQL Server. The person's identity and Windows group membership is established as he logs in to Windows. As you'll see later in this chapter, these identities play important roles with regard to object permissions and access to data that SQL Server manages. 1. Open Enterprise Manager and select the Security icon. Open this icon by clicking on the plus sign (+) next to it. 2. Select New Login from the Actions menu, or click on Logins with the right mouse button and select New Login from the context menu. Regardless of which method you use, the SQL Server Login Properties dialog box (see Figure 11.10) opens. Page 464 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Use the button next to the Name text box to display the list of Windows NT/2000 user and group logins that SQL Server recognizes. The list is alphabetically sorted first by groups, and then by users. In Figure 11.11, you see the list scrolled downward to show the last several groups and the first users in the list. Figure 11.11. The Names list includes both groups and users. 4. Select a group or user for the new login. If the user or group does not appear in the list, use the drop-down list at the top of the dialog box shown in Figure 11.11 to select another computer on the network. Comments Establishing a Windows NT/2000 login account is similar to creating a standard SQL Server login. The biggest difference is that SQL Server recognizes the user's Windows identity,including the password and group membership. The user's identity is how SQL Server determines the individual's access to database data and objects. You'll learn about these important permissions in the sections titled A and B later in this chapter. Don't automatically create logins for every Windows NT/2000 group. This would mean that virtually every user has access to SQL Server. You should provide access to SQL Server only to those users with a legitimate need to use the data that is stored in SQL Server, or to people who are established as SQL Server system administrators. [ Team LiB ] Page 465 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.7 Use a Fixed Server Role Managing a server database engine such as SQL Server can be a time-consuming process. Administrative tasks include backing up the data, adding new users, modifying tables and views, and so on. Most SQL Server administrators find it useful from time to time to permit other people to perform these tasks. Assigning other people tasks such as backing up the databases or administering security allows the system administrators to devote more time to other responsibilities. As a system administrator, I am overwhelmed by the administrative tasks that are required to keep several databases operating efficiently. There's too much to do between database administration, adding new users, performing backups, and other tasks. I'd like to be able to allow an assistant to assume some of these responsibilities so that I won't have to be personally involved in performing these tasks. However, I'm not looking forward to assigning various permissions to all of my administrative assistants. For instance, some people are to be designated as security administrators whereas others will be responsible for updating table designs. Technique SQL Server supports the notion of fixed server roles that define certain administrative profiles. Each fixed server role is accompanied by the appropriate permissions to perform the administrative tasks that are associated with the role. Enterprise Manager provides all the dialog boxes that are necessary to assign user accounts to the fixed server roles that SQL Server recognizes. It is important to note that each fixed server role is global within SQL Server. This means, for instance, that the dbcreator fixed server role is able not only to create new databases, but also to make changes to existing databases in SQL Server. SQL Server recognizes eight fixed server roles:  sysadmin. This is the most powerful fixed server role. Members of this role are able to perform all the tasks included with the other roles.  serveradmin. The serveradmin role adjusts the serverwide settings in SQL Server, such as memory usage, authentication mode, and home directories.  setupadmin. This role administers linked servers. A SQL Server installation is able to share SQL Server databases that are located on other computers. The setupadmin group is responsible for creating links to SQL Server installations on other computers.  securityadmin. Members of the securityadmin role add new user and group logins, assign passwords, and perform other security-oriented tasks.    processadmin. This role manages processes that are spawned by SQL Server. dbcreator. Members of this role are responsible for creating and altering databases. diskadmin. The diskadmin role adjusts the disk space that is available for databases, sets the database growth increment (as a percent or in megabytes), and specifies the parameters for the SQL Server log file. Page 466 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html  bulkadmin. SQL Server 2000 includes a number of statements intended to perform bulk inserts to data. Because the BULK INSERT statement can involve considerable amounts of processing time, SQL Server does not allow anyone other than members of the sysadmin and bulkadmin roles to perform this statement. Steps Often, you'll want individual users or groups of users to have database administrative responsibilities. For instance, you might want the accounting group to manage its own login names and passwords. In this case, you'll want to join the users in the accounting group to certain fixed server roles, which are predefined special security groups. Each fixed server role defines a category of administrative tasks, and each member of a fixed server role is able to perform those administrative tasks. SQL Server recognizes members of fixed server roles as people who are authorized to perform these administrative tasks. Each role is accompanied by the appropriate SQL Server permissions that are necessary to perform those tasks. 1. 2. Open Enterprise Manager and expand the Security icon. Click on the Server Roles icon to show the eight fixed server roles in the right pane (see Figure 11.12). Figure 11.12. The Server Roles icon reveals the eight SQL Server fixed server roles. 3. Right-click on any of the fixed server role entries and select Properties from the pop-up menu. Alternatively, select one of the fixed server roles and use the Properties command under the Action menu to open the Server Role Properties dialog box, as shown in Figure 11.13. Figure 11.13. The Server Role Properties dialog box shows you the logins that are added to the selected role. Page 467 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Use the Add button to open the Add Members dialog box (see Figure 11.14). The Add Members dialog box shows only those logins that have not already been added to the role. In Figure 11.14, only TonyS, the Marketing group, and members of the BUILTIN/Administrators group are not members of the securityadmin fixed server role. Figure 11.14. The Add Members dialog box shows you only those logins that have not been added to the selected role. 5. Select the login to add to the selected fixed server role and click the OK button. Comments Membership in a fixed server role does not grant access to a database or data within the databases. Fixed server roles are intended for administrators and assistant administrators and do not automatically grant access to any of the data that SQL Server manages. Database object permissions (discussed later in this chapter in How-To 11.10) are required to gain access to data and database objects. Page 468 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html The special sysadmin role should be reserved for trusted and trained system administrators. Members of this role are able to perform all SQL Server administrative tasks, and those tasks are applicable to all databases that SQL Server manages. Obviously, this can lead to serious problems in the wrong hands. Finally, when you add people to fixed server roles, make sure these people understand the consequences of their actions as system administrators. Because fixed server roles are global within SQL Server, the actions that fixed server role members perform could affect all the databases that SQL Server manages. Incorrectly configuring SQL Server or failing to carefully implement security can have a dramatic negative impact on every database that SQL Server manages. Members of the SQL Server BUILTIN/Administrators group are automatically added to the sysadmin fixed server role. [ Team LiB ] Page 469 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.8 Create a Database User Account The logins that you created in How-To 11.5 or 11.6 provide access to SQL Server, but not to any databases within SQL Server. This is much like giving someone a key to a building, but not providing keys to offices within the building. The fixed server role that you might have specified in How-To 11.7 gives the person rights to perform serverwide administrative tasks such as creating or modifying databases. Using the building analogy, this is something like giving an electrician permission to rewire or modify the electrical service within the building. However, neither of these settings actually grants access to databases within SQL Server. Before a user can access a SQL Server database (somewhat like entering a locked office in the building), he must be provided with the database user account. I have been authenticated and logged into SQL Server and now I need to access data that is stored within a SQL Server database. Without a specific database user account, I am unable to access and use data that SQL Server manages. Technique Enterprise Manager provides the dialog boxes that are necessary to create user accounts in any of its databases. Be sure to add the user to every database that he requires. Otherwise, the user will not be able to use the data, run stored procedures, or otherwise access the database. Steps Simply logging in to SQL Server does not automatically establish a person's database identity. In other words, accessing SQL Server does not mean that SQL Server recognizes the person as a valid database user. This is particularly true when Windows NT/2000 authentication is used. After all, this authentication mode means that anyone who logs in to Windows is able to access the database. SQL Server needs to know exactly who the person is and what data and database objects this person is allowed to access. A SQL Server user account is needed for each user or group of users who is accessing SQL Server. Each SQL Server database maintains an internal registry of user accounts that are permitted into the database. This information is stored in the table named sysusers within the database. The account information travels with the database's MDF file and is backed up when the database is backed up. 1. 2. Open Enterprise Manager and expand the Northwind database icon. Right-click on the Users icon and select New Database User from the shortcut menu that appears. Alternatively, select New Database User from the Action menu. In either case, the Database User Properties dialog box opens (see Figure 11.15). Figure 11.15. You add new user accounts with the Database User Properties dialog box. Page 470 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. Select a user or group login from the drop-down list at the top of the Database User Properties dialog box. If desired, you can provide a different username for the user account. Normally, however, you'll want to avoid complications by using the default username. 4. Click the OK button to commit the new user account. Comments It is important to distinguish between a SQL Server login and a database user account. The SQL Server login simply allows a person to access SQL Server, but it does not provide access to databases. A database user account provides access to one and only one database that SQL Server manages. Each user, therefore, will need an account with each database he intends to use. This is why creating database user accounts for groups of users is much more efficient than adding user accounts for individual users. Database user accounts can be established for individual users as well as groups. The Login name drop-down list in the User Account Properties dialog box contains all the SQL Server logins you have created. The statement earlier that a user without a specific database account is unable to use the database is not entirely correct. SQL Server declines to default user accounts: guest and dbo. The guest account is used whenever a user seeks access to the database in which he has no specific account. Under most situations, the SQL Server system administrator has severely limited the ability of the default user account to access a database within SQL Server. Exactly how this is done is explained in How-To 11.10. The database owner (dbo) account owns all the objects that are created by anyone who is a member of the sysadmin fixed server role. You'll frequently see the dbo account listed as an Page 471 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html object's owner simply because the database construction is most often left up to SQL Server's system administrators. [ Team LiB ] Page 472 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.9 Use Statement Permissions SQL Server databases can become quite large and complex. It is important to control the number and type of objects that are added to a SQL Server database so that its structure contains only those objects that are actually required for the database's operation. If object creation were not controlled, users could build temporary tables, views, stored procedures, and other database objects that would become permanent additions to the database. There's no easy way to tell whether a particular database object is required by some front-end applications, making it difficult to remove these objects. I want to control unwanted and unneeded object proliferation in my databases. Without some kind of control, users might unnecessarily complicate the database's structure by adding unwarranted objects. Technique You will employ statement permissions to permit or disallow users to execute SQL statements that modify the database structure. There are also statement permissions controlling SQL statements that back up the database and its log file. These statements include the following:      CREATE DATABASE. Creates a new database (applicable only in the master database). CREATE DEFAULT. Establishes default values for columns in tables. CREATE FUNCTION. Creates a user-defined function that is saved as a Transact-SQL routine. CREATE PROCEDURE. Creates a stored procedure. CREATE RULE. Adds a rule to a column in a table. A rule specifies the acceptable values for the column.     CREATE TABLE. Creates a new table within the database. CREATE VIEW. Adds a view to the database. BACKUP DATABASE. Backs up the entire database to removable media. BACKUP LOG. Backs up the database's log file to removable media. Although this security task has been discussed only from the perspective of limiting the user's ability to create database objects, statement permissions are also a way to ensure that users who really need to modify the database structure are able to do so. Statement permissions are applied at the database level. There are no global SQL Server statement permissions. Steps Logging in to SQL Server does not mean that a user is actually able to access and use the data and other objects that are stored in SQL Server. Each user account has certain permissions assigned to it that specify the account's ability to use the database and its objects. Statement permissions are one category of database permissions. Statement permissions specify which types of SQL DDL (data definition language) statements a user is allowed to execute against Page 473 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html the database. DLL statements are frequently used to create and modify tables, add indexes to tables, and perform other data structure operations on the database. Statement permissions limit a user's ability to perform operations that could be dangerous to the database. After statement permissions have been established, the user is able to execute object creation statements (such as CREATE TABLE) only if the statements permission has been granted. By default, SQL Server does not grant statement permissions. As the SQL Server system administrator, you should grant these permissions only to users who require object creation ability. 1. 2. Open Enterprise Manager and expand the Northwind database's icon. Right-click on the Northwind database's icon and select Properties from the shortcut menu. This action opens the database's Properties dialog box (see Figure 11.16). Figure 11.16. The database Properties dialog box includes settings for statement permissions. 3. Click on the Permissions tab. Notice that the leftmost column contains the roles and logins that you have created within the database. Select a role or login, and check the statement permissions you want to assign. Comments Each statement permission has three different states:  Revoke. The user is not given the statement permission unless he is a member of a role Page 474 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html that has been given the permission. The graphic to depict this state is blank.  Grant. The user is given permission to run the statement. The graphic to depict this state is the check.  Deny. The user is denied the statement permission and cannot run the SQL Statement. The red X depicts this state. Statement permissions are a great way to permit assistants the ability to add tables, views, stored procedures, and other objects as needed. Because the default setting is to deny these permissions, you do not have to worry about unwarranted object proliferation in your databases. [ Team LiB ] Page 475 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.10 Use Object Permissions At this point, you have added SQL Server logins and established user accounts in each database within SQL Server. In most situations, you want to restrict the user's access to tables, views, stored procedures, and other objects within this database. This is done by setting permissions on these database objects. I do not want every user to have read, write, and update permissions on every table within the database. Otherwise, unauthorized users are able to view data that they are not permitted to see. Often, only certain users are permitted to add new records or to delete existing records in a database table. Without object permissions, I have no way of controlling individual user access to the data within a database. Technique You'll use the Enterprise Manager dialog boxes to assign permissions on the objects within a database. SQL Server provides the following object permissions for tables, views, and stored procedures:   Select. Permission to issue SELECT statements against a table or view to retrieve data. Insert. Permission that allows the user to execute the INSERT statement to add new records to a table or view.  Update. Permission that allows the UPDATE statement to run, changing the data in a row of a table or view.   Delete. Permission to run the DELETE statement and remove rows from a table or view. Execute. Permission that allows the user to run stored procedures and functions within the database. Steps A SQL Server database contains a wide variety of database objects, such as tables, views, and stored procedures. A user account can be assigned specific permissions on each object in a SQL Server database. These permissions direct SQL Server to allow an account to run stored procedures, view and update data that is contained in tables, and perform other database operations. As you click on the individual object permissions, the check box changes from empty to a green check mark to a red X, as mentioned in the previous How-To. 1. 2. Open Enterprise Manager and expand the Northwind database's icon. Expand the Northwind database's Tables icon to display all the tables in Enterprise Manager's right pane. 3. Right-click on a table in the Tables list, and select Properties from the shortcut menu to open the Table Properties dialog box (see Figure 11.17). Figure 11.17. The Table Properties dialog box displays important information about the table. Page 476 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Select the Permissions button in the upper-right corner of the Table Properties dialog box to displaythe Permissions tab (see Figure 11.18). Figure 11.18. The Permissions tab contains all the object permission settings for the table. Page 477 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 5. Select a user or role from the leftmost column, and then click on the check box in any of the Permissions columns. Comments Each permission on an object has three levels of access:   Grant. SQL Server permits all operations whose permission is set to Grant. Revoke. The user is unable to perform the operation unless he's been implicitly granted permission through membership in some role (discussed in How-To 11.11) or through a group. Revoke is the default setting for all permissions.  Deny. The user cannot perform a denied operation, even if permission is implicitly granted by role or group membership. Most often, unless the user has a specific need to be granted or denied permission on an object, you'll leave the permission set to Revoke. This means that the permission is not provided unless the user is given permission through a database role (discussed in the next section). Generally speaking, it is better to provide too little access to database objects than to grant too much access that could lead to confidentiality or data integrity problems. This is why the default permission on SQL Server objects is set to Revoke by default. [ Team LiB ] Page 478 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.11 Use Fixed Database Roles Creating database accounts and assigning permissions is obviously a lot of work. When you consider that most SQL Server installations service dozens to hundreds of users, it's easy to see that a considerable amount of time and effort goes into administering database security. All in all, creating and managing a database security scheme is one of the most time- and effort-intensive tasks of any database administrator. Fortunately, SQL Server provides a tool to considerably lighten this administrative load. As you'll see in this section, SQL Server makes it easy to assign predefined permissions to groups of users rather than individually handling each user. Setting up database object permissions for individual users is a hassle. Every time a user account is added to SQL Server, the permissions on database objects must be set for the user. I'd like to be able to minimize the amount of time spent designing individual object permissions for my users. Technique SQL Server defines many built-in fixed database roles that grant or deny permissions on database objects. Each fixed database role adds or subtracts permissions on all the tables, stored procedures, or other database objects within the database. A user who is added to a fixed database role inherits all the permissions specified by the role. A person can belong to multiple roles, if necessary. Steps A fixed database role is similar in some ways to the fixed server roles discussed earlier in this chapter. The difference is that fixed database roles determine permissions to perform operations on objects within a single database, whereas fixed server roles specify the administrative operations that are permitted on all SQL Server databases. SQL Server defines 10 different fixed database roles:  db_owner. As owners of the database, members of this role can perform any task that is granted to the other fixed database roles. The db_owner role includes all administrative, design, and data access permissions.  db_accessadmin. The db_accessadmin role manages the creation of new logins and accounts. These logins and accounts include individual users as well as groups of users.   db_datareader. This role is able to view all data from all tables in the database. db_datawriter. The db_datawriter role is able to add, update, or delete data from all the tables in the database.  db_ddladmin. This role can modify objects within the database. This means that db_ddladmin users can add or delete tables or modify the design of existing tables.  db_securityadmin. Members of the db_securityadmin role manage security on the database. This means they can add new roles and manage statement and object permissions within the database.  db_backupoperator. This role is responsible for backing up the database. Page 479 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html  db_denydatareader. Members of this role are unable to view data in the database. This role is useful for data entry clerks whose job is inputting new data without viewing existing records.  db_denydatawriter. Use this role to prevent users from changing data in the database. This is useful, for instance, for clerical and management staff who are supposed to be able to read, but not update, data.  public. This role is for all users of the database that don't have specifically defined roles or permissions in the database. You can edit the permissions of the public role, but be careful. The db_prefix on each of these roles is significant. It's there to help distinguish between fixed server roles (explained earlier in this How-To and discussed in the following section) from the fixed database roles explained in this section. 1. 2. Open Enterprise Manager and expand the Northwind database's icon. Locate and expand the Northwind database's Roles icon to display the fixed database roles in Enterprise Manager's right pane (see Figure 11.19). Figure 11.19. SQL Server 2000 defines 10 different fixed database roles. 3. Right-click on a role (such as db_securityadmin) in the Roles list, and select Properties from the shortcut menu. You'll see the Database Role Properties dialog box (shown in Figure 11.20) open in response. Figure 11.20. Use the Database Role Properties dialog box to assign login accounts to a SQL Server's fixed database role. Page 480 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 4. Click on the Add button to open the Add Role Members dialog box (see Figure 11.21). This dialog shows all database accounts that are not currently assigned to the selected role. Figure 11.21. The Add Role Members dialog box shows everyone who is not currently assigned to the selected role. 5. Click on any members you'd like to add to the selected role. The list box in the Add Role Members dialog box allows you to select multiple logins at one time. 6. When you are satisfied with your selections, click the OK button to close the Add Role Page 481 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Members dialog box; then close the Database Role Properties dialog box by clicking on its OK button. Comments The fixed database roles are not to be confused with the similar fixed server roles. Each fixed database role applies only to a single database. The members you add to a role are only able to operate with the role inside of the selected database. Fixed server roles, on the other hand, affect all databases within SQL Server as well as SQL Server. Therefore, fixed database role security is the ideal way to assign specific permissions on a single database. This can be useful to allow departmental groups within a company to manage their own databases. Because relatively small amounts of data are influenced by fixed database roles (this depends, of course, on the type and size of the database), it isn't as likely that a poorly trained individual will damage the data within SQL Server. [ Team LiB ] Page 482 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.12 Create Custom Database Roles Even though the 10 built-in fixed server roles might appear to cover all contingencies, it is possible to create custom database roles for your SQL Server databases. One of the problems with the fixed database roles is that they apply to all objects within the database. Therefore, assigning users to the db_datareader role means that they'll be able to read data in all tables and views within the database. What should you do if you want to provide access just to one or two tables instead of every table? My database includes a mix of public and confidential information. I want to set up a role that permits read access to the Categories and Products tables, but does not allow access to the Employees or Customers tables. Technique You'll create a custom database role that specifies read permissions on the Products and Categories tables, but does not give access to any other table in the database. Steps One of the essential qualities of SQL Server is its flexibility in dealing with almost any environment. As an example of this flexibility, SQL Server provides custom database roles, which are freely modified to include permissions to perform any administrative task. The SQL Server system administrator creates the custom database roles and assigns them to any users who require the special combination of permissions on the database objects. SQL Server recognizes the security profiles that are established with custom database roles the same as fixed database roles. Although considerable work is involved in setting up custom database roles, you are assured that your users can view, edit, and add records only to those tables you want them to. 1. 2. Open Enterprise Manager and expand the Northwind database's icon. Right-click the Northwind database's Roles icon and select New Database Role from the shortcut menu. The New Role dialog box (see Figure 11.22) opens in response. Notice how similar this dialog box is to the Database Role Properties dialog box shown in Figure 11.20. Figure 11.22. Add a custom database role with the New Role dialog box. Page 483 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. 4. Provide a name such as ProdCatReadOnly for the custom database role. Add users to the new role as you did in steps 4 and 5 in section 11.11. In this case, you'll add the guest user so that all SQL Server users who are added to this role will have access to the tables. 5. 6. Click OK to close the New Role dialog box and to establish the ProdCatReadOnly role. Right-click on the ProdCatReadOnly role and select Properties from the shortcut menu. When the Database Role Properties dialog box opens, click on the Permissions button in the upper-right corner to display the Permissions tab (see Figure 11.23). Figure 11.23. Set the database object permissions with the Permissions tab of the Database Role Properties dialog box. Page 484 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 7. Locate the Categories and Products table and click on the check box in the SELECT column until a green check mark appears for each table. Notice that as you continue to click on the check box, its icon changes from the green check mark to a red X, and then empty again. These icons indicate the permission states on the table: green means grant, the red X means deny, and the empty check box means revoke. 8. Click the OK button to close the Permissions dialog box, and then close the Database Role Properties dialog box. Comments You'll notice in Figure 11.23 that the list box on the permissions tab shows all the database objects, including tables, views, and stored procedures. You are able to enable or disable the SELECT, INSERT, UPDATE, DELETE, and EXEC permissions for any of the objects that appear in the list. It's easy to go overboard on setting up a custom database role. You can overly complicate a custom database role by overloading it with too many security settings. Generally speaking, you're better off with several simple, easy-to-understand custom database roles than one or two massive, complicated custom roles. [ Team LiB ] Page 485 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 11.13 Create Application Roles As if fixed database roles and custom database roles weren't enough, SQL Server provides a third category of database role. Sometimes you want users to simply start up an application and have access to SQL Server's data through the application. In these cases, you don't want to have to set up logins, user accounts, and other security configurations to accommodate the application's users. This is the job of application roles. I have users who routinely access SQL Server through an application that I've written in Visual Basic. I also have users who use Web pages to access the data using ASP techniques. I'd like a simple and easy way to provide these users with limited access to the database, but I don't want to spend a lot of time configuring SQL Server. Technique Create a SQL Server 2000 application role for these users. The application logs into SQL Server and provides the password that is required to access data. Typically, application roles are severely limited in their ability to access data. Steps SQL Server provides for the creation of application roles. An application role is established to allow programs that are written in Visual Basic and other programming languages to freely access and update SQL Server data. People cannot use application roles. You cannot add users, groups, or other roles to an application role. The application role is not enabled until a password is provided. At runtime, the user's application will provide the role's name and password to gain access to the data that is granted by the application role. The application is unable to do anything other than the permissions you established for the application role. 1. 2. Open Enterprise Manager and expand the Northwind database's icon. Right-click the Northwind database's Roles icon and select New Database Role from the shortcut menu. The New Role dialog box opens in response (see Figure 11.24). Select the Application Role option button near the bottom of this dialog box. Figure 11.24. The New Role dialog box allows you to create application roles. Page 486 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 3. 4. 5. 6. Provide a name and a password for the application role. Click the OK button to save the application role. Right-click the new application role, and select Properties from the shortcut menu. Set the object permissions as you did in steps 6, 7, and 8 in section 11.12 in this chapter. Comments An application role bypasses the normal permissions that are applied to a database. A user who is not otherwise able to access data will be able to use a program such as Excel, Word, or Visual Basic to get at the data as long as an application role has been established for the program. The permissions that are established for the application role exist only while the application maintains a connection to the database. While the application role is active, all other permissions that are granted to the user on the database are suspended, and only the permissions that the application role provides are enabled. A user can't exploit an application role to access other databases that SQL Server manages. The only permissions that an application role has on other databases are the permissions granted to the default guest user. Under most circumstances, the system administrator will have disabled or severely limited the SQL Server guest account. [ Team LiB ] Page 487 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 12. Utilizing XML Data In Your Visual Basic .NET Applications In this chapter you will        Utilize XML in .NET Use XML namespaces in .NET Use XMLWriter to create an XML document Use XMLReader to read an XML document Work with the XML document object model Retrieve XML from SQL Server 2000 Work with datasets and XML Extensible Markup Language (XML) is to data what Hypertext Markup Language (HTML) is to presentation. XML is similar to HTML; in fact, it is derived from the same standard. As you deal with outside systems over the Internet or even by importing data, you will need to access XML data at one time or another. [ Team LiB ] Page 488 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Ways of Utilizing XML in .NET You can utilize XML from within .NET in hundreds of ways. The following list spells out some of those ways. The first three ways will be shown in some of the How-Tos later in this chapter.       Utilizing the XML Document Object Model (DOM) Reading XML with the XMLReader Writing XML with the XMLWriter Validating XML with Schemas Using XPathNavigator in the .NET Framework Integrating XML with Relational Data and ADO.NET To use XML, you must use the XML namespaces that are available within .NET. [ Team LiB ] Page 489 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] XML Namespaces in .NET .NET utilizes XML for a number of purposes behind the scenes. As such, .NET has a number of namespaces that not only can you use, but that .NET uses as well. Those namespaces are as follows:     System.XML. Provides standards-based support for processing XML. System.XML.Xpath. Contains the XPath parser and evaluation engine. System.XML.XSL. Provides support for Extensible Stylesheet Transformations (XSLT). System.XML.Schema. Contains the XML classes that provide standards-based support for XML Schemas Definition (XSD) language schemas. You will see some classes within these namespaces utilized in this chapter. You can enhance the classes to handle almost any task you might have that utilizes XML. [ Team LiB ] Page 490 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 12.1 Use XMLWriter to Create an XML Document Sometimes I need to take data that is in my database and write it out to an XML document. I heard that XMLWriter is a good way to do this. What does XMLWriter do, and how do I create an XML document with it? Technique The XMLWriter provides a quick way to generate streams or files that contain XML data. The stream is not cached; it is forward-only. The XML data that the XMLWriter generates conforms to W3C XML 1.0 and the namespaces in XML recommendations. With XMLWriter, you can accomplish the following:   Create well-formed XML. Manage the output WriteState property. including methods to determine the progress of the output with the      Flush or close the output. Write multiple documents to one output stream. Encode binary bytes as base64 and as binhex, and write out the resulting text. Report the current namespace prefix, xml:lang, or xml:space scope. Write valid names, qualified names, and name tokens. XMLWriter has one implementation: the XMLTextWriter. To show you how to use the XMLTextWriter, the sample code will create a data table, allowing the user to add names to it. Then the XMLTextWriter will be used to write the data from the data table into an XML document. Creating the Data Table Rather than using a DataAdapter object to create and populate the data table from live data, the code will create the data table from scratch, and the user will add data to it. To perform this task, add the properties and methods shown in Table 12.1. The first object that will be created and utilized is the DataColumn object. Table 12.1. Objects, Properties, and Methods for Creating a DataTable Object Object Property/Method Description Specifies the Column name for the current data column that is being created. Stores the Caption used to be displayed. Adds the current DataColumn object to the collection of columns in the data table. DataColumn ColumnName DataColumn Caption DataTable.Columns Add DataTable NewRow Creates a DataRow object. Page 491 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataRow Item(ColumnName) Replaces data in the specified column, in the current DataRow object. Add Adds the data row to the collection of rows in the data table . DataTable.Rows Using the XMLTextWriter Implementation The last task that the example performs is creating the XML document by using the properties and methods of the XMLTextWriter class, shown in Table 12.2. Table 12.2. XMLTextWriter Properties and Methods Used for This How-To Property/Method Description Writes the XML declaration with the version 1.0. Specifies how you want the XML file formatted. In this case, System.Xml.Formatting.Indented is used. Writes the DOCTYPE declaration with the specified name and optional attributes. This allows you to specify the type of objects that this document represents. Allows you to write comments into your XML document. Used for both the rows and the columns, this lets you specify the starting element for a row that is represented from a table. WriteStartDocument Formatting WriteDocType WriteComment WriteStartElement WriteAttributeString Writes columns and properties for data that is represented in the XML document. WriteEndElement Flush Close Steps Ends the row or column. Flushes the stream from memory. Closes the string. Open and run the Visual Basic .NET Chapter 12 solution. From the main Web page, click on the hyperlink with the caption How-To 12.1: Use XMLWriter to Create an XML Document. When the page loads, you can enter a few names by entering the last and first names and then clicking the button labeled Add to DataTable. When you have added a few names, click the button labeled Create XML File. Using Explorer, open the file created in C:\ called test.xml (see Figure 12.1). 1. Create a Web Form. Then place the Labels, TextBoxes, Buttons, and DataGrid objects as seen in Figure 12.1 on the form with the properties set as in Table 12.3. Table 12.3. Label, TextBox, and Button Control Property Settings Object Property Setting Page 492 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label TextBox Label TextBox Button Text ID Text ID ID Text Last Name txtLastName First Name txtFirstName btnAdd Add to DataTable btnCreateXMLFile Create XML File dgDataToWrite hplReturnToMain wfrmMain.aspx Button ID Text DataGrid HyperLink ID ID NavigateURL 2. Add the following line to the code module of the form. Place it under the line that reads Web Form Designer Generated Code. 3. 4. 5. Dim mdtData As New DataTable() Add the code in Listing 12.1 to the Load event of the page. If the data table has not been saved to the Session object, then you need to create it from scratch by first creating the data columns and then adding them to the data table. The DataTable object is then saved to the Session object with the name MyDataTable. If the Session object entry already exists, it is assigned back to the module variable mdtData. Last, the data table is bound to the DataGrid object by calling the BindTheGrid routine, which is described in the next step. Listing 12.1 wfrmHowTo12_1.aspx.vb: Creating a DataTable Object from Scratch Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If (Session("MyDataTable") Is Nothing) Then Dim dcFirstName As New DataColumn() dcFirstName.ColumnName = "FirstName" dcFirstName.Caption = "First Name" mdtData.Columns.Add(dcFirstName) Dim dcLastName As New DataColumn() Page 493 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html dcLastName.ColumnName = "LastName" dcLastName.Caption = "Last Name" mdtData.Columns.Add(dcLastName) Session("MyDataTable") = mdtData Else mdtData = CType(Session("MyDataTable"), DataTable) End If BindTheGrid() End Sub 6. Create the routine BindTheGrid, shown in Listing 12.2, in the code module for the page. Listing 12.2 wfrmHowTo12_1.aspx.vb: Binding the Data Table to the Data Grid Sub BindTheGrid() dgDataToWrite.DataSource = mdtData dgDataToWrite.DataBind() End Sub 7. Add the code in Listing 12.3 to the Click event of the btnAdd button. This routine starts off by calling the NewRow method off the mdtData data table, thus creating a new DataRow object. The two columns in drNew are replaced with the values in txtLastName and txtFirstName. The new row is added to the data table, and the text boxes are cleared. Last, mdtData is rebound to the data grid by calling BindTheGrid. Listing 12.3 wfrmHowTo12_1.aspx.vb: Adding Data to the Data Table and Then Rebinding the Data Grid Private Sub btnAdd_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAdd.Click Dim drNew As DataRow drNew = mdtData.NewRow() drNew.Item("LastName") = Me.txtLastName.Text drNew.Item("FirstName") = Me.txtFirstName.Text mdtData.Rows.Add(drNew) Me.txtLastName.Text = "" Me.txtFirstName.Text = "" BindTheGrid() Page 494 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html End Sub 8. Add the code in Listing 12.4 to the Click event of the btnCreateXMLFile button. The first task is to declare an instance of the XMLTextWriter. Then the XMLTextWriter creates and opens the file c:\Text.xml. Next, the XML document is created using the Write methods, including the writing of the individual rows of the DataTable object. Last, the data is flushed, and the XMLTextWriter is closed. Listing 12.4 wfrmHowTo12_1.aspx.vb: Creating the XML Document Private Sub btnCreateXMLFile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCreateXMLFile.Click Dim xtwMyData As System.Xml.XmlTextWriter = Nothing Dim intCurrRow As Integer Dim intNumRows As Integer xtwMyData = New System.Xml.XmlTextWriter("c:\Test.XML", Nothing) intNumRows = mdtData.Rows.Count - 1 With xtwMyData .WriteStartDocument(False) .Formatting = System.Xml.Formatting.Indented .WriteDocType("Names", Nothing, Nothing, Nothing) .WriteComment("This file represents names list") .WriteStartElement("names") For intCurrRow = 0 To intNumRows '-- Start the current row .WriteStartElement("name", Nothing) '-- Write the fields .WriteAttributeString("FirstName", _ mdtData.Rows(intCurrRow).Item("FirstName")) .WriteAttributeString("LastName", _ mdtData.Rows(intCurrRow).Item("LastName")) '-- Ending the row .WriteEndElement() Next '-- Write the XML to file and close the writer .Flush() .Close() End With End Sub Figure 12.1. This XML document was created using XMLTextWriter. Page 495 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments This is one of three ways described in this chapter of how to write data out to an XML document. This is probably the second easiest method. The other two methods are using the XML DOM (described in How-To 12.3), which is the hardest method, and using the WriteXML method off the DataSet object (described in How-To 12.5), which is the easiest method of all three. The amount of control you have over the document matches the degree of difficulty in use. [ Team LiB ] Page 496 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 12.2 Use XMLReader to Read an XML Document In How-To 12.1, I learned how to write out data to an XML document by using the XMLWriter. How do I read data using the XMLReader? Technique Whereas the XMLWriter has one implementation (class), the XMLReader has three, depending on the task you need to perform. Those classes are listed in Table 12.4. Table 12.4. XMLWriter Implementations Class Name Purpose/Descriptions Reads character streams. This is a forward-only reader that has methods returning data on content and node types. No validation occurs. Provides a parser over an XML Document Object Model (DOM) API, similar to the XMLNode tree. XMLTextReader XMLNodeReader XMLValidatingReader Takes an XMLTextReader adding validation. In doing so, it provides a fully compliant validating or non-validating XML parser with DTD, XSD schema, or XML-Data Reduced (XDR) schema support . For this How-To, you will be using the XMLTextReader to read the file and display the results. To do this, you will use the following methods:   Read. Reads a line of the character stream out of the XMLReadReader. AttributeCount. Gives the count of attributes. This depends on the type of data that is being read. In this case, AttributeCount is used to display the individual attributes, which will be columns.  NodeType. Allows you to specify node types in the XML document. In the case of this How-To, the System.Xml.XmlNodeType.XmlDeclaration is checked for so that no information is printed for that type of node. You can see the other node types by looking at intellisense for the NodeType property.   Steps Value. Represents the actual value of the line in the stream. Close. Closes the stream. Open and run the Visual Basic .NET Chapter 12 solution. From the main Web page, click on the hyperlink with the caption How-To 12.2: Use XMLReader to Read an XML Document. When the page loads, click the button labeled Read XML File. The example then reads the XML file that is specified in the text box labeled File to Read and displays the information in the text area located at the bottom of the form (see Figure 12.2). 1. Create a Web Form. Then place the Label, TextBox, and Button objects as seen in Figure 12.2 on the form with the following properties set as in Table 12.5. Page 497 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table 12.5. Label, TextBox, and Button Control Property Settings Object Property Setting Label TextBox Button Text ID ID Text File to Read txtFileToRead btnReadFile Read XML File taOutput hplReturnToMain wfrmMain.aspx TextArea HyperLink ID ID NavigateURL 2. Note You will find the TextArea control in the HTML Components section of the toolbox. After you have dragged this control onto the Web Form, right-click and choose Run as Server Control from the pop-up menu. This will then run this control as a server side control, and you will be able to work with its properties and methods in code behind. 3. Add the code in Listing 12.5 to the Click event of btnReadFile. To start off, the XXLTextReader is initialized with the XML document specified in txtFileToRead. Then each node of the document is read using the Read method. The node type is compared to make sure the current node is not the XMLDeclaration. If it's not, then each of the attributes is displayed; in this case, the columns of each name are entered. After each of the nodes (rows) have been read and added to strOut, then that string is assigned to the InnerText property of the TextArea object called taOutput. Last, the XMLTextReader object is closed. Listing 12.5 wfrmHowTo12_2.aspx.vb: Reading an XML Document Using XMLTextReader Private Sub btnReadFile_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnReadFile.Click Dim xtrNames As System.Xml.XmlTextReader Dim strOut As String Dim intAtts As Integer Dim intCurrAtt As Integer Try Page 498 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html strOut = "Reading file " & _ Me.txtFileToRead.Text & "..." & vbCrLf xtrNames = New System.Xml.XmlTextReader(Me.txtFileToRead.Text) While xtrNames.Read() intAtts = xtrNames.AttributeCount If xtrNames.NodeType <> System.Xml.XmlNodeType.XmlDeclaration Then If intAtts > 0 Then For intCurrAtt = 0 To intAtts - 1 strOut &= xtrNames(intCurrAtt) & " " Next Else strOut &= xtrNames.Value End If End If End While Catch excp As Exception strOut &= "Following Error Occurred: " & excp.Message Finally strOut &= vbCrLf & "Done Processing " & Me.txtFileToRead.Text & "" taOutput.InnerText = strOut If Not xtrNames Is Nothing Then xtrNames.Close() End If End Try End Sub Figure 12.2. The information displayed here was read from an XML document using XMLReader. Page 499 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Again, as with XMLTextReader, this falls into the middle of complexity when it comes to reading XML documents. If you want to actually validate the data, then you should use the XMLValidatingReader implementation of the XMLReader, rather than the XMLTextReader. [ Team LiB ] Page 500 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 12.3 Work with the XML Document Object Model I want to have more control over the XML document as I create it. I heard that I can do this with XML DOM. How do I work with the XML Document Object Model? Technique In How-Tos 12.1 and 12.2, you saw two ways to independently read and write XML documents. However, what if you want to do both at the same time? To have this kind of flexibility, you need to use the XML Document Object Model, also known as DOM. The DOM class is an XML document that is represented in memory. It allows you not only to programmatically read and write out XML documents, but also to modify those documents in memory. Within the DOM, the XMLNode object is the base object in the DOM Tree, XMLDocument class that extends it. XMLDocument has methods that allow you to perform operations on the document as a whole. It also lets the developer work with the nodes in the entire XML document. Both XMLNode and XMLDocument have performance and usability enhancements over prior versions. The properties and methods of XMLNode and XMLDocument that will be used for this How-To are listed in Table 12.6. Table 12.6. DOM Properties and Methods Used in This How-To Class Name Property/Method Purpose/Description Loads an XML document into the XMLDocument object. In this case, it is a means to create the stub for the XML document that will be created from the dataset. XMLDocument LoadXML XMLDocument DocumentElement Serves as the root element for the document. It is, in fact, of the type XMLElement. XMLDocument CreateNode XMLElement AppendChild XMLDocument CreateComment XMLNode AppendChild Creates an XMLNode object. Appends the node created to the element specified as a child. Adds a comment to the XML document. Appends a node to another node as a child. Saves the current XML document. XMLDocument Save Steps Open and run the Visual Basic .NET Chapter 12 solution. From the main Web page, click on the hyperlink with the caption How-To 12.3: Working with the XML Document Object Model. As with How-To 12.1, when the page loads, you can enter a few names. Enter the last and first names, and then click the button labeled Add to DataTable. When you have added a few names, click the button labeled Create XML File. Using Explorer, open the file created in C:\ called test.xml(see Page 501 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Figure 12.3). 1. Create a Web Form. Then place the Labels, TextBoxes, Buttons, and DataGrid objects as seen in Figure 12.3 on the form with the properties set as in Table 12.7. Table 12.7. Label, TextBox, and Button Control Property Settings Object Property Setting Label TextBox Label TextBox Button Text ID Text ID ID Text Last Name txtLastName First Name txtFirstName btnAdd Add to DataTable btnCreateXMLFile Create XML File dgDataToWrite hplReturnToMain wfrmMain.aspx Button ID Text DataGrid HyperLink ID ID NavigateURL 2. Add the following line to the code module of the form. I place it under the line that reads Web Form Designer Generated Code. 3. 4. 5. Dim mdtData As New DataTable() Add the code in Listing 12.6 to the Load event of the page. If the data table has not been saved to the Session object, then it is created from scratch by first creating the data columns and then adding them to the data table. The DataTable object is then saved to the Session object with the name MyDataTable. If the Session object entry already exists, it is reassigned to the module variable mdtData. Last, the data table is bound to the DataGrid object by calling the BindTheGrid routine, which is described in the next step. Listing 12.6 wfrmHowTo12_3.aspx.vb: Creating a DataTable Object from Scratch Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Page 502 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 'Put user code to initialize the page here If (Session("MyDataTable") Is Nothing) Then Dim dcFirstName As New DataColumn() dcFirstName.ColumnName = "FirstName" dcFirstName.Caption = "First Name" mdtData.Columns.Add(dcFirstName) Dim dcLastName As New DataColumn() dcLastName.ColumnName = "LastName" dcLastName.Caption = "Last Name" mdtData.Columns.Add(dcLastName) Session("MyDataTable") = mdtData Else mdtData = CType(Session("MyDataTable"), DataTable) End If BindTheGrid() End Sub 6. Create the routine BindTheGrid, shown in Listing 12.7, in the code module for the page. Listing 12.7 wfrmHowTo12_3.aspx.vb: Binding the Data Table to the Data Grid Sub BindTheGrid() dgDataToWrite.DataSource = mdtData dgDataToWrite.DataBind() End Sub 7. Add the code in Listing 12.8 to the Click event of the btnAdd button. This routine starts off by calling the NewRow method off the mdtData data table, thus creating a new DataRow object. The two columns in drNew are replaced with the values in txtLastName and txtFirstName. The new row is added to the data table, and the text boxes are cleared. Last, mdtData is rebound to the data grid by calling BindTheGrid. Listing 12.8 wfrmHowTo12_3.aspx.vb: Adding Data to the Data Table and Then Rebinding the Data Grid Private Sub btnAdd_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAdd.Click Dim drNew As DataRow Page 503 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html drNew = mdtData.NewRow() drNew.Item("LastName") = Me.txtLastName.Text drNew.Item("FirstName") = Me.txtFirstName.Text mdtData.Rows.Add(drNew) Me.txtLastName.Text = "" Me.txtFirstName.Text = "" BindTheGrid() End Sub 8. Add the code in Listing 12.9 to the Click event of the btnCreateXMLFile button. After getting the number of rows in mdtData, an XML document is started using the LoadXML method. Next, the root element is retrieved so that nodes can then be "hung" from it, using the CreateNode and AppendChild methods. A comment is then added using the CreateComment method of xdMyData. Then, for each of the rows in the mdtData, nodName is created using CreateNode and AppendChild methods, and node on nodName is added for the LastName and FirstName. Again, these nodes are added using the CreateNode and AppendChild methods. Last, the Save method is used to save the XML document. Listing 12.9 wfrmHowTo12_3.aspx.vb: Creating the XML Document Private Sub btnCreateXMLFile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCreateXMLFile.Click Dim xdMyData As New System.Xml.XmlDocument() Dim xeRoot As System.Xml.XmlElement Dim intCurrRow As Integer Dim intNumRows As Integer intNumRows = mdtData.Rows.Count - 1 With xdMyData '-- Start the XML document .LoadXml("") xeRoot = .DocumentElement Dim nodRoot As System.Xml.XmlNode = _ .CreateNode(System.Xml.XmlNodeType.Element, "Names", "") xeRoot.AppendChild(nodRoot) '-- Add the comment .CreateComment("This file represents names list created using the XML DOM") Page 504 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html For intCurrRow = 0 To intNumRows '-- Start the current row Dim nodName As System.Xml.XmlNode = _ .CreateNode(System.Xml.XmlNodeType.Element, "name", "") nodName = nodRoot.AppendChild(nodName) '-- Add the attributes (columns) Dim nodFirstName As System.Xml.XmlNode = _ .CreateNode(System.Xml.XmlNodeType.Element, "FirstName", "") nodFirstName.InnerText = mdtData.Rows(intCurrRow).Item("FirstName") nodName.AppendChild(nodFirstName) Dim nodLastName As System.Xml.XmlNode = _ .CreateNode(System.Xml.XmlNodeType.Element, "LastName", "") nodLastName.InnerText = mdtData.Rows(intCurrRow).Item("LastName") nodName.AppendChild(nodLastName) Next '-- Write the XML to file and close the writer .Save("c:\Test.xml") End With End Sub Figure 12.3. This XML document was created using XMLTextWriter. Page 505 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments As you can see, working with the DOM takes a bit more time and work. However, when you really need to massage the data, this is the way to go! [ Team LiB ] Page 506 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 12.4 Retrieve XML from SQL Server 2000 Sometimes I have to pull data from my SQL Server database into an XML document format. How do I do that with SQL Server 2000? Technique To accomplish this task, you will create a Command object with the Transact-SQL SELECT statement that you want to execute. However, at the end of your SQL statement, you will add the clause FOR XML mode. The mode can be any of these that are listed:  RAW. With this mode, each of the rows that is returned in the query result is made into a generic XML element with as the identifier tag.  AUTO. Each of the rows and the columns are identified with tags for each of the elements and attributes, using the column names as identifier tags.  EXPLICIT. Here, you have to nest and create your query in a particular way. For more information on this mode, check out the SQL Server Books Online. For this example, the code will use the RAW mode and look like this: SELECT * FROM Customers FOR XML RAW To execute the SQL statement in this case, you use the method ExecuteXMLReader. When you use this method, an XMLReader is returned. You should then iterate through the elements as seen in How-To 12.2. Steps Open and run the Visual Basic .NET Chapter 12 solution. From the main Web page, click on the hyperlink with the caption How-To 12.4: Retrieving XML from SQL Server 2000. When the page loads, you will see an example of a T-SQL statement that retrieves data from SQL Server 2000 in an XML format. Click on the button labeled Retrieve XML, and the data will be listed in the TextArea at the bottom of the form (see Figure 12.4). 1. Create a Web Form. Then place the Label, TextBox, and Button objects as seen in Figure 12.4 on the form with the properties in Table 12.8 set. Table 12.8. Label, TextBox, and Button Control Property Settings Object Label TextBox Property Text ID Text ID Setting SQL To Execute txtSQLToExecute SELECT * FROM Customers FOR XML AUTO, ELEMENTS btnRetrieveXML Button Page 507 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Text TextArea ID Retrieve XML taOutput hplReturnToMain HyperLink ID NavigateURL wfrmMain.aspx 2. Add the code in Listing 12.10 to the Click event of btnRetrieveXML. Taking the SQL statement displayed in the "Technique" section, the Command object cmdCust is created, and ExecuteXMLReader is invoked. The XMLReader then iterates through each of the elements in the document, and they concatenate to a string. Last, the string is assigned to the InnerText property of taOutput, and the connection to the XMLReader object is closed. Listing 12.10 wfrmHowTo12_4.aspx.vb: Reading an XML Document Using XMLTextReader Private Sub btnRetrieveXML_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnRetrieveXML.Click Dim cnn As New SqlClient.SqlConnection(BuildCnnStr("(local)", "Northwind")) Dim cmdCust As SqlClient.SqlCommand = New SqlClient.SqlCommand( _ Me.txtSQLToExecute.Text, cnn) Dim xrCust As System.Xml.XmlReader Dim intAtts As Int32 Dim intCurrAtt As Int32 Dim strOut As String Try cnn.Open() xrCust = cmdCust.ExecuteXmlReader() While xrCust.Read() intAtts = xrCust.AttributeCount If xrCust.NodeType <> System.Xml.XmlNodeType.XmlDeclaration Then If intAtts > 0 Then For intCurrAtt = 0 To intAtts - 1 strOut &= xrCust(intCurrAtt) & vbCrLf Next Else strOut &= xrCust.Value & vbCrLf End If End If End While Catch excp As Exception strOut &= "Following Error Occurred: " & excp.Message Page 508 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Finally strOut &= vbCrLf & "Done Processing " taOutput.InnerText = strOut If Not xrCust Is Nothing Then xrCust.Close() End If cnn.Close() End Try End Sub Note You have been using the BuildCnnStr() function throughout this book. You should add this function to a module or copy it from other chapters. Here is the code for the function: Function BuildCnnStr(ByVal strServer As String, ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Figure 12.4. The information displayed here was read from SQL Server in an XML format. Page 509 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments Normally, you would be taking the XML document that the command object returned and passing that on to another system that requires the data to be in XML format. The data was displayed from the XMLReader for demonstration purposes. [ Team LiB ] Page 510 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 12.5 Work with Datasets and XML Sometimes, I have to pull XML documents into datasets and vice versa. How do I accomplish this using .NET? Technique .NET has developed a number of ways to utilize datasets and XML together. The simplest use is pushing data between the two. To do this, you have the two methods belonging to the DataSet object: ReadXML and WriteXML. For both of these methods, you need to provide a filename to read or write the XML document to. To demonstrate how to take advantage of these methods, I created a form that looks similar to the other How-Tos showing how to write XML documents. However, for this example, I also added another button and data grid that will show the data after reading from the XML document. Steps Open and run the Visual Basic .NET Chapter 12 solution. From the main Web page, click on the hyperlink with the caption How-To 12.5: Working with Datasets and XML. As with How-To 12.1, when the page loads, you can enter a few names. Enter the last and first names, and then click the button labeled Add to DataTable. When you have added a few names, click the button labeled Create XML File. Using Explorer, open the file created in C:\ called test.xml. If you click Read XML File, you will see the same data because it was read from text.xml (see Figure 12.5). 1. Create a Web Form. Then place the Labels, TextBoxes, Buttons, and DataGrid objects as seen in Figure 12.5 on the form with the properties set as in Table 12.9. Table 12.9. Label, TextBox, and Button Control Property Settings Object Property Setting Label TextBox Label TextBox Button Text ID Text ID ID Text Last Name txtLastName First Name txtFirstName btnAdd Add to DataTable btnCreateXMLFile Create XML File dgDataToWrite btnReadFile Button ID Text DataGrid Button ID ID Page 511 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataGrid HyperLink ID ID NavigateURL dgResultsFromXML hplReturnToMain wfrmMain.aspx 2. Add the following line to the code module of the form. Then place it under the line that reads Web Form Designer Generated Code. 3. 4. 5. 6. Dim mdtData As New DataTable() Dim mdsData As New DataSet() Add the code in Listing 12.11 to the Load event of the page. If the data table has not been saved to the Session object, then it is created from scratch by first creating the data columns and then adding them to the data table. The DataTable object is then saved to the Session object with the name MyDataTable. A DataSet object is also created because some of the XML methods must be used from the DataSet object, rather than at the DataTable level. If the Session objects entry already exists, it is assigned back to the module variable mdtData and mdsData. Last, the data table is bound to the DataGrid object by calling the BindTheGrid routine, which is described in the next step. Listing 12.11 wfrmHowTo12_5.aspx.vb: Creating a DataTable Object from Scratch Private Sub Page_Load(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles MyBase.Load 'Put user code to initialize the page here If (Session("MyDataTable") Is Nothing) Then Dim dcFirstName As New DataColumn() dcFirstName.ColumnName = "FirstName" dcFirstName.Caption = "First Name" mdtData.Columns.Add(dcFirstName) Dim dcLastName As New DataColumn() dcLastName.ColumnName = "LastName" dcLastName.Caption = "Last Name" mdtData.Columns.Add(dcLastName) mdsData.Tables.Add(mdtData) Session("MyDataTable") = mdtData Session("MyDataSet") = mdsData Else mdtData = CType(Session("MyDataTable"), DataTable) End If Page 512 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BindTheGrid() End Sub 7. Create the routine BindTheGrid, shown in Listing 12.12, in the code module for the page. Listing 12.12 wfrmHowTo12_5.aspx.vb: Binding the Data Table to the Data Grid Sub BindTheGrid() dgDataToWrite.DataSource = mdtData dgDataToWrite.DataBind() End Sub 8. Add the code in Listing 12.13 to the Click event of the btnAdd button. This routine starts off by calling the NewRow method off the mdtData data table, thus creating a new DataRow object. The two columns in drNew are replaced with the values in txtLastName and txtFirstName. The new row is added to the data table, and the text boxes are cleared. Last, mdtData is rebound to the data grid by calling BindTheGrid. Listing 12.13 wfrmHowTo12_5.aspx.vb: Adding Data to the Data Table and Then Rebinding the Data Grid Private Sub btnAdd_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAdd.Click Dim drNew As DataRow drNew = mdtData.NewRow() drNew.Item("LastName") = Me.txtLastName.Text drNew.Item("FirstName") = Me.txtFirstName.Text mdtData.Rows.Add(drNew) Me.txtLastName.Text = "" Me.txtFirstName.Text = "" BindTheGrid() End Sub 9. Add the code in Listing 12.14 to the event of the btnCreateXMLFile button. After loading the dataset from the Session object, the WriteXML method is invoked to save the data into an XML document. Listing 12.14 wfrmHowTo12_5.aspx.vb: Creating the XML Document from the Dataset Private Sub btnCreateXMLFile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnCreateXMLFile.Click Page 513 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html mdsData = CType(Session("MyDataset"), DataSet) mdsData.WriteXml("c:\Test.xml") End Sub 10. Add the code in Listing 12.14 to the Click event of the btnReadFile button. Here, the code reads the XML document by using the ReadXML method off the dsXMLData DataSet object and then binds it to a DataGrid object. Listing 12.15 wfrmHowTo12_5.aspx.vb: Reading the XML Document Back into the Dataset Private Sub btnReadFile_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnReadFile.Click Dim dsXMLData As DataSet = New DataSet() dsXMLData.ReadXml("c:\Test.xml") Me.dgResultsFromXML.DataSource = dsXMLData Me.dgResultsFromXML.DataBind() End Sub Figure 12.5. This XML document was created using XMLTextWriter. Comments As you can see, for both reading and writing XML document from and to datasets, Microsoft has given us some easy commands to accomplish the task. However, remember that you do have the control over the format of the XML document that you have using the other methods, such as using the DOM. [ Team LiB ] Page 514 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Chapter 13. Creating XML Web Services In this chapter you will      Overview of the XML Web Services infrastructure Get started with XML Web Services Create a simple XML Web Service using parameters Consume XML Web Services Pass a dataset back from an XML Web Service Methods and other program logic available to applications both on the Web or the desktop are callled XML Web Servers or simply Web Servers. To use the service, or communicate, the consumer will use XML Messaging and HTTP. The same is true when the Web Service is communicating back to the consumer. One of the great things about using XML Web Services is that as long as the consumer can create and consume messages defined for the Web Service, it doesn't matter what the consumer is written in, or even what the platform is. The term used for this is loosely coupled, or in other words, nonproprietary (see Figure 13.1.) Figure 13.1. Notice that no specific languages or platforms are named in this graphic, except to point out ASP.NET, of course. You also can use XML Web Services either internally or externally to an organization, as long as you Page 515 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html can get to the network or Internet. [ Team LiB ] Page 516 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Overview of the XML Web Services Infrastructure The infrastructure of Web Services has four main areas:  XML Web Services Directories. Central location to locate XML Web Services that outside organizations create. The UDDI registry is an example of one of these directories. Your Web Service client might not even need to use these if you know the address of the Web Service you are accessing.  XML Web Service Discovery. Discovering documents that describe a particular XML Web Service using the Web Services Description Language (WSDL). The DISCO specification defines an algorithm for locating service descriptions. Again, if you know the location of the service description, you can avoid this process.  XML Web Service Description. Defines what types of methods the XML Web Service uses. Tells clients how to interact with an XML Web Service so that they know how to use it.  XML Web Service Wire Formats. To be able to communicate with all platforms and languages, XML Web Services use open wire formats. These are protocols that any system that is capable of supporting the most common Web standards can understand. SOAP is the main protocol used. Figure 13.2. Don't panic these steps are performed for you in some cases after you set up the Web reference. You can find all of the examples in this chapter in the Solution called Visual Basic .NET on the Web site. Note Chapter 13 You will find the Web Service solution in a separate location called SecurityWebServices on the Web site. The Chapter 13 solution will contain the sample forms that are created to call methods from the Web Service. Page 517 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Page 518 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 13.1 Get Started with XML Web Services I have heard some great things about XML Web Services, but I don't know how to get started. What do I do to get started working with XML Web Services? Technique The best way to get started with XML Web Services is to simply create your own XML Web Service and start playing with it. Visual Studio .NET makes it extremely easy to do just that. To achieve this task, you will be creating your first Web Service, which, of course, will be Hello World. Now, before you start groaning, this example will show you the basics of creating a Web Service without a lot of other fluff that gets in the way and confuses things. Creating a Web Service The way you start to create a Web Service is to choose ASP.NET Web Service for a new project. When you have done this, VS will create the Web Service project, and you will be brought to what looks like a blank Web Form, as displayed in Figure 13.3. Figure 13.3. Here is a newly created Web Service project. Note Remember: Web Services can be created in various ways. Because you are creating this one using Visual Studio .NET, you will be using ASP.NET to create it. For the most part, you will be using Web Services to provide central processes or functionality that Page 519 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html you want to be consistent regardless of where you consume it from. This means that you will not be creating a user interface that users will see; you are basically creating a class-like interface that will provide methods (hence the use of Service1.asmx instead of *.aspx). You will use *.asmx as an entry point for your Web Service. To really get going with working with your first Web Service, you will click on the View Code icon in the Solution Explorer. When you do so, you will see the first method to create. That's right it is Hello World. The first thing you should do now is uncomment the lines of code that read as follows: ' Public Function HelloWorld() As String ' HelloWorld = "Hello World" 'End Function The screen should look like Figure 13.4. Figure 13.4. Your first Web Service method. That's it! You have created your first Web Service method. Now it's time to test it. Testing the Web Service After you have created your Web Service, click the Start toolbar button. Visual Studio will then compile and build your Web Service. After which, Visual Studio will create a test page for your Web Service, as shown in Figure 13.5. Figure 13.5. This page that Visual Studio created gives you instructions on how to specify a namespace for your Web Service within the calling application. Page 520 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Note As mentioned on this Web page, when you are developing your Web Service, Visual Basic uses a temporary namespace called http://tempuri.org/. When you are going to make the Web service public, you will want to create different namespace for the Web Service. I would recommend just using the examples they give on your test Web page. One of the items you see on this test Web page is the list of operations, otherwise known as methods you created. If you click on the Hello World method, you will see another page that you will use to invoke the actual method (see Figure 13.6.) Figure 13.6. This page allows you to test your Hello World method. Page 521 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You also will see example code for calling the method using SOAP, HTTP GET, and HTTP POST. However, you will just be using this test page to check out the Hello World example, and you will be learning how to call methods from Visual Basic behind Web Forms in How-To 3.3. If you click on the Invoke button, you will see the following: Hello World This is the value that the method you created returns. That's it! That's all there is to the test page. Note Before telling yourself that this test page doesn't do much, remember that if you did have a problem with the code in your Web Service, the problem would have shown up here. This quick testing saves a lot of hassle of writing code that actually calls the methods and then making sure the calling code wasn't causing errors. Using the test page allows you to debug your Web Service before you integrate it. Okay, I am now off my SOAPbox. Pun intended. Looking at the Description of the Web Service Visual Studio .NET saves you from a lot of work. If you click the Back button and go to the main test page, you will see a link to Description in the top sentence. If you click on this link, you will see the SOAP code shown in Listing 13.1. Listing 13.1 http://localhost/WebService1/Service1.asmx?WSDL: Soap Definition for Your First Web Service - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The really nice thing to remember is that Visual Studio .NET generates all this code for you, so you don't have to. Steps For this How-To, you will create the example Web Service that was discussed in the "Technique" section. 1. 2. Open up Visual Studio .NET to the Start Page, with no projects or solutions opened. From the File menu, choose New, Project. You will see the New Project dialog box. Highlight Page 524 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html the ASP.NET Web Service template (see Figure 13.7.) Then click OK. You will then be given a blank *.asmx file. Figure 13.7. You will be using the ASP.NET Web Service template for this project. 3. Click on the in the Solution Explorer. You will see the commented out method called Hello World. Uncomment the lines of code that read as follows: 4. 5. 6. 7. 8. ' Public Function HelloWorld() As String ' HelloWorld = "Hello World" 'End Function Click the Start button. You are shown the test page as described in the "Technique" ssection. Comments Although this is definitely the simplest example to be given while creating a Web Service, if you look at the description of even this simple Web Service and you see all the SOAP that is generated, you can appreciate all the work Microsoft has done to make the generation of Web Services using Visual Studio as painless as possible. [ Team LiB ] Page 525 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 13.2 Create a Simple XML Web Service Using Parameters I have seen how to create a Web Service using the sample that Microsoft provides. This was instructive but not very useful. How do I create a Web Service that uses parameters? Technique For this How-To, you are going to create the start of a security Web Service. This security Web Service is going to take in two parameters: Login Name and Password. It will then check against a table that you will create of names, passwords, and security levels. The method you will create first will then pass back True or False if the name and password are found. Looking at the Security Table The security table is included in the Web Service's Web folder. It is called WebServiceSecurity.MDB and is, in fact, a jet database. You can see the table created, tblUsers, in Figure 13.8. Figure 13.8. Using the tblUsers, you can look up usernames and passwords The method created for this first real example will take in the username and password and then look up the username. If the username is found, the method will then compare the password. If the password matches, then True will be returned from the method. Otherwise, False will be returned. Passing Parameters You will pass parameters to Web Service methods just as you would to any other methods or functions, as shown in the function header for the Web Service method created in this How-To: Page 526 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Public Function TestUser(ByVal strUserID As String, ByVal strPassword As String) As Boolean The return value is also assigned to the name of the function. Specifying Descriptions for the Web Service and Methods You can help developers who use your Web Service by adding descriptions to the Web Service and each of the methods you create. This cuts down on the number of support requests you get, and is a good habit to get into. For the Web Service, you will place it in the WebService header, where you will want to specify your own namespace as well: _ Public Class SecurityServices_ This causes the description specified to be displayed as the first line on the main test page. For the method, you will include the description in the Web Method header: Public Function TestUserPassword(ByVal strUserID As String, _ ByVal strPassWord As String) As Boolean You can see what the lines of code look like in the designer in Figure 13.9. Figure 13.9. Adding descriptions to the Web Service. Now it's time to put it all together. Steps Page 527 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Open and run the SecurityWebService solution. From the main test page, click on the link for the method TestUserPassword. You are presented with a page to input the user ID and password (see Figure 13.10.) If you type FSBarker for the strUserID and test for the strPassword, the value True is returned; otherwise, False is returned. 1. 2. Create an ASP.NET Web service project, calling it SecurityWebService. Highlight the default .asmx file created in the Solution Explorer, renaming it to SecurityServices.asmx. 3. Click on the View Code button in the Solution Explorer. Change the WebService at the top of the code to read as follows: 4. 5. 6. 7. 8. _ Public Class SecurityServices Add the code in Listing 13.2 to the code of the Web Service. (Double-click on the Web Service to bring up the code.) You could replace the commented out lines that display for the Hello World Web method. This code starts off by specifying the description for the Web Method and then declaring the function header for the method called TestUserPassword. The parameters strUserID and strPassword are passed, and a Boolean type value is returned. The rest of this routine should look somewhat familiar because a DataAdapter object is created, and a DataTable object is filled, based on the username that was passed in. If a record is not found for the user, then False is passed back. If a record is found and the password matches, then True is passed back. If the password for the user does not match, then False is passed back. Listing 13.2 SecurityServices.asmx.vb: Web Method to Validate Username and Password Public Function TestUserPassword(ByVal strUserID As String, _ ByVal strPassword As String) As Boolean Dim ocnn As New _ OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=E:\InetPub\wwwroot\SecurityWebService\" & _ "WebServiceSecurity.MDB") Dim odaUsers As New _ OleDb.OleDbDataAdapter("Select * from tblUsers " & _ "Where UserID = '" &strUserID & "'", ocnn) Dim dtUsers As New DataTable() odaUsers.Fill(dtUsers) If dtUsers.Rows.Count = 0 Then Page 528 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html TestUserPassword = False ElseIf dtUsers.Rows(0).Item("Password") = strPassword Then TestUserPassword = True Else TestUserPassword = False End If End Function Note If you have a problem with sharing rights on the database, you might want to include "Mode=Share Deny None;" in your connection string. 9. Press the Start button on the toolbar to test the service. Figure 13.10. Testing a simple security Web Service. Comments When you are working in code for your Web Service, you can perform the majority of tasks, including ADO.NET, that you can in ASP.NET, except for those depending on a user interface (UI). You have now seen how to specify parameters. Now check out the next How-To to see how to consume, or use, your Web Service in an application. [ Team LiB ] Page 529 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 13.3 Consume XML Web Services I have created this Web Service that takes the username and password and returns True or False based on whether the username and password check out. I have even tested the Web Service to make sure it works correctly. How do I use, or consume, this Web Service in another application? Technique To use a Web Service, you need to create a reference to it. Setting Up the Web Reference to the Web Service To set up a Web reference, you choose Add Web Reference from the Project menu. You are then presented with the Add Web Reference dialog box, which allows you to browse for Web Services using the Universal Description Discovery Integration (UDDI) directories, as described in the beginning of the chapter. However, you will be able to browse to the Web Service you created and supply the name of the full URL using localhost to the name of the .asmx file you created, in this case: http://localhost/securitywebservice/SecurityServices.asmx After you have specified this, you will see the methods appear for your Web Service (see Figure 13.11.) Figure 13.11. You can test the Web Service right in this dialog box. Note You can see two methods for this Web Service: TestUserPassword and GetUserInfo. The second method is discussed in How-To 13.4. Page 530 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html After you have clicked Add Reference to accept the new reference, you can use the methods in your application. You can double-check that the reference is there by looking for it under the Web Reference node that appears in the Solution Explorer (see Figure 13.12.) Figure 13.12. You can see the reference created in the Solution Explorer. Calling Web Service Methods After you have created the reference to the Web Service, you will create a reference within your application, much like you would to other object models. Following is a snippet of code that performs this very task: Dim wsSec As localhost.SecurityServices wsSec = New localhost.SecurityServices() If wsSec.TestUserPassword(Me.txtUser.Text, Me.txtPassword.Text) Then As you can see, the method TestUserPassword is called just as another other method or function is called. Steps To preview this How-To, open the solution called Visual Basic .NET chapter folder. Note Chapter 13, located in the Page 531 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html You will probably have to re-establish the Web reference for the Web Service that is used for this example. Locate where you have installed SecurityWebServices and set the reference. When you run the project, the first form that comes up is the main switchboard with each of the How-Tos listed for this chapter. Click on How-To 13.3. The form for How-To 13.3 opens. If you type FSBarker for the User and Test for the Password, you get a message box telling you that you can continue into the application (see Figure 13.13). 1. Create a new Visual Studio .NET project using the Windows Application project template. Create a Windows Form, and place the controls shown in Table 13.1 in the order displayed in Figure 13.13. Table 13.1. Label, TextBox, and Command Button Control Property Settings Object Property Setting Label TextBox Label TextBox Button 2. Text Name Text Name Name User txtUser Password txtPassword btnLogin As described in the "Technique" section, set a reference to the Web Service you created in the previous How-To. Remember to point to the *.asmx file created in the Web Service. Choose Add Web Reference from the Project menu. 3. Add the code listed in Listing 13.3 to the Click event of btnLogin by double-clicking on the button. This routine instantiates an instance of the Web Service. Then, using the wsSec object, the routine calls the TestUserPassword method. This method is passed the username and password that were entered. Listing 13.3 frmHowTo13_3.vb: Web Method to Validate Username and Password Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click Dim wsSec As localhost.SecurityServices wsSec = New localhost.SecurityServices() Page 532 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html If wsSec.TestUserPassword(Me.txtUser.Text, Me.txtPassword.Text) Then MessageBox.Show("You may go into the applcation.") Else MessageBox.Show("You may not go into the application.") End If End Sub Figure 13.13. This login form takes advantage of a Web Service for authentication. Comment Note that passing parameters and using the return value is just like using methods from other objects or even functions from your own applications. [ Team LiB ] Page 533 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] 13.4 Pass a Dataset Back from an XML Web Service I want to be able to get more data than just a single value. How do I retrieve a whole dataset from a Web Service? Technique When you need to pass back a record or multiple records from a Web Service, you have to pass it back as a DataSet object, rather than a DataTable object. For this How-To, you will pass back the record of the user who is requested. Before returning the record, however, the code removes the Password column. You don't particularly want that information going out over the Net(see Listing 13.4). Listing 13.4 SecurityServices.asmx.vb: Passing Back a DataSet Object Public Function GetUserInfo(ByVal strUserID As String) As DataSet Dim ocnn As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & _ "Data Source=E:\InetPub\wwwroot\SecurityWebService\WebServiceSecurity.MDB") Dim odaUsers As New _ OleDb.OleDbDataAdapter("Select * from tblUsers Where UserID = '" & strUserID & "'", ocnn) Dim dsUsers As New DataSet() odaUsers.Fill(dsUsers) '-- remove the password column dsUsers.Tables(0).Columns.Remove("Password") Return dsUsers End Function Note Although you could limit the SELECT string to only return the necessary columns, and not have to delete the Password column, there are two reasons for coding it the way it was done. 1. It shows how to delete columns from a data table. 2. If the goal is to include all the columns in the table and accept the Password column, then when other columns are added, you will not have to touch the code because the * is being used. Tip When referring to tables on the receiving end, as displayed in step 2 of this How-To, you have to refer to tables in the dataset by their ordinal values. Therefore, some information in the description of the Web Service method about the dataset might be warranted. Page 534 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Steps To preview this How-To, open the solution called Visual Basic .NET Chapter 13, found in this chapter's folder. On the main form, click on the button labeled How-To 13.4. The form for How-To 13.4 then opens. If you type FSBarker for the User and Test for the Password, you can see the user's information listed in the DataGrid object (see Figure 13.14). Otherwise, a message box appears saying that you cannot see the data. 1. Open the SecurityWebServices Web Service project you created in How-To 13.2. Add the code from Listing 13.4 in the "Technique" section to create the GetUserInfo method. Test the new Web method. When you do so, you will see some XML, as shown here in Listing 13.5. Listing 13.5 Dataset Sent Back as XML - - - - - - - - - - - FSBarkerF. Scott Barker3
Page 535 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html
2. Open the Windows Project where you created the Login windows Form. Create a new Windows Form and place the controls shown in Table 13.2 in the order displayed in Figure 13.14. Table 13.2. Label, TextBox, DataGrid, and Command Button Control Property Settings Object Property Setting Label TextBox Label TextBox DataGrid Button 3. Text Name Text Name Name Name User txtUser Password txtPassword dgUserInfo btnLogin Add the code in Listing 13.6 to the Click event of btnLogin. This code once again checks the username and password by calling the TestUserMethod of the Web Service. If the username and password check out, then the GetUserInfo method is called, passing the username once again. The first table from the returned dataset is assigned to the DataSource property of dgUsers. Listing 13.6 frmHowTo13_4.vb: Retrieving a Dataset from a Web Service Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click Dim wsSec As localhost.SecurityServices wsSec = New localhost.SecurityServices() If wsSec.TestUserPassword(Me.txtUser.Text, Me.txtPassword.Text) Then dgUserInfo.DataSource = wsSec.GetUserInfo(Me.txtUser.Text).Tables(0) Else MessageBox.Show("No information may be presented.") End If End Sub Figure 13.14. The information in the data grid was retrieved from a Web Service. Page 536 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Comments You can use Web Services in literally thousands of ways. This chapter just covers a couple, but it should be enough to start you down the path of using them productively. [ Team LiB ] Page 537 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Appendix A. Desktop Development With ADO You will learn about the following in this appendix:         When to use ADO (local database/single-tier applications) Looking at the ADO Object Models Using the Connection object Working with the ADO Recordset object Executing a SQL Server stored procedure by using ActiveX Data Objects Executing batch updates with ADO and SQL Server Creating SQL Server objects with ActiveX Data Objects Perform a transaction using ActiveX Data Objects Although it's true that in the .NET environment, you will want to use ADO.NET for the majority of your development, developers have invested a lot of time and money into ActiveX Data Objects (ADO), and you might want to use it for desktop applications. [ Team LiB ] Page 538 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] When to Use ADO (Local Database/Single Tier Applications) ADO was Microsoft's last data-access method, and it is now the standard for most Office, Web, and Visual Basic environments prior to .NET. The following products ship ADO in the box:    Microsoft Office 200x Visual Studio 6.0 (including all the languages in the box) SQL Server 7.0, 2000 Data Access Objects (DAO), the standard prior to even ADO, was used throughout Office and Visual Basic, but it wasn't designed to be used with Web environments such as Visual InterDev and other data servers. Currently, no plan is underway to update DAO beyond DAO 3.6, which includes support for Unicode and some bug fixes, but doesn't have any other new features included beyond 3.5. [ Team LiB ] Page 539 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Looking At the ADO Object Models That's right, object models, plural. Unlike DAO, which consists of one object model, ADO has several separate object models. Note With ADO.NET, you use Namespaces and classes rather than references and object models. Although this takes some getting used to, it isn't too bad after a while. ADO's object models work together to give you the objects and collections that are necessary to work with your data. A couple of the object models consist of the following:  ActiveX Data Objects 2.7 (ADODB) allows you to create and work with recordsets, as well as perform error handling.  ADO Extensions 2.7 for DDL and Security (ADOX) is the data definition language, allowing you to work with and modify the database schema. Security objects are also included in this object model. Although these are separate object models and will be explained as such, you will also use them cohesively. For instance, to modify the table's structure, you need to get to the Tables collection located off the Catalog object in the ADOX library; however, this Catalog will have its ActiveConnection property set to the Connection object (ADODB). Take a look at what makes up the individual object models. The ActiveX Data Objects 2.7 (ADODB) Object Model The ActiveX Data Objects object model (see Figure A.1) consists of the following:  Connection object. Equivalent to the Database object in DAO, this is where most of your work with ADO begins. All the objects and collections that are mentioned after this come from the Connection object.  Errors collection/Error object. Identical to the DAO errors collection and error object, this allows developers to manage error handling.  Command object. This allows you to run a query against a database and return records in a Recordset object, to manipulate a database's structure, and to execute a bulk operation. A collection of parameters is used with the Command object. Recordset object. Similar to the DAO Recordset object, you can open the Recordset objects as read-only or dynamic. Each Recordset object also has a Fields collection. Stream object. This object allows you to read in special tree-structured hierarchies, such as e-mail messages or file systems. You can even point the object to an URL, provided the system has set it up in a consistent manner. This is another way that ADO allows developers to read outside data, such as from other applications or over the Internet. You   Page 540 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html could not do this easily with DAO. Figure A.1. The object model for ActiveX Data Objects 2.7. Most of the work is done in the ADODB module when you use ADO. Whenever you use recordsets, this is also the object model to use. [ Team LiB ] Page 541 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Referencing the Type Libraries Before seeing how to use these collections and objects, you need to know how to reference the object model libraries for use. The object models are found in type libraries in the file system. A type library contains the information about the object models such as the collections, properties, and methods. Referencing the type libraries isn't difficult, but it is still very important. Because Visual Basic .NET uses ADO.NET by default, you will have to reference all the object models you are going to need. To reference the object models, choose Add Reference from Visual Studio .NET's Project menu. After you're in the Add Reference dialog box, click on the COM tab. You then have to find the type libraries for the object models and select them. The type library name that you will be using is as follows: Microsoft ActiveX Data Objects 2.7 Library. This is also referred to as the ADODB object model. You can see this library, as well as other Microsoft ActiveX Data Objects Libraries, in Figure A.2. Figure A.2. Registering the COM type libraries. Tip You can use both ADO libraries and ADO.NET classes in the same application without worrying about the order of libraries in the references. This is great when you're converting applications from ADO to ADO.NET. To use all libraries and not worry about the order of reference, you must prefix your objects with the library with which they come. Here are some examples, with the specific library types: Dim odaTest as OLEDB.OLEDBDataAdapter Dim rstTestADO as ADODB.Recordset Dim catTest as ADOX.Catalog Page 542 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Although not all objects are shared between the libraries, it's a good idea to specify the library while you're getting used to the objects. After the library has been selected, you can see the ADODB reference entry in the Solution Explorer under references. [ Team LiB ] Page 543 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Using the Connection Object As with ADO.NET, you will be using the Connection object to set up a connection to the database of your choice. As you get started looking at the different examples, take a look at the main form that will be used to launch each of them, shown in Figure A.3. Figure A.3. This form, called frmMain, is the Main form that is used for the examples in this Appendix. The button that is used for this example is called btnOpenConn, and the following is the code used for the Click event, shown here in Listing A.1. Listing A.1 frmMain.vb: Code for Calling the Routine to Open and Display the ADO Connection Private Sub btnOpenConn_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnOpenConn.Click OpenAndDisplayADOConnection(Me.txtCurrentResults) End Sub Each of the buttons calls examples, passing the text box called txtCurrentResults. This text box is located at the bottom of the form. For clarity, the examples have been grouped in modules by section. In this case, the first example routine, called OpenAndDisplayADOConnection, can be found in basConnectionExamples.vb. The code for this routine is shown in Listing A.2. Listing A.2 basConnectionExamples.vb: Code for Opening and Displaying the ADO Connection Sub OpenAndDisplayADOConnection(ByVal txtResults As TextBox) Page 544 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Dim cnnNet As New ADODB.Connection() Dim strConnect As String = _ "Provider=SQLOLEDB.1;Integrated Security=SSPI;" & "Persist Security Info=False;Initial Catalog=Northwind;Data Source=(local)" cnnNet.Open(strConnect) txtResults.Text = "New connection string : " & _ vbCrLf & vbCrLf & cnnNet.ConnectionString cnnNet.Close() End Sub As you can see from this example, using the ADO Connection object is virtually the same as ADO.NET. You can see this example being executed in Figure A.4. Figure A.4. The text displayed here is the connection string that was set. Listing A.3 provides two other examples of using the connection object, also found in basConnectionExamples.vb. The first is code to open a connection to a Jet database by using a workgroup file, username, and password. The second is to open a Jet version of the Northwind database. Listing A.3 basConnectionExamples.vb: Two Examples of Opening Jet Databases Sub DisplayProviderAndSecuredAccessDB(ByVal txtResults As TextBox) Dim cnnNet As New ADODB.Connection() cnnNet.Provider = "Microsoft.Jet.OLEDB.4.0" cnnNet.Properties("Jet OLEDB:System database").Value = _ Page 545 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html "c:\Books\VBNETHowTo\Examples\AppA\MySystem.mdw" cnnNet.Open("Data Source=c:\Books\VBNETHowTo\Examples\AppA\MyMDB.mdb;" & "User Id=Admin;Password=MyPW") txtResults.Text = cnnNet.ConnectionString End Sub Sub OpenNorthwindADOConnection(ByRef cnnCurr As ADODB.Connection) Dim strConnect As String = "Provider=SQLOLEDB.1;Integrated Security=SSPI;" & "Persist Security Info=False;Initial Catalog=Northwind;Data Source=(local)" Try cnnCurr.Open(strConnect) Catch expADO As Exception MessageBox.Show("The following error occurred: " & expADO.Message) End Try End Sub In the last routine, you can also see how to use the Try…Catch…End Try block to trap any exceptions that might occur. Next you will see how to use the Connection object with the Recordset object in VB .NET. [ Team LiB ] Page 546 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Working with the ADO Recordset Object The central object in the ADODB object model is the Recordset object. You will be using this object when you want to manipulate records one at a time or bring back a set of records with which to work. With ADO, when you declare the type of variable you are going to use, you can instantiate it at the same time with the New keyword. Displaying Records by Using GetString For debugging purposes, you can also dump the whole recordset into a string variable for display. Listing A.4 shows you how to do this. Listing A.4 basRecordsetExamples.vb: Opening and Retrieving a Recordset for Display Sub OpenRecordsetWithGetStringDisplayExample(ByVal txtResults As TextBox) Dim cnn As New ADODB.Connection() Dim rstCurr As New ADODB.Recordset() OpenNorthwindADOConnection(cnn) rstCurr.Open("Select * from Orders where OrderDate = '06/12/97'", cnn, ADODB.CursorTypeEnum.adOpenForwardOnly) txtResults.Text = rstCurr.GetString rstCurr.Close() End Sub Using the OpenNorthwindADOConnection subroutine listing in Listing A.3, a connection object is referenced, and that is passed to the Open method of a Recordset object. Tip Notice that the cursor type returned will be ADODB.CursorTypeEnum.adOpenForwardOnly. Because all that is happening is the data being dumped to a string, using this cursor type makes sense. This will give you the best performance. Some other choices include adOpenDynamic, adOpenKeyset, adOpenStatic, and adOpenUnspecified. You can run this example by clicking on the button labeled Open a Recordset with GetString Display on the main form. Figure A.5 shows what you will see. Figure A.5. The GetString method is handy for checking out data. Page 547 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Editing and Updating Records You can use several methods to perform editing and updating of records in code. Unlike the last section in which you could open the recordset as a Forward Only type cursor, you will want to open it as a Dynamic type cursor. You can see this in Listing A.5. Listing A.5 basRecordsetExamples.vb: Opening and Retrieving a Recordset for Display Sub OpenRecordsetWithEditingExample(ByVal txtResults As TextBox) Dim Dim Dim Dim cnn As New rstCurr As fldCurr As strTemp As ADODB.Connection() New ADODB.Recordset() ADODB.Field String OpenNorthwindADOConnection(cnn) rstCurr.Open("Select * from Orders where OrderDate = '06/12/97'", cnn, ADODB.CursorTypeEnum.adOpenDynamic, _ ADODB.LockTypeEnum.adLockOptimistic) With rstCurr Do Until .EOF strTemp = strTemp & " Old Field Value: " & _ .Fields("ShippedDate").Value '-- Updating the release date .Fields("ShippedDate").Value = DateAdd(DateInterval.Day, 5, _ .Fields("ShippedDate").Value) Page 548 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html .Update() strTemp = strTemp & " New Field Value: " & _ .Fields("ShippedDate").Value & vbCrLf .MoveNext() Loop End With txtResults.Text = strTemp rstCurr.Close() End Sub You can see that the Update method is used after assigning the value that you want to the field you specify. You could have specified other fields to be updated as well. Note Notice that when updating individual fields in the recordset, the Value property is specified to be updated. You didn't have to do this in VB 6.0 or VBA, but .NET doesn't allow for default properties, which the Value property is. You don't have to explicitly use an Edit method; in fact, you won't find one like you could in previous editions. To add a new record, you must use the AddNew method before updating field values. To delete a record, you use the Delete method. One last thing to discuss about recordsets is how to persist, or save a recordset to disk. Persisting a Recordset This example will open up two recordsets: one from the Orders table, and one from a file created from the Orders table called OrdersForDate.rst. The code, shown in Listing A.6, opens the Orders table for a specific date and uses the GetString method to stash the contents to the results text box. The routine then saves that recordset using the Save method, and passes the adPersistADTG format enumerator. You could save the recordset as XML by using adPersistXML. The code opens the file into a recordset and prints it by saving it to the results TextBox control. Listing A.6 basRecordsetExamples.vb: Persisting a Recordset to Disk Sub PersistingARecordset(ByVal txtResults As TextBox) Dim cnn As New ADODB.Connection() Dim rstOrig As New ADODB.Recordset() Dim rstPersist As New ADODB.Recordset() Const adCmdFile As Long = 256 OpenNorthwindADOConnection(cnn) Page 549 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html '-disk. rstOrig.Open("Select * from Orders where OrderDate = '06/12/97'", cnn, ADODB.CursorTypeEnum.adOpenStatic) txtResults.Text = "Original Records : " & vbCrLf & rstOrig.GetString '-- Delete any existing old copies. ' If you don't, you will get an error. On Error Resume Next Kill("OrdersForDate.rst") '-- Create the persistent recordset in the applications directory On Error GoTo 0 rstOrig.Save("OrdersForDate.rst", ADODB.PersistFormatEnum.adPersistADTG) cnn = Nothing rstOrig = Nothing ' Open the persisted recordset rstPersist.Open("OrdersForDate.rst", Options:=adCmdFile) txtResults.Text = txtResults.Text & vbCrLf & vbCrLf & _ "Persisted File : " & vbCrLf & rstPersist.GetString rstPersist.Close() End Sub That's all there is to it. You will find that you can do most other things with recordsets using VB .NET that you have been able to do in other languages. Now take a look at another common task that you must do if you are using ADO with Visual Basic .NET: calling stored procedures. Open forward only and readonly since we are just saving it to [ Team LiB ] Page 550 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Executing a SQL Server Stored Procedure By Using ActiveX Data Objects If you are doing an ADO development with client server for backends, then you probably call stored procedures. In doing so, you will use the ADO Command object, as well as the Parameter object if you are passing parameters. You will create a Command object and supply the command text, which in this case will be the name of the stored procedure, called CustOrdersHist. You can see the T-SQL for CustOrderHist in Listing A.7. This stored procedure returns product names and the total quantity purchased of those products for a given customer. Listing A.7 Northwind SQL Server Database: T-SQL for the Stored Procedure Called CustOrdersHist ALTER PROCEDURE CustOrderHist @CustomerID nchar(5) AS SELECT ProductName, Total=SUM(Quantity) FROM Products P, [Order Details] OD, Orders O, Customers C WHERE C.CustomerID = @CustomerID AND C.CustomerID = O.CustomerID AND O.OrderID = OD.OrderID AND _ OD.ProductID = P.ProductID GROUP BY ProductName You will then specify the type of Command object you are creating of ADODB.CommandTypeEnum.adCmdStoredProc. in this case by using the type The next step is to create a parameter that the Command object will use. This parameter will match the one specified in CustOrdersHist, called CustomerID. You can see the actual code for this routine, called UseAStoredProcedureWithAParameter, in Listing A.8. Listing A.8 basCommandExamples.vb: Calling a Stored Procedure By Using Parameters Sub UseAStoredProcedureWithAParameter(ByVal txtResults As TextBox) Dim Dim Dim Dim Try cmd.CommandText = "CustOrderHist" cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc prm = cmd.CreateParameter("CustomerID", ADODB.DataTypeEnum.adChar, ADODB.ParameterDirectionEnum.adParamInput, 5) cmd.Parameters.Append(prm) prm.Value = "CHOPS" OpenNorthwindADOConnection(cnn) cmd.ActiveConnection = cnn rstCurr.Open(cmd) txtResults.Text = rstCurr.GetString cnn As New ADODB.Connection() rstCurr As New ADODB.Recordset() cmd As New ADODB.Command() prm As ADODB.Parameter Page 551 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Catch excp As Exception MessageBox.Show(excp.Message) End Try End Sub The last thing that this routine does is open a recordset based on the Command object. This is to the use just those records that are needed. In this case, the GetString method is used to assign it to the results text box. If you are using a bulk query, shown in the next section, you would use the Execute method. To see the routine in A.8 executed, click on the button with the caption Stored Procedure with Parameter, located on the frmMain form for this Appendix project. [ Team LiB ] Page 552 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Executing Batch Updates with ADO and SQL Server The biggest difference between this section and the previous one is the fact that in the last section, a recordset being populated using a Command object. With the Command object, no data was affected. That is one type of use for a Command object. What if you want to perform bulk tasks against a recordset? This is the major use for using the Command object because you don't necessarily need it for populating a recordset. The Parameter object is also not used. It was not necessary for the example, although you would want to use it if criteria were being implemented. To learn how to perform a bulk operation using ADO in Visual Basic .NET, see this simple Update SQL statement, shown here: Update Orders Set ShippedDate = DeliveryDate+1 This statement adds a day to the date in the ShippedDate column for all the records in the Orders table. This statement is being assigned to the CommandText property of the Command object instead of to the name of a stored procedure. Another important task is setting the CommandType property to be ADODB.CommandTypeEnum.adCmdText. This tells ADO that you are performing a bulk operation. Last, the Execute method is called from the Command object. This routine, called ExecuteABatchCommand, can be seen in Listing A.9. Listing A.9 basCommandExamples.vb: Creating and Executing a Bulk Query Sub ExecuteABatchCommand(ByVal txtResults As TextBox) Dim Dim Dim Dim Dim cnn As cmd As prm As rstOld rstNew New ADODB.Connection() New ADODB.Command() ADODB.Parameter As New ADODB.Recordset() As New ADODB.Recordset() '-- In .NET, we can assign values as we declare variables Dim strSQL As String = "Update Orders Set ShippedDate = ShippedDate+1" Dim strDispSQL As String = _ "Select OrderID, ShippedDate From Orders Where OrderID < 10251" '-- Open the connection OpenNorthwindADOConnection(cnn) '-- Open the Orders table and display the ShippedDate as they were. rstOld.Open(strDispSQL, cnn) txtResults.Text = "Old Values: " & vbCrLf & vbCrLf & rstOld.GetString '-- Set up the Command object to use the SQL string. cmd.ActiveConnection = cnn cmd.CommandText = strSQL cmd.CommandType = ADODB.CommandTypeEnum.adCmdText '-- Execute the command cmd.Execute() '-- Reopen the Orders table and redisplay the ShippedDate Field Page 553 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html rstNew.Open(strDispSQL, cnn) txtResults.Text = txtResults.Text & vbCrLf & vbCrLf & "New Values: " & vbCrLf & vbCrLf & rstNew.GetString End Sub For this example recordset, objects were used merely to display the before and after data, as seen in Figure A.6. Figure A.6. Although they're not pretty, you can see the values of the OrderID and DeliveryDate before and after the routine has been executed. You can also use the Insert and Delete statements to perform other bulk operations with the Command object. One of the last tasks that is useful to perform using ADO with SQL Server is to create objects such as tables on-the-fly. [ Team LiB ] Page 554 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Creating SQL Server Objects with ActiveX Data Objects It is worthwhile to mention an example of creating a new table object with fields and primary key specified, even though the majority of the work of creating objects using ADO and SQL Server is done in the T-SQL Statement that you create. You will execute this statement using the Command object, as shown in Listing A.10. Listing A.10 basStoredProcedureExamples.vb: Creating SQL Server Objects with ADO and T-SQL Sub CreatingASQLServerObjectFromADO(ByVal txtResults As TextBox) Dim Dim Dim Dim Dim cnn As cmd As prm As rstOld rstNew New ADODB.Connection() New ADODB.Command() ADODB.Parameter As New ADODB.Recordset() As New ADODB.Recordset() '-- In .NET, we can assign values as we declare variables. ' This is where the hard work is. Dim strSQL As String = "CREATE TABLE Test (PrimaryIntFld Integer IDENTITY(1,1) PRIMARY KEY, Field2 Text)" '-- Open the connection OpenNorthwindADOConnection(cnn) '-- Set up the Command object to use the SQL string. cmd.ActiveConnection = cnn cmd.CommandText = strSQL cmd.CommandType = ADODB.CommandTypeEnum.adCmdText '-- Execute the command cmd.Execute() End Sub This routine is a lot like the previous example except for the SQL statement and the fact that results aren't displayed. You can see the results by going to the Visual Studio .NET Server Explorer, zeroing in on the tables for the Northwind database, and opening the new Test table in Design mode, as shown in Figure A.7. Figure A.7. Creating objects such as this table is just a matter of learning the correct SQL syntax. Page 555 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Note If you already had the tables displayed for Northwind, you might need to right-click on the Tables node and choose Refresh. [ Team LiB ] Page 556 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] Conclusion Well, there you have it. As you can see, you can use ADO in Visual Basic .NET under the covers in basically the same way that you did in prior versions of VB. Just as a parting word of advice for this Appendix: Convert as much of your code to take advantage of ADO .NET as possible. However, if you have several developers and need to crank out a simple application with Visual Basic .NET in a hurry, ADO is still available. [ Team LiB ] Page 557 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F] [G] [H] [I] [J] [K] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] [ Team LiB ] Page 558 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] "" (double quotation marks) # (number sign) % (percent sign) & (ampersand) variables, declaring > (right arrow button) < (left arrow button) *.asmx file extension + (plus sign) - (minus sign) 2nd 2nd .NET namespaces XML (Extensible Markup Language) System.XML namespace System.XML.Schema namespace System.XML.Xpath namespace System.XML.XSL namespace 2nd XML (Extensible Markup Language) .NET Framework Developer's Guide 2nd .NET namespaces bound list boxes, creating 2nd 3rd 4th 5th .vb file extension .xsd file extension ? (question mark) @ (at symbol) parameters 2nd [ ] (square brackets) ^ (caret) _ (underscore) 1stBackupDevices list box populating (code) 2nd 3rd 4th 1stC ustomers Click event, code 1stDatabases list box populating (code) 2nd 3rd 4th 5th 1stLookUpTables Items collection data, adding 1stLookupTables pointing to items (code) 2nd 1stUnSelected list box reloading code 1stUnselected list box reloading code 3621 error [ Team LiB ] Page 559 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] abstract classes AcceptChanges method access (Public) modifiers 2nd 2nd access levels deny (object permissions) grant (object permissions) revoke (object permissions) accessing command buttons on forms CommandText property libraries 2nd 2nd accounts database users, creating 2nd 3rd 4th 5th 6th Windows NT/2000 disabled 2nd Action menu commands New Group Properties Action property actions execution on forms 2nd Actions menu commands New Login ActivateEditing routine creating (code) 2nd ActiveEditing frmHowTo1_4.vb SaveRecord routing, calling (code) text boxes, disabling (code) 2nd 2nd ActiveEditing subroutine calling (code) 2nd ActiveX Data Objects 2.7 (ADODB) ActiveX Data Objects 2.7 object model (ADODB) 2nd 3rd ActiveX Data Objects. adapters. [See ADO]2nd [See ADO] [See also data adapters]2nd [See also data adapters] Add button clicking, effects Add Class command (Add menu) Add Members dialog box 2nd Add menu commands Add Class Add New Item Add method Add New Item command (Add menu) Add New User dialog box 2nd 3rd 2nd 2nd Add Reference command (Project menu) dialog box Add Reference command (Project menu) Add Role Members dialog box Add Table dialog box Add to DataTable button 2nd 3rd 2nd Page 560 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Add Web Reference command (Project menu) adding buttons to DataGrid control 2nd 3rd 4th data in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th to Items collection data to lookup tables 2nd 2nd lookup table information methods to interfaces 2nd 3rd 4th properties to interfaces 2nd records 2nd 3rd 4th 5th 6th 7th 8th 9th 10th buttons canceling in DataGrid object (code) to data tables (code) 2nd 2nd 3rd 4th 5th rows in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th AddNew method 2nd AddObjectForTransfer method Administrative Tools groups and users, adding ADO 2nd (ActiveX Data Objects) 2nd ADODB (ActiveX Data Objects 2.7 object model) 2nd 3rd and ADO.NET, comparing 2nd 3rd batch updates, executing Connection object 2nd 3rd 4th 5th 2nd 3rd 4th 5th connections opening and displaying (code) local databases 2nd 2nd Microsoft Office 200x object models 2nd OLE DB data provider choosing 2nd Recordset object records, displaying 2nd 3rd records, editing 2nd 3rd 4th records, updating 2nd 3rd 4th recordsets, persisting 2nd 3rd 4th single tier applications 2nd SQL Server 2000 SQL Server 7.0 SQL Server objects, creating 2nd 3rd 4th SQL Server stored procedures, executing 2nd 3rd 4th type libraries, referencing 2nd 3rd Visual Studio 6.0 ADO 2.x cursors ADO Extensions 2.7 for DDL and Security (ADOX) ADO.NET 2nd and ADO (ActiveX Data Objects), comparing 2nd 3rd batch updates on-the-fly, creating on-the-fly, executing objects 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th 7th 8th 9th Page 561 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html stored procedures parameterized, executing 2nd 3rd 4th 5th 6th 7th 8th Windows forms objects, using in Web forms ADO.NET code writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th SQL (auto-generated) strongly typed datasets XSDs 2nd 3rd ADO.NET. 2nd 3rd 2nd 3rd [See also DataSet object] ADODB (ActiveX Data Objects 2.7) ADODB (ActiveX Data Objects 2.7 object model) 2nd 3rd ADODB.CursorTypeEnum.adOpenForwardOnly cursor type ADOX (ADO Extensions 2.7 for DDL and Security) Advanced Options button Alfred's Fried Foods Alias property ALL clause Allow Nulls Allow Nulls property ALTER TABLE statement 2nd ampersand ( & ) variables, declaring Anchor property APIs DMF (Distributed Management Framework) references, setting 2nd 3rd 2nd 3rd SQL-DMO objects 2nd AppendChild (XMLElement class) AppendChild (XMLNode class) applets Windows NT/2000 C ontrol Panel groups and users, adding Application object methods properties Application Role button application roles (SQL Server security) 2nd 3rd 4th 5th ApplicationException applications assemblies desktop (VB .NET) generic search forms, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th exceptions single tier ADO (ActiveX Data Objects) 2nd states Web (ASP.NET) generic search forms, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd arrow buttons (right and left) ASP.NET Web applications Page 562 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html generic search forms, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd Web Forms developing Windows forms objects, using in Web forms ASP.NET Web Service templates 2nd 3rd assemblies assigning reports with ReportDocument 2nd UDFs (user-defined functions) code 2nd variables syntax assigning values text boxes code 2nd at symbol (@) parameters 2nd Attach Database button AttachDBWithSingleFile method 2nd attaching database file, code 2nd files to databases 2nd routines to SelectedIndexChanged event SQL Server databases code 2nd AttributeCount method attributes AutoEventWireUp 2nd authentication login forms XML Web Services mixed-mode 2nd 3rd 4th 5th authentication mode SQL Server Enterprise Manager Windows NT/2000 AUTO mode 2nd 3rd 4th 5th 6th 7th 8th auto-generated SQL VB .NET tools, writing ADO.NET code 2nd 3rd AutoEventWireUp attribute 2nd AutoIncrement property AutoPostBack property [ Tea m LiB ] Page 563 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] backing up databases with SQL-DMO SQL databases SQL Server databases 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th BACKUP DATABASE statement backup devices 1stBackupDevices list box populating (code) 2nd 3rd 4th names, retrieving (code) BACKUP LOG statement Backup object methods properties Backup/Restore Wizard 2nd BackupDevice object methods properties BackupDevices object methods properties backups performing (code) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th basC ommandExamples.vb bulk queries, creating and executing (code) stored procedures, calling (code) 2nd 3rd 2nd basC onnectionExamples.vb ADO connections opening and displaying (code) JET databases opening (code) 2nd basRecordsetExamples.vb recordsets opening and retrieving (code) persisting to disks (code) 2nd 2nd 3rd 4th basStoredProcedureesExamples.vb SQL Server objects, creating (code) batch updates executing 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th on-the-fly, creating in ADO.NET on-the-fly, executing in ADO.NET BEGIN statement BeginEdit method BeginLoadData method behavior of Crystal Report Viewer, controlling 2nd behaviorial control of classes 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th BETWEEN operator syntax 2nd BETWEEN statement data, generating (code) bigint data type (SQL Server) 2nd Page 564 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html binary data type (SQL Server) BinderContext class binding columns to controls properties 2nd data to ComboBox control 2nd 3rd 4th 5th 6th 7th 8th 9th to DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th data grids to DataView control (code) data tables code 2nd 3rd 4th 5th 6th 7th 8th DataSet control with ListBox control properties 2nd filling and binding products to DataGrid object (code) text boxes 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd 2nd 2nd to datasets to list boxes BindingContext object BindingManagerBase object BindingManagerBase objects BindTheGrid routine 2nd bit data type (SQL Server) blocks If[ellipsis dots] Then code 2nd Try[ellipsis dots]C atch[ellipsis dots]End Catch statements Try[ellipsis dots]C atch[ellipsis dots]End Try controls, ignoring exceptions, trapping Try[ellipsis dots]Catch[ellipsis dots]Finally exceptions 2nd blue wavy lines (code) BorderColor property borders Red/Blue style 2nd BottomLineStyle property bound contols on Web Forms at runtime 2nd bound controls at runtime 2nd data editing and updating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th error handling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th on Web Forms 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th AutoPostBack property DataBind method IsPostBack property 2nd Web server and HTML controls, comparing 2nd records adding and deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Windows forms bound list boxes, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th bound list boxes, displaying data data bound forms 2nd 3rd 4th 5th 6th 7th 2nd 3rd 4th 5th 6th 7th 8th 9th data, binding to controls 2nd 3rd 4th 5th 6th 7th 8th 9th Page 565 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html data, editing and updating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th DataGrid control, drilling down to data 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th developing 2nd error handling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th records, adding and deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th text boxes, binding and viewing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th bound list boxes creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th data displaying 2nd 3rd 4th 5th 6th 7th boxes bound list creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th data, displaying 2nd 3rd 4th 5th 6th 7th list text boxes, binding and viewing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th message displaying text binding and viewing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th boxes. text boxes [See also list boxes] brackets square ([ ]) break points setting in stored procedures 2nd Web pages browsers Object Browser btnAccept button click event code 2nd btnAdd Click event, code 2nd 3rd btnAdd button click event code Click event, code 2nd 3rd btnAttach button click event code btnBackup button click event code btnC ancel Click event, code 2nd btnC ancel button click event code 2nd btnC lose button click event code 2nd 3rd btnC onnect button click event code btnC onnection button Page 566 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html disabling (code) enabling (code) 2nd 2nd btnC reateTable click event PerformTask( ) function, calling (code) btnC reateUDF click event code btnC reateXMLFile button Click event, code 2nd 3rd btnDelete Click event, code btnDelete button enabled properties, toggling (code) 2nd 3rd 4th 5th 2nd btnDeleteTable click event PerformTask( ) function, calling (code) 2nd btnDetach button click event code toggling (code) btnEdit Click event, code btnEdit button enabled properties, toggling (code) 2nd 3rd 4th 5th btnEdit command button ActiveEditing subroutine, calling (code) 2nd btnExecute click event (code) Click event, code btnExport button click event code btnLoadList Click event, code btnLoadList button btnLocateFile button click event code btnLogin button Click event, code 2nd btnModifyTable click event PerformTask( ) function, calling (code) btnNew button 2nd btnOpenC onn button click event code btnPrint button click event code btnReadFile button Click event, code 2nd btnRestore button click event code btnRetrieve code btnRetrieveXML button Click event, code Page 567 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html btnSave Click event, code btnSave click event trapping save exceptions (code) 2nd btnSearch button click event code 2nd btnSelect button click event code 2nd btnTestValidator Click event, code btnTransfer button click event code btnUnSelect button click event code 2nd btnUpdate button click event code btnUseUDF click event code btnVerify button click event code btnView Click event, code 2nd btnView button click event code Build button BuildCnnStr function 2nd BuildCnnStr routine BuildCnnStr( ) function 2nd builders. 2nd [See also Query Builder] building SQL statements with Query Builder SQL strings code built-in functions T-SQL 2nd built-in stored procedures sp-tables testing 2nd bulk queries creating and executing code 2nd bulkadmin (fixed server role) business rules data constraints 2nd Button control properties 2nd 3rd 4th 5th 6th button controls click events, adding (code) Page 568 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Button object properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th buttons Add clicking, effects Add to DataTable 2nd 3rd adding to DataGrid control 2nd 3rd 4th Advanced Options Application Role arrow (right and left Attach Database btnAccept click event (code) 2nd btnAdd click event (code) Click event, code 2nd 3rd btnAttach click event (code) btnBackup click event (code) btnC ancel click event (code) 2nd btnC lose click event (code) 2nd 3rd btnC onnect click event (code) btnC onnection disabling (code) enabling (code) 2nd 2nd btnC reateXMLFile Click event, code btnDelete enabled properties, toggling (code) 2nd 3rd 4th 5th 2nd 3rd btnDetach click event (code) toggling (code) btnEdit enabled properties, toggling (code) 2nd 3rd 4th 5th btnEdit command ActiveEditing subroutine, calling (code) 2nd btnExport click event (code) btnLoadList btnLocateFile click event (code) btnLogin Click event, code btnNew 2nd btnOpenC onn click event (code) btnPrint click event (code) btnReadFile Click event, code 2nd Page 569 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html btnRestore click event (code) btnRetrieve code btnRetrieveXML Click event, code btnSearch click event (code) 2nd btnSelect click event (code) 2nd btnTransfer click event (code) btnUnSelect click event (code) 2nd btnUpdate click event (code) btnVerify click event (code) btnView click event (code) Build 2nd C ancel clicking, effects command accessing on forms 2nd 2nd data (to edit, save, or cancel) C ommand properties command properties C ommand properties properties, settings 2nd 3rd 4th C ommand Button control properties 2nd 3rd 4th 5th 6th 7th 8th property settings 2nd 3rd 4th 5th 6th 7th C ommand Button object properties 2nd 3rd 4th property C onnect enabling Create XML File 2nd 3rd DataGrid control events Delete Detach Edit Ellipsis events on data grids Execute Export Invoke 2nd 2nd 2nd ItemC ommand event Repeater control events, programming Label, TextBox, and C ommand control property settings 2nd Page 570 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label, TextBox, ListBox, and C ommand property settings 2nd Letter Button controls click events (code) 2nd Letter Button result sets, filling (code) 2nd 3rd 4th Load List 2nd 3rd Locate File New Connection Open a Recordset Perform Backup Permissions 2nd Print properties setting property settings 2nd PushButton 2nd Radio Button object properties rbDistinct Radio Button control Read XML File records adding deleting RegionID, displaying Run Query Save clicking, effects Search SQL Server Authentication Stored Procedure with Parameter Use Distinct Use UDF View Code 2nd [ Tea m LiB ] Page 571 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] calculated fields, adding to reports 2nd 3rd 4th 5th calling ActiveEditing subroutine code 2nd GenerateData routine code 2nd 3rd LoadProducts routine code PerformTask( ) function code 2nd 3rd RefreshIndividual routine code 2nd 3rd routines code 2nd 3rd 4th 5th 6th 7th 8th 9th SaveRecord routine code 2nd search forms 2nd stored procedures code 2nd 3rd UDFs (user-defined functions) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th XML Web Services methods 2nd calling pages, returning to (code) 2nd calls RefreshIndividual subroutine adding (code) 2nd C ancel button clicking, effects C ancel command code canceling edits code 2nd 2nd canceling changes to data, code canceling data command buttons 2nd canceling editing/adding records in DataGrid object (code) cancelling data grid edits (code) caret (^) Cascade Delete Related Records cascade deletes C atch statements in Try[ellipsis dots]Catch[ellipsis dots]End Try block catching exceptions (code) 2nd 3rd categories DropDown control loading (code) loading;code 2nd 3rd 4th Page 572 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html list boxes repopulating (code) 2nd loading into list boxes (code) 2nd 3rd 4th 5th C C ustomer class code 2nd constructors (code) 2nd mFax variable event handlers (code) property declarations (code) C C ustomerID class constructors code 2nd C C ustomerID.vb constructors (object-based), code constructors, code 2nd 3rd CustomerID property, code changes updating to servers (code) 2nd 3rd 4th chapters in book, source code (Web site) char data type (SQL Server) characters Unicode C hart tab Standard Report Wizard check boxes Create Columns Automatically at Run Time, checking Run Time Create Columns Automatically, unchecking Unassigned Products Only 2nd Unassigned Products Only check Users Must Enter a User Name and Password to Use This Computer 2nd C heckBox object properties 2nd property C heckC hanged event code 2nd child records cascade deletes Choose a Query Type page (DataAdapter Configuration Wizard) Choose Your Data Connection page (DataAdapter Configuration Wizard) Choose Your Data Connection pge (DataAdapter Configuration Wizard) class declarations MaximumStringLengthExceededException code classes abstract ADO.NET code, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th SQL (auto-generated) strongly typed datasets XSDs 2nd 3rd behavioral control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th BinderContext 2nd 3rd 2nd 3rd C C ustomer code 2nd constructors (code) 2nd Page 573 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html mFax variable event handlers (code) property declarations (code) C C ustomerID constructors (code) 2nd 3rd C NumberString code 2nd 3rd 4th international phone number extensions (code) code 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th creating to implement interfaces creation control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th C ustomer code data errors, communicating to developers 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th validating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th validation code, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th data providers 2nd default properties defining 2nd 3rd 4th 5th in interfaces definition diagrams 2nd inheritance permission keywords 2nd instances definition interfaces implementing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 2nd member override keywords members definition methods adding to interfaces 2nd 3rd MustInherit keyword objects definition OleDb performance improvement parameterized properties pointers properties 2nd 3rd 4th adding to interfaces read-only properties 2nd 2nd SQLC lient performance improvement 2nd variables declarations (code) write-only properties 2nd XMLDocument CreateComment CreateNode DocumentElement LoadXML methods 2nd properties 2nd Save Page 574 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XMLElement AppendChild XMLNode AppendChild methods 2nd properties 2nd XMLNodeReader XMLReader 2nd XMLTextReader XMLValidatingReader classes. [See also data providers] clauses ALL DISTINCT records, displaying 2nd C lear method code 2nd click events adding to button controls (code) btnAccept button code 2nd btnAdd button code btnAttach button code btnBackup button code btnC ancel button code 2nd btnC lose button code 2nd 3rd btnC onnect button code btnC reateTable click PerformTask( ) function, calling (code) 2nd btnC reateUDF code btnDeleteTable click PerformTask( ) function, calling (code) 2nd btnDetach button code btnExecute code btnExport button code btnLocateFile button code btnModifyTable click PerformTask( ) function, calling (code) 2nd btnOpenC onn button code btnPrint button code btnRestore button code btnSave Page 575 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html trapping save exceptions (code) 2nd btnSearch button code 2nd btnSelect button code 2nd btnTransfer button code btnUnSelect button code 2nd btnUpdate button code btnUseUDF code btnVerify button code btnView button code 2nd C lick events for 1stCustomers (code) for btnAdd (code) 2nd 3rd 2nd 3rd for btnAdd button (code) for btnCancel (code) 2nd for btnCreateXMLFile button (code) for btnDelete (code) for btnEdit (code) for btnExecute (code) for btnLoadList (code) for btnLogin button (code) 2nd 2nd 2nd 2nd 3rd for btnReadFile button (code) for btnRetrieveXML button (code) for btnSave (code) for btnTestValidator (code) for btnView (code) 2nd click events Letter Button controls code 2nd clicking Add button, effects Cancel button, effects Delete key, effects Save button, effects client-side cursors clients state management 2nd XML Web Services Description Close (XMLTextWriter) Close method closing forms code 2nd 3rd 2nd forms (code) C NumberString class code 2nd 3rd international phone number extensions (code) code 1stBackupDevices list box, populating 2nd 3rd 4th 5th 6th 7th 8th Page 576 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html 1stCustomers Click event 1stDatabases list box, populating 2nd 3rd 4th 5th 6th 1stLookupTables pointing to items 2nd 1stUnSelected list box reloading 1stUnselected list box reloading ActivateEditing routine creating 2nd 3rd ADO connections opening and displaying 2nd 3rd 4th ADO.NET, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th SQL (auto-generated) strongly typed datasets XSDs 2nd 3rd backup device names, retieving backups, performing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 2nd 3rd 2nd 3rd basC ommandExamples.vb bulk queries, creating and executing stored procedures, calling 2nd 3rd 2nd basC onnectionExamples.vb ADO connections, opening and displaying JET databases, opening 2nd basRecordsetExamples.vb recordsets, opening and retrieving 2nd 3rd 4th recordsets, persisting to disks 2nd basStoredProcedureesExamples.vb SQL Server objects, creating BEGIN statement btnAccept button click event 2nd btnAdd button click event btnAdd button Click event btnAdd Click event 2nd 3rd 2nd 3rd btnAttach button click event btnBackup button click event btnCancel button click event btnCancel Click event 2nd 2nd 3rd 2nd btnClose button click event btnConnect button click event btnC onnection button disabling 2nd enabling 2nd btnCreateUDF click event btnCreateXMLFile button Click event btnDelete Click event 2nd 2nd 3rd btnDetach button click event btnDetach button, toggling 2nd btnEdit Click event btnExecute Click event btnExecute click event btnExport button click event btnLoadList Click event btnLocateFile button click event btnLogin button Click event 2nd btnOpenConn button click event Page 577 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html btnPrint button click event btnReadFile button Click event btnRestore button click event btnRetrieve btnRetrieveXML button Click event btnSave Click event btnSearch button click event 2nd btnSelect button click event 2nd btnTestValidator Click event btnTransfer button click event btnUnSelect button click event 2nd btnUpdate button click event btnUseUDF click event btnVerify button click event btnView button click event 2nd btnView Click event 2nd 2nd bulk queries creating and executing 2nd button controls, adding click events calling pages, returning to 2nd Cancel command CCustomer class 2nd constructors 2nd 3rd property declarations C C ustomerID.vb constructors 2nd 3rd constructors (object-based) CustomerID property changes updating servers 2nd 3rd 4th CheckChanged event 2nd class variable declarations 2nd classes 2nd 3rd creating to implement interfaces default properties defining 2nd 3rd 4th 5th interfaces, implementing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th methods, adding to interfaces parameterized properties properties 2nd 3rd 4th properties, adding to interfaces read-only properties 2nd write-only properties 2nd Clear method 2nd 3rd CNumberString class 2nd 3rd 4th columns listing in databases 2nd 3rd 4th columns, sorting 2nd ComboBox control, adding column names ComboBox control, loading 2nd 3rd 2nd 3rd connection strings creating 2nd 3rd 4th 5th 6th 7th 8th 9th establishing 2nd connection strings, creating 2nd constructors for CCustomerID class 2nd 3rd 4th Page 578 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html inserting rows into tables 2nd object-based for CCustomerID class testing constructors, testing 2nd ContactName property Customer class 2nd 2nd customer information listing 2nd C ustomerData.vb DataAdapter Configuration Wizard 2nd 3rd SELECT command text Update command text CustomerID property 2nd 2nd 3rd C ustomerInterface.vb ICustomer interface, properties (code) C ustomerInterface9_1.vb delete method, declaring (code) ICustomer interface interfaces ReadOnly keyword save method, declaring (code) Customers XSD 2nd CustOrdersHist stored procedure, T-SQL 2nd data adding to data tables generating 2nd regenerating saving 2nd 2nd 3rd 4th data grids binding to DataView control edits, cancelling page indexes, updating paging through 2nd records, deleting 2nd 3rd 4th 5th 6th records, posting 2nd 3rd 4th 5th 6th setting to edit mode sorting 2nd updating 2nd data tables binding 2nd 3rd 4th 5th records, adding 2nd 3rd data tables, adding data data tables, binding data tables, loading 2nd 2nd 3rd 2nd 3rd DataAdapter Configuration Wizard 2nd 3rd 4th database files, finding and attaching 2nd database list boxes loading 2nd 3rd 4th database names, retrieving 2nd 3rd DataGrid control loading 2nd 3rd 4th 5th 6th DataGrid controls populating 2nd 3rd 4th 5th DataGrid object loading 2nd records, canceling editing/adding Page 579 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html special instructions 2nd DataSet object passing datasets loading 2nd retrieving from XML Web Services returning as XML 2nd 3rd DataTable object creating 2nd 3rd 4th tracking 2nd 3rd 4th 5th DataTable object, creating 2nd 2nd DataView object, setting RowFilter property default properties, declaring DefineValidC hars method declaring Delete command delete method declaring 2nd Delete method implementing testing detail pages hyperlinks 2nd DialogResult, setting 2nd 3rd DoesCustomerIDExist function DropDown control loading 2nd 3rd 4th 5th dsC ustomers.xsd Customers XSD 2nd Edit command edits canceling 2nd END statement event handlers 2nd for mFax variable events wiring for DataGrid control exception handling 2nd exceptions catching 2nd 3rd passing 2nd formatting UDFs (user-defined functions) 2nd forms closing 2nd 3rd 4th 5th loading 2nd 3rd opening 2nd 3rd 4th frmHowTo.vb constructors, testing frmHowTo1_1 data sets, filling frmHowTo1_2.vb 2nd frmHowTo1_3.vb dataset, refreshing 2nd RefreshIndividual routine, calling 2nd RefreshIndividual subroutine, adding calls 2nd Page 580 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmHowTo1_4.vb ActiveEditing subroutine, calling 2nd data, canceling changes data, saving to servers 2nd 2nd SaveRecord routine, calling 2nd text boxes, disabling text boxes, toggling 2nd 3rd 4th 2nd frmHowTo1_5.vb data, saving (code) 2nd 2nd dsCustomerIndividual dataset, adding records (code) edits, canceling (code) 2nd 2nd 3rd 2nd list boxes, reloading (code) mbAddNew variable, resetting (code) records, deleting (code) 2nd 3rd frmHowTo1_6.vb btnSave click event, trapping save exceptions (code) exceptions, catching 2nd 3rd exceptions, passing 2nd 2nd frmHowTo1_7.vb enabled properties of buttons, toggling forms, closing 2nd records, saving before closing 2nd 2nd 3rd 4th 5th frmHowTo1_8.vb DataGrid control, refreshing 2nd datasets, filling 2nd 3rd 4th frmHowTo1_9 forms;opening (code) 2nd frmHowTo1_9b datasets;loading (code) 2nd frmHowTo10_4.vb reports, exporting 2nd reports, printing frmHowTo10_5.vb Selection combo box, populating SelectionFormula property, setting 2nd 3rd frmHowTo13_3.vb passwords, validating (code) usernames, validating (code) frmHowTo13_4.vb datasets, retrieving from XML Web Services frmHowTo3_1.vb list boxes, loading 2nd 3rd frmHowTo3_2.vb list boxes, loading 2nd frmHowTo3_3.vb ComboBox control, loading records, locating 2nd text boxes, assigning values 2nd 2nd 3rd frmHowTo3_4.vb button controls, adding click events columns, sorting 2nd ComboBox control, adding column names data tables, loading 2nd 3rd 2nd 2nd 3rd DataView object, setting RowFilter property frmHowTo6_1.vb data, regenerating Page 581 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html forms, loading SQL strings, building frmHowTo6_2.vb SQL statements, storing and executing 2nd frmHowTo6_3.vb data, generating 2nd GenerateData routine, calling 2nd 3rd frmHowTo6_4.vb left outer joins frmHowTo6_6.vb PerformTask( ) function, calling (code) SQL statements, executing (code) SQL statements, loading (code) 2nd 2nd 3rd frmHowTo6_7.vb forms, loading (code) 2nd SQL statements, storing (code) 2nd frmHowTo6_8.vb UDFs (user-defined functions), assigning UDFs (user-defined functions), creating 2nd 2nd 3rd 4th 5th UDFs (user-defined functions), displaying data UDFs (user-defined functions), updating SELECT statement 2nd frmHowTo7_1.vb btnConnection button;disabling 2nd btnConnection button;enabling database list boxes, loading list boxes, repopulating routines, reloading list boxes 2nd routines;calling 2nd SQL Servers, loading 2nd 2nd 2nd 3rd 4th frmHowTo7_2.vb 1stBackupDevices list box, populating 1stDatabases list box, populating backups, performing (code) routines, loading SQL Servers routines;calling 2nd 3rd 4th 5th 6th 7th frmHowTo7_3.vb 1stBackupDevices list box, populating 1stDatabases list box, populating backups, performing (code) routines, calling SQL Servers, loading 2nd 3rd frmHowTo7_4.vb 1stBackupDevices list box, populating 2nd 1stDatabases list box, populating 2nd forms, closing routines, calling SQL Servers, loading tables, copying 2nd 3rd 4th 5th frmHowTo7_5.vb 1stDatabases list box, populating btnDetach button, toggling database files, finding and attaching forms, closing 2nd routines, calling SQL Server database, detaching SQL Server databases, attaching 2nd 2nd Page 582 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SQL Servers, loading frmHowTo8_1.vb 1stUnSelected list box, reloading list boxes, loading categories 2nd list boxes, populating 2nd 3rd 4th 5th 6th routines, calling servers, updating 2nd 3rd 4th 5th 6th frmHowTo8_2.vb 1stLookupTables, pointing to items connection strings, establishing 2nd DataGrid control, populating 2nd 3rd 4th 5th 2nd frmHowTo8_3.vb columns, listing in databases 2nd DataGrid control, loading SQL strings, creating 2nd stored procedures, executing 2nd 3rd 4th 5th tables, listing in databases 2nd 3rd frmHowTo8_4.vb search forms, creating custom properties 2nd stored procedures, executing tables, listing in databases frmHowTo8_4a.vb Letter Button result sets, filling 2nd records, loading into text boxes 2nd 3rd frmHowTo8_4b.vb DialogResult, setting 2nd key values, storing 2nd Letter Button controls, click events search forms, creating custom properties 2nd 3rd stored procedures, executing tables, listing in databases frmHowTo8_6.aspx data grids, deleting records 2nd 3rd 4th 5th 6th data grids, posting records 2nd 3rd 4th 5th 6th data grids, updating page indexes data tables, adding records 2nd 3rd DataGrid object, canceling editing/adding records DataGrid object, special instructions DataTable object;tracking 2nd 3rd 4th 5th frmHowTo8_7.vb columns, listing in databases 2nd DataGrid control, loading 2nd 3rd SQL strings;creating 2nd 3rd 4th stored procedures, executing 2nd 3rd 4th tables, listing in databases 2nd frmHowTo8_8a.vb Letter Button result sets, filling 2nd records, loading 2nd 3rd Session object, storing values frmHowTo8_8b.vb calling pages, returning to 2nd data grids;updating key values, storing 2nd Letter Button controls, click events stored procedures, executing tables, listing in databases Page 583 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmHowTo9_2.vb CCustomer class 2nd CCustomer class, property declarations class variable declarations Customer class TextBoxChange method, writing values in text boxees TextChanged event ToString method, property information output 2nd 2nd frmHowTo9_4.vb CCustomer class, constructors 2nd ReadValuesFromDataRow method 2nd frmHowTo9_5.vb Clear method 2nd constructors, inserting rows into tables constructors, testing Delete method, implementing Delete method, testing Save method, implementing Save method, testing WriteChangesToDB method 2nd 2nd 3rd 4th 5th frmHowTo9_6 ContactName property InvalidPhoneNumberException MaximumStringLengthExceededException;class declaration phone numbers, validating 2nd 3rd frmHowTo9_6.vb DoesCustomerIDExist function If[ellipsis dots] Then block InvalidCustomerIDException, declaring ValidateCustomerID method frmHowTo9_7.vb event handlers frmMain.vb ADO connections, opening and displaying forms;opening (code) routines, calling 2nd GenerateData routine calling 2nd 3rd 4th HTML repRegions Repeater control repTerritories Repeater control http[colon, no spaces]//localhost/WebService1/Service1.asmx?WSDL XML Web Services, SOAP definition (code) 2nd 3rd 4th 5th ICustomer interface properties If[ellipsis dots] Then block international phone number extensions InvalidC ustomerIDException declaring 2nd InvalidPhoneNumberException 2nd IsValid method declaring JET databases opening 2nd 3rd 2nd 3rd 4th key values, storing left outer joins 2nd Page 584 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Letter Button controls click events 2nd 3rd 4th Letter Button result sets, filling 2nd 3rd 4th list boxes categories, loading 2nd 3rd 4th 5th populating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th reloading 2nd 3rd 4th 5th list boxes, loading 2nd 3rd 4th 5th list boxes, repopulating Load event 2nd LoadIndividual routine creating 2nd 3rd LoadList routine creating 2nd LoadProducts routine calling lstSQLServers list box m (adding to) MaximumStringLengthExceededException class declaration mbAddNew variable resetting 2nd mdtProducts DataTable object rows, finding 2nd modGeneralRoutines.vb connection strings, creating 2nd 3rd 4th 5th 6th 7th 8th 9th modPublicVariables.vb public variables, declaring modSQLDMORoutines.vb backup device names, retrieving connection strings, creating 2nd database names, retrieving SQL Servers, loading 2nd 2nd 3rd Northwind SQL Server database CustOrdersHist stored procedure, T-SQL code overloaded methods PageIndexChanged command parameterized properties 2nd passwords validating 2nd 3rd PerformTask( ) function calling 2nd 3rd phone number extensions phone numbers, validating 2nd 2nd 3rd PhoneDatatypes.vb CNumberString class 2nd 3rd DefineValidChars method, declaring event handlers international phone number extensions IsValid method, declaring phone number extensions StringValue property ThrowException method, declaring ProductID detail information, loading 2nd property declarations (VB .NET) 2nd property declarations (VB 6) Page 585 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html public varibles, declaring ReadOnly keyword 2nd 2nd ReadValuesFromDataRow method records adding to data tables deleting 2nd 3rd loading into text boxes records, locating 2nd 2nd 3rd 2nd recordsets opening and retrieving 2nd 3rd 4th 5th persisting to disks 2nd RefreshIndividual routine calling reports exporting 2nd 3rd printing 2nd repRegion Repeater control loading repTerritories Repeater control loading routines calling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th list boxes, reloading 2nd SQL Servers, loading rows deleting in data grids 2nd 3rd finding save exceptions, trapping 2nd save method declaring Save method implementing testing 2nd 3rd 4th 5th SaveRecord routine creating 2nd 3rd replacing 2nd 3rd SaveRecord subroutine search forms custom properties, creating 2nd 3rd 4th 5th SecurityServices.asmx.vb DataSet object, passing passwords, validating (code) usernames, validating (code) SELECT command text SELEC T statement data, displaying updating 2nd SelectedIndexC hanged code 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th SelectedIndexChanged event SelectedIndexChanged event, adding Selection combo box populating 2nd 3rd SelectionFormula property setting servers Page 586 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html updating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Session object values, storing session variables tracking 2nd 3rd source code for chapters in book (Web site) SQL Server database, detaching 2nd SQL Server databases attaching 2nd SQL Server objects creating SQL Servers loading 2nd 3rd 4th SQL Servers, loading 2nd 3rd 4th SQL statements executing loading 2nd loading and executing storing 2nd storing and executing 2nd SQL strings building creating 2nd 3rd 4th 5th 6th stored procedures calling 2nd 3rd executing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th StringValue property 2nd Table control loading 2nd 3rd 4th 5th Table data type creating and returning tables copying 2nd 3rd 4th 5th 6th 7th listing in databases 2nd 3rd 4th 5th 6th 7th 8th text boxes toggling 2nd 3rd 4th text boxes, assigning values 2nd TextBoxC hange method text boxes, writing values TextChanged event 2nd 3rd 2nd ThrowException method declaring ToString method property information output 2nd 3rd UDFs (user-defined functions) assigning 2nd creating 2nd 3rd 4th 5th data, displaying SELECT statement, updating 2nd Update command Update command text 2nd 3rd 4th UseAStoredProcedureWithAParameter routine usernames validating 2nd ValidateCustomerID method validation controls 2nd Page 587 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html validation, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th VB .NET property declarations VB 6 default properties property declarations wavy blue lines Web pages initializing 2nd 3rd 4th 5th linking loading 2nd 3rd wfrmHowTo12_1.aspx.vb data tables, adding data data tables, binding 2nd 3rd 2nd DataTable object, creating XML documents, creating 2nd wfrmHowTo12_2.aspx.vb XML documents, reading 2nd 3rd wfrmHowTo12_3.aspx.vb data tables, adding data data tables, binding 2nd 2nd 3rd 2nd DataTable object, creating XML documents, creating 2nd wfrmHowTo12_4.aspx.vb XML documents, reading 2nd wfrmHowTo12_5.aspx.vb data tables, adding data data tables, binding 2nd 2nd DataTable object, creating XML documents, creating XML documents, reading into datasets wfrmHowTo5_1.aspx.vb customer information, listing RefreshIndividual routine, calling Web pages, loading wfrmHowTo5_2.aspx.vb validation controls wfrmHowTo5_3.aspx.vb LoadProducts routine, calling rows, finding Web pages, initializing 2nd 3rd wfrmHowTo5_4.aspx.vb DropDown control, loading 2nd 3rd 4th Table control, loading 2nd 3rd 4th wfrmHowTo5_5a.aspx repRegions Repeater control, HTML repTerritories Repeater control wfrmHowTo5_5a.aspx.vb DropDown control, loading repRegion Repeater control, loading Table control, loading wfrmHowTo5_5b.aspx repTerritories Repeater control, HTML wfrmHowTo5_5b.aspx.vb repTerritories Repeater control, loading Page 588 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html wfrmHowTo5_6.aspx.vb data grids, binding to DataView control data grids, paging through data grids, sorting Web pages, loading wfrmHowTo5_7.aspx events, wiring for DataGrid control wfrmHowTo5_7.aspx.vb changes, updating servers 2nd 3rd 4th data grids, cancelling edits data grids, setting to edit mode DataGrid object, loading 2nd 2nd records, adding to data tables rows, deleting in data grids 2nd 3rd session variables, tracking 2nd 3rd wfrmHowTo5_8a.aspx.vb products, filling and binding to DataGrid object wfrmHowTo5_8b.aspx.vb ProductID, loading detail information 2nd wfrmHowTo8_5.aspx 1stUnselected list box, reloading list boxes, loading categories 2nd 3rd list boxes, populating 2nd 3rd 4th 5th 6th routines, calling servers, updating 2nd 3rd 4th WriteChangesToDB method 2nd XML documents creating 2nd 3rd 4th 5th 6th 7th reading 2nd reading into datasets reading with XMLTextReader 2nd 3rd XML Web Services SOAP definition 2nd 3rd 4th 5th code (VB .NET) reports displaying 2nd 3rd 4th 5th 6th 7th exporting 2nd 3rd 4th 5th 6th 7th 8th 9th printing 2nd 3rd 4th 5th 6th 7th 8th 9th Code command (View menu) collapsing routines collections Items data, adding Items (index) SelectedIndices (index) collection SQL-DMO 2nd String Collection Editor 2nd Table Mappings 2nd Column Name property Column property columns adding to tables binding to controls properties 2nd Create Columns Automatically at Run Time check box, checking Create Columns Automatically, unchecking Page 589 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CustomerID (Customers table) CustomerID (Orders table) 2nd 2nd data entering data grids templates DataGrid Property Builder Columns tab DataItem.RegionURL HyperLink listing in databases code 2nd 3rd 4th names adding to ComboBox control (code) NULL properties 2nd 3rd SELECT string setting for DataGrid control 2nd sorting sorting (code) 2nd 2nd 3rd SQL Server database objects 2nd 3rd 4th 5th Columns tab (DataGrid Property Builder) columns. [See also fields] C OM type libraries, registering combo boxes customers, finding Selection populating (code) 2nd 3rd 4th 5th 6th C ombo control property settings 2nd C omboBox control column names, adding (code) 2nd 3rd data binding to 2nd 3rd 4th 5th 6th 7th 8th 9th datasets filling (code) loading (code) properties property settings 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 2nd 3rd C omboBox object properties 2nd 3rd 4th property property settings 2nd C ommand button properties 2nd settings 2nd 3rd 4th C ommand Button control properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th property settings 2nd 3rd 4th 5th 6th 7th C ommand Button object properties 2nd 3rd 4th 5th property command buttons accessing on forms 2nd 2nd data (to edit, save, or cancel) Page 590 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html properties Command object 2nd 3rd actions executing with SQL statements 2nd methods properties TextBox control populating with stored procedures 2nd CommandBuilder object methods properties commands Action menu New Group Properties Actions menu New Login Add menu Add Class Add New Item 2nd C ancel code context menu New Login Properties CREATE FUNCTION Delete code Edit code File menu New PageIndexC hanged code pop-up menu Copy Generate Dataset Paste Run as Server Control 2nd Project menu Add Reference 2nd Add Web Reference Report menu Report Options SELECT command text, code shortcut menu New Database Role New Database User New Login Update code Update command text, code 2nd 3rd View menu Code Indexes/Keys commands. 2nd [See also T-SQL (Transact-SQL) commands] Page 591 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html CommandText property CommandText property, accessing 2nd companies Alfred's Fried Foods CompareValidator control C ompareValidator object properties comparing ADO (ActiveX Data Objects) and ADO.NET 2nd 3rd OleDb and SQLClient objects Web server and HTML controls compound indexes Confirm Password text box 2nd 2nd C onnect button enabling connected data Connection object 2nd ADO (ActiveX Data Objects) 2nd 3rd 4th 5th methods properties connection strings BuildCnnStr( ) function creating code 2nd 3rd 4th 5th 6th 7th 8th 2nd 3rd 2nd creating (code) establishing (code) text, displaying 2nd connections ADO (ActiveX Data Objects) opening and displaying (code) 2nd databases with SQL-DMO objects 2nd Northwind database creating 2nd trusted (SQL Server) conrtrols bound at runtime 2nd constraints defining 2nd 3rd 4th 5th 6th for data 2nd of indexes constructors C C ustomer class code 2nd for C C ustomerID class code for CCustomerID class (code) 2nd object-based for CCustomerID class (code) objects rows, inserting into tables code testing code 2nd consuming XML Web Services 2nd 3rd 4th 5th 6th 7th Page 592 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html methods, calling 2nd Web references 2nd 3rd C ontactName property code context menu commands New Login Properties C ontrol Panel applets (Windows NT/2000) groups and users, adding control property settings Label, TextBox, and Command button 2nd C ontrol.ViewState property definition controlling classes, creation and behavior Crystal Report Viewer behavior sort order at run-time 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 2nd controls arranging on forms 2nd 3rd 4th 5th bound AutoPostBack property DataBind method IsPostBack property 2nd on Web Forms 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 2nd Web server and HTML controls, comparing button click events, adding (code) 2nd Button properties 2nd 3rd 4th 5th 6th columns, binding to properties 2nd C ombo property settings 2nd C omboBox data, binding to 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd datasets, filling (code) loading (code) properties property settings 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd C ommand Button properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th property settings 2nd 3rd 4th 5th 6th 7th CompareValidator C rystal Report Viewer reports, displaying 2nd 3rd 4th 5th 6th 7th 8th 9th C rystalReportViewer property settings 2nd customer orders header information, displaying CustomValidator 2nd 2nd data DataSet DataView in Windows forms OleDbCommand OleDbConnection 2nd 3rd Page 593 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html OleDbDataAdapter SqlCommand SqlConnection SqlDataAdapter DataGrid button events on data grids 2nd buttons, adding 2nd 3rd 4th buttons, events 2nd columns, setting 2nd data grids, hyperlinking from rows to detail pages data, adding 24th 25th 26th data, binding to data, deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 2nd 3rd 4th 5th 6th 7th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th data, displaying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th data, drilling down to data, editing 24th 25th 26th data, manipulating data, new items 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 2nd data, paging through 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th data, sorting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th datasets, filling (code) events, wiring (code) 2nd 2nd General properties, setting 2nd loading (code) 2nd 3rd 4th 5th 2nd lookup tables, adding data objects, handling 2nd 3rd Paging properties, setting 2nd populating (code) 2nd 3rd 4th 5th properties 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th refreshing (code) 2nd 2nd schemas;loading into data tables DataGrid Web server DataList Web server DataRepeater DataSet 2nd binding with ListBox control properties 2nd for frmHowTo1_9b forms DataView data grids, binding (code) 2nd 2nd 3rd ddSortby SelectedIndexChanged event, attaching routines DropDown loading (code) 2nd 3rd 4th 5th populating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th propeties Export tab page objects and properties Hyperlink properties HyperLink propeties ignoring with Try[ellipsis dots]Catch[ellipsis dots]End Try block Page 594 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Label properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th properties, settings 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th propeties Label, TextBox, ListBox, and C ommand button property settings 2nd Letter Button click events (code) 2nd ListBox loading populating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th properties 2nd 3rd 4th 5th 6th 7th properties, setting to bind DataSet control 2nd properties, settings 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th 7th ListBox Web server ListBox Windows Forms OleDataAdapter for frmHowTo1_9b forms 2nd 3rd OleDbDataAdapter controls 2nd on Web Forms bound at runtime OpenFileDialog order information, displaying 2nd 2nd Print tab page objects and properties properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th setting settings property settings 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th RangeValidator rbDistinct Radio Button Regular ExpressionValidator Repeater data, displaying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th events, programming lists, buttons and hyperlinks lists, displaying regional territories 2nd 3rd properties repRegion, loading (code) repRegions, HTML code repTerritories, code repTerritories, HTML code repTerritories, loading (code) 2nd templates 2nd 3rd 2nd URLs (uniform resource locators), creating 2nd Repeater Web server repRegion Repeater loading (code) repRegions Repeater HTML code repTerritories Repeater code HTML code Page 595 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html loading (code) RequiredFieldValidator Selected Products ListBox tab pages 2nd Table data, displaying loading (code) persistence propeties tables, displaying 2nd Table Web server 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th objects, creating 2nd TextArea TextBox populating 2nd properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th properties, settings 2nd 3rd 4th property settings 2nd 3rd 4th unbound on forms Unselected Products ListBox validation code messages, displaying on Web Forms 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th property settings 2nd 3rd validation (Web Forms) property settings 2nd 3rd 4th 5th validation errors 2nd Validation Web server 2nd 3rd ValidationSummary lists, look of validator reaction inconsistencies View tab page objects and properties Web server and HTML, comparing controls. 2nd [See also bound controls] cookies definition Copy command (pop-up menu) copying tables between SQL Server databases code 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th Create Columns Automatically at Run Time check box, checking Create Columns Automatically, unchecking Create Database dialog box CREATE DATABASE statement CREATE DEFAULT statement CREATE FUNCTION command CREATE FUNCTION statement CREATE PROCEDURE statement Create Relationships dialog box CREATE RULE statement CREATE TABLE statement 2nd 3rd 4th CREATE VIEW statement 2nd 3rd 2nd Page 596 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Create XML File button 2nd 3rd CreateComment (XMLDocument class) CreateNode (XMLDocument class) creatin objectsd 2nd creating ActivateEditing routine code 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th bound list boxes bulk queries code 2nd classes to implement interfaces 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th connection strings code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th custom properties for search forms 2nd 3rd 4th 5th data adapters data tables 2nd 2nd 2nd 3rd 4th 5th 6th database user accounts DataTable object code 2nd 3rd 4th 5th 6th Delete Record Detach/Attach SQL Server Database dialog box 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th dialog boxes forms GenerateData routine 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th generic search forms data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th 47th 48th 49th 50th GetBackupDevices routine GetSQLDatabases routine indexes with Property Pages dialog box interfaces LoadIndividual routine 2nd code 2nd 3rd 2nd LoadList routine code 2nd LoadSelectedProducts routine 2nd LoadUnSelectedProducts routine mailing labels 2nd 3rd Northwind database connections 2nd objects with SQL syntax on-screen reports with hyperlinks fields as hyperlinks 2nd 3rd Web site fields, adding 2nd 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th on-the-fly batch updates in ADO.NET point-and-click query tool data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th point-and-click SQL Server query tool data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th reports with Report Expert 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th Page 597 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SaveRecord routine code 2nd 3rd SQL Server database 2nd 3rd 4th 5th 6th constraints, defining 2nd 3rd 4th 5th 6th default values, defining fields, defining 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th 6th 7th 8th 9th indexes, defining primary keys, defining stored procedures, creating 2nd 3rd 4th 5th tables, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th tables, defining relationships 2nd 3rd 4th 5th 6th 7th 8th 9th views, creating 2nd 3rd 4th 5th 6th 7th 8th SQL Server database objects column properties 2nd 3rd columns 2nd rows 2nd table properties 2nd 3rd tables 2nd SQL Server objects code SQL Server objects with ADO (ActiveX Data Objects) 2nd 3rd 4th SQL statements SQL strings code 2nd 3rd 4th creating 2nd standard logins 2nd 3rd 4th 5th stored procedures 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th T-SQL commands 2nd Table data type tables 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th CREATE TABLE statement 2nd 3rd tblCustomerPhones table UDFs 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th (user-defined functions) calling 2nd code, formatting 2nd parameters, passing scalar types, returning 2nd table types, returning 2nd UDFs (user-defined functions) code 2nd 3rd 4th 5th URLs (uniform resource locators) 2nd views 2nd 3rd 4th 5th 6th 7th 8th Web Forms Windows NT/2000 groups Windows NT/2000 logins 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th XML documents code 2nd 3rd 4th 5th 2nd data tables, creating with XMLTextWriter 2nd 3rd 4th with XMLWriter 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th XMLTextWriter 2nd 3rd XML Web Services 2nd 3rd 4th 5th 6th 7th XML Web Services with parameters descriptions 2nd methods, descriptions 2nd 2nd 3rd 4th 5th 6th Page 598 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html parameters, passing 2nd security tables 2nd creation control of classes 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th Criteria property Crosstab reports C rystal Report Gallery dialog box Crystal Report Gallery dialog box C rystal Report Viewer behavior, controlling 2nd reports displaying 2nd 3rd 4th 5th 6th 7th 8th 9th ReportSource property 2nd 3rd Crystal Reports Experts licensing reports calculated fields, adding 2nd 3rd 4th 5th creating with Report Expert 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th displaying 2nd 3rd 4th 5th 6th 7th displaying with Viewer 2nd 3rd 4th 5th 6th 7th 8th 9th exporting 2nd 3rd 4th 5th 6th 7th 8th 9th fields as hyperlinks 2nd 3rd labels, printing 2nd 3rd 4th 5th 6th 7th 8th mailing labels, creating 2nd 3rd on-screen, adding Web site fields 2nd on-screen, creating with hyperlinks 2nd 3rd 4th 5th 6th options, setting 2nd printing 2nd 3rd 4th 5th 6th 7th 8th 9th printing at run-time 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th records, printing 2nd 3rd 4th 5th 6th 7th 8th ReportSource property 2nd 3rd SelectionFormula syntax 2nd sort order, controlling at run-time 2nd C rystalReportViewer control property settings 2nd C rystalReportViewer object property settings 2nd CType( ) function cursor data type (SQL Server) cursors ADO 2.x client-side Dynamic type Forward Only type types ADODB.CursorTypeEnum.adOpenForwardOnly custom database roles (SQL Server security) 2nd 3rd 4th 5th 6th C ustomer class code customer information listing code customer orders header information, displaying 2nd information Page 599 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html controls to display 2nd displaying (code) 2nd 3rd 4th C ustomerData.vb DataAdapter Configuration Wizard, code 2nd 3rd SELECT command text, code Update command text, code 2nd 3rd 2nd CustomerID column (Customers table) CustomerID column (Orders table) 2nd C ustomerID property code C ustomerInterface.vb IC ustomer interface properties (code) C ustomerInterface9_1.vb delete method declaring (code) IC ustomer interface code interfaces code ReadOnly keyword, code save method declaring (code) customers finding in combo boxes RefreshIndividual routine calling (code) customers orders details, drilling down to C ustomers page search forms, calling 2nd C ustomers table CustomerID column 2nd list Server Explorer Customers XSD, code 2nd Customers, CustomerCustomerDemo, and CustomerDemographics table customizing reports 2nd C ustomTask object methods properties CustomValidator control 2nd CustOrdersHist stored procedure, T-SQL code [ Tea m LiB ] Page 600 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D ] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] DAO (Data Access Objects) 2nd data adding in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th to Items collection adding to lookup tables 2nd binding to ComboBox control 2nd 3rd 4th 5th 6th 7th 8th 9th to DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th canceling changes (code) 2nd command buttons to edit, save, or cancel connected constraints 2nd 2nd controls DataSet DataView in Windows forms OleDbCommand OleDbConnection OleDbDataAdapter SqlCommand SqlConnection SqlDataAdapter 2nd 3rd deleting in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th details, retrieving disconnected displaying in bound list boxes 2nd 3rd 4th 5th 6th 7th in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th templates 2nd 3rd URLs (uniform resource locators), creating 2nd with Repeater control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th with SELECT statement (code) with Table control 2nd 3rd 4th 5th 6th 7th 8th 9th displaying in DataGrid control 2nd drilling down to 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th editing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th notifying users 2nd entering into columns errors, communicating to developers 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th exporting with SQL-DTS filling DataGrid control generating Page 601 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html code 2nd loading into list boxes 2nd manipulating 2nd 3rd methods objects 2nd 3rd 2nd 3rd paging through in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th properties 2nd 3rd regenerating (code) retrieving from SQL Server 2000 database 2nd 3rd 4th 5th 6th 7th retrieving with DataReader object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th saving code 2nd 2nd to servers (code) sorting in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th tables binding (code) updating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th validating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th validating on Web Forms validation code, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th views Data Access Objects. [See DAO]2nd [See DAO] Data Adapter Configuration Wizard 2nd data adapters creating 2nd Table Mappings collection 2nd data bound forms 2nd 3rd 4th 5th 6th 7th 8th 9th data driven definition data grids binding to DataView control (code) button events 2nd data tables binding (code) 2nd 3rd 4th 5th 6th 7th 2nd 3rd data tables, binding (code) EditItemIndex edits cancelling (code) HyperLink columns hyperlinking from rows to detail pages information, retrieving 2nd 2nd 3rd 4th 5th 6th 7th page indexes updating (code) paging through code records deleting (code) posting (code) 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th rows deleting (code) 2nd 3rd setting to edit mode (code) sorting code Page 602 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html sorting, setting 2nd 3rd 4th templates updating code Data Link Properties dialog box data providers classes 2nd OLE DB (ADO) choosing 2nd data sets filling with frmHowTo1_1 (code) data sources choosing Data tab Standard Report Wizard data tables binding code 2nd 3rd 4th 2nd 3rd binding (code) creating 2nd data adding (code) data, adding (code) loading (code) 2nd 3rd 2nd 3rd records adding (code) locating (code) 2nd 2nd records, adding, code 2nd 3rd schemas, loading 2nd text boxes assigning values (code) Data Transformation Services. 2nd [See DTS] data types bigint (SQL Server) binary (SQL Server) bit (SQL Server) char (SQL Server) cursor (SQL Server) datetime (SQL Server) decimal (SQL Server) float (SQL Server) image (SQL Server) int (SQL Server) money (SQL Server) nchar (SQL Server) ntext (SQL Server) numeric (SQL Server) nvarchar (SQL Server) real (SQL Server) smalldatetime (SQL Server) smallint (SQL Server) smallmoney (SQL Server) SQL Server 2nd 3rd 4th 5th sql_variant (SQL Server) Table creating and returning Page 603 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html table (SQL Server) text (SQL Server) timestamp (SQL Server) tinyint (SQL Server) uniqueidentifier (SQL Server) varbinary (SQL Server) varchar (SQL Server) data-bound multi-select list boxes data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th data-driven techniques 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th data-bound multi-select list boxes 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th generic search forms creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th 47th 48th 49th 50th lookup tables updating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th point-and-click query tool creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th point-and-click SQL Server query tool creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th DataAdapter frmHowTo1_2.vb code 2nd DataAdapter C onfiguration Wizard Choose a Query Type page Choose Your Data Connection page code 2nd 3rd 2nd 2nd Generate the SQL Statements page DataAdapter object methods 2nd 3rd properties 2nd 3rd DataAdapter Update method database list boxes loading code 2nd Database property Database Role Properties dialog box Permissions tab 2nd Database User Properties dialog box 2nd 2nd databases 1stDatabases list box populating (code) 2nd 3rd 4th 5th application roles (SQL Server security) 2nd 3rd 4th 5th backing up with SQL-DMO btnDetach button toggling (code) classes code 2nd 3rd columns listing (code) 2nd 3rd 4th Page 604 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html connecting to with SQL-DMO objects 2nd custom database roles (SQL Server security) 2nd 3rd 4th 5th 6th db_accessadmin (fixed database role) db_backupoperator (fixed database role) db_datareader (fixed database role) db_datawriter (fixed database role) db_ddladmin (fixed database role) db_denydatareader (fixed database role) db_denydatawriter (fixed database role) db_owner (fixed database role) db_securityadmin (fixed database role) Detach/Attach SQL Server Database dialog box creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th detaching 2nd diagrams dialog boxes creating and connecting to 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th files attaching 2nd finding and attaching (code) 2nd fixed database roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th how-to, design view 2nd JET opening (code) JET database engine 2nd list boxes loading (code) 2nd lists, refreshing 2nd local ADO (ActiveX Data Objects) 2nd names retrieving (code) 2nd 3rd Northwind customers, tracking demographics Northwind SQL Server Customers table list null values, interpreting public (fixed database role) reattaching records inserting relationships Create Relationships dialog box rights, sharing Server Explorer 2nd 2nd SQL backing up verifying SQL Server attaching (code) backing up 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th constraints, defining 2nd 3rd 4th 5th 6th creating 2nd 3rd 4th 5th 6th default values, defining detaching (code) 2nd 3rd 4th 5th 6th Page 605 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html fields, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th 6th 7th 8th 9th indexes, defining primary keys, defining restoring 2nd 3rd 4th 5th 6th 7th 8th 9th 10th stored procedures, creating 2nd 3rd 4th 5th tables, copying between tables, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th tables, defining relationships 2nd 3rd 4th 5th 6th 7th 8th 9th verifying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 2nd 3rd 4th 5th 6th 7th 8th views, creating SQL Server 2000 data, retrieving 2nd 3rd 4th 5th 6th 7th SQL Server database objects column properties 2nd 3rd columns 2nd creating rows 2nd table properties 2nd 3rd tables 2nd SQL-DMO (SQL-Distributed Management Objects) 2nd 3rd objects states supporting tables listing (code) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th many-to-many relationship one-to-many relationship one-to-one relationship referential integrity 2nd 3rd searching 2nd 3rd 4th 2nd updating methods, implementing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th user accounts, creating 2nd 3rd 4th 5th 6th user options users logging in databases. [See also data-driven techniques] DataBind method Databind method DataColumn object methods properties DataDefinition object DataFormatString property DataGrid control button events on data grids 2nd buttons, adding 2nd 3rd 4th buttons, events 2nd columns, setting 2nd data adding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th binding to 2nd 3rd 4th 5th 6th 7th 8th 9th deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th Page 606 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html displaying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th drilling down to 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th editing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th manipulating 2nd new items paging through 2nd 3rd 4th 5th 6th 7th 8th 9th 10th sorting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th data grids hyperlinking from rows to detail pages data, displaying 2nd 2nd 3rd 4th 5th 6th 7th datasets filling (code) 2nd events, wiring (code) General properties, setting 2nd loading code loading (code) 2nd 3rd lookup tables data, adding 2nd objects handling 2nd 3rd Paging properties, setting 2nd populating (code) 2nd 3rd 4th 5th properties 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th refreshing (code) 2nd schemas loading into data tables 2nd DataGrid object loading code 2nd products filling and binding (code) properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd records, canceling editing/adding (code) special instructions, code DataGrid Property Builder Columns tab General tab Paging tab DataGrid Web server control DataGrids displaying 2nd DataItem.RegionURL column DataList Web server control DataReader object data, retrieving 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th list boxes loading (code) methods properties datareader.Read( ) method DataRepeater control DataRow object methods 2nd 2nd 3rd Page 607 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html properties 2nd DataRowView object DataSet (data control) controls 2nd frmHowTo1_2.vb code 2nd DataSet control binding with ListBox control properties 2nd DataSet controls for frmHowTo1_9b forms DataSet object methods 2nd 3rd passing code properties 2nd 3rd 4th 5th 6th 7th 8th DataSet objects data editing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th rows adding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th datasets dsC ustomerIndividual records, adding (code) loading (code) 2nd 2nd passing from XML Web Services 2nd 3rd 4th 5th 6th 7th refreshing code 2nd retrieving from XML Web Services (code) returning as XML (code) 2nd 3rd strongly typed VB .NET tools, writing ADO.NET code 2nd 3rd tables text boxes binding 2nd XML documents 2nd 3rd 4th 5th 6th 7th 8th 9th creating (code) reading (code) DataSource property DataSource property (list boxes) 2nd 2nd DataTable object creating (code) DataTable object 2nd C omboBox control loading (code) 2nd 3rd creating code 2nd 2nd creating (code) list boxes loading (code) methods objects 2nd 2nd 3rd 4th 5th 2nd 3rd properties 2nd 3rd 4th 5th records, locating 2nd 3rd 4th 5th 6th 7th 8th 9th Page 608 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SQL Server results, retrieving 2nd 3rd 4th 5th 6th tracking code 2nd 3rd 4th 5th DataTable.C olumns object methods properties DataTable.Rows object methods 2nd properties 2nd DataTextField property DataType property DataValueField property DataView (data control) DataView control data grids, binding (code) DataView object records, filtering 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th records, sorting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th RowFilter property, setting (code) 2nd DateDiff function Days_to_Ship, displaying DateDiff( ) function Days_to_Ship, displaying datetime data type (SQL Server) DateTimePicker object properties Days_To_Ship (SQL statements, displaying in labels) 2nd db_accessadmin (fixed database role) db_backupoperator (fixed database role) db_datareader (fixed database role) db_datawriter (fixed database role) db_ddladmin (fixed database role) db_denydatareader (fixed database role) db_denydatawriter (fixed database role) db_owner (fixed database role) db_securityadmin (fixed database role) dbcreator (fixed server role) ddSortby control SelectedIndexC hanged event routines, attaching decimal data type (SQL Server) declarations CCustomer class properties (code) class variables (code) MaximumStringLengthExceededException class, code Private property (VB .NET code) property (VB 6 code) DECLARE statement 2nd 2nd declaring default properties code DefineValidC hars method code Page 609 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html delete method code InvalidCustomerIDException (code) IsValid method code local variables in T-SQL 2nd public variables code save method code ThrowException method code 2nd Default keyword default properties classes, defining declaring code in VB 6 code default values defining 2nd 3rd 4th 5th 6th DefineValidC hars method declaring code defining classes 2nd 3rd 4th 5th default properties in interfaces methods, adding to interfaces parameterized properties properties 2nd 3rd 4th properties, adding to interfaces read-only properties 2nd 2nd 3rd write-only properties 2nd constraints 2nd 3rd 4th 5th 6th default values 2nd 3rd 4th 5th 6th fields 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th indexes 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th 6th 7th 8th 9th primary keys table relationships 2nd 3rd 4th 5th 6th 7th 8th 9th tables 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th definitions class Control.ViewState property cookies data driven HTML hidden fields inheritance instances of classes loosely coupled messages members of classes method signature objects query strings definitios Page 610 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XSD (XML Schema Definition) Delete button Delete command code Delete key clicking, effects Delete method 2nd delete method declaring code Delete method implementing code testing code delete object permission Delete Record, creating deletes, cascade deleting data in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th lookup table information 2nd records 2nd 3rd 4th 5th 6th 7th 8th 9th 10th buttons code 2nd 3rd 2nd 3rd exceptions, catching (code) in data grids (code) 2nd 3rd 4th 5th 6th rows in data grids (code) 2nd 3rd in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th tables 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th DROP TABLE statement 2nd DeliveryDate values 2nd demographics of customers, tracking deny access level (object permissions) deny state (statement permissions) DESC (Sort property) Description text box 2nd descriptions of methods 2nd Web Services, creating with parameters 2nd XML Web Services 2nd viewing 2nd 3rd 4th 5th XML Web Services Description descriptive languages. [See also WSDL] design time DataGrid control columns, setting 2nd Paging properties, setting 2nd design view database how-to 2nd Design view reports, displaying 2nd Page 611 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html designers Report Designer View Designer Diagram pane Grid pane properties Results pane SQL pane tables 2nd designes Taable Designer desktop applications (VB .NET) generic search forms, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th DestinationOptions (ExportOptions object) Detach button Detach/Attach SQL Server Database dialog box creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th DetachDB method 2nd detaching databases 2nd SQL Server database, code detail data, retrieving detail information of Product ID loading (code) 2nd detail pages hyperlinks 2nd rows, hyperlinking to 2nd 3rd 4th 5th 6th 7th Details section of reports fields 2nd developing Windows forms Devices property dgRegion_CancelCommand routine dgRegion_DeleteCommand routine dgRegion_EditCommand routine dgRegion_UpdateCommand routine Diagram pane (View Designer) 2nd diagrams databases of classes 2nd dialog boxes Add Members Add New User Add Reference Add Role Members Add Table connecting to databases Create Database 2nd 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 2nd 2nd 2nd 3rd Create Relationships creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th Crystal Report Gallery Data Link Properties Database Role Properties Permissions tab 2nd Database User Properties 2nd 2nd 2nd Detach/Attach SQL Server Database Page 612 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th Format Generate Dataset New Group New Project New Role 2nd 3rd 4th 2nd OLE DB (ADO) dialog box Properties Windows Only option Property Builder 2nd Property Pages indexes, creating opening 2nd Report Options reports, customizing 2nd Server Role Properties 2nd SQL Server Login Properties 2nd Standard Report Expert tabs 2nd Table Properties 2nd Permissions tab 2nd DialogResult, setting (code) 2nd directories XML Web Services Directories disabled Windows NT/2000 accounts 2nd disabling btnC onnection button code 2nd text boxes code 2nd 2nd text boxes, code disconnected data discoveries XML Web Services Discovery diskadmin (fixed server role) disks recordsets, persisting to (code) 2nd 3rd displaying ADO connections code 2nd connection string text 2nd customer order header information 2nd data in bound list boxes 2nd 3rd 4th 5th 6th 7th in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th templates 2nd 3rd URLs (uniform resource locators), creating 2nd with Repeater control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 2nd with SELECT statement (code) with Table control 2nd 3rd 4th 5th 6th 7th 8th 9th data in DataGrid control 2nd DataGrids 2nd Formula Editor displaying 2nd Page 613 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html lists look of in ValidationSummary control message boxes messages in validation controls order information controls 2nd records 2nd 3rd in DISTINCT clause 2nd regional descriptions regional territories 2nd 3rd RegionID reports 2nd 3rd 4th 5th 6th 7th in Design view 2nd ReportSource property 2nd 3rd with Crystal Report Viewer 2nd 3rd 4th 5th 6th 7th 8th 9th SQL statements in lables 2nd table results tables with Table control 2nd 2nd Windows NT/2000 domain users DisplayMember property DisplayMember property (list boxes) Dispose method DISTINCT clause records, displaying 2nd Distributed Management Framework. [See DMF] 2nd DMF (Distributed Management Framework) APIs (Application Programming Interfaces) 2nd 3rd DOC UMENT object properties 2nd 3rd 4th 5th Document Object Model. [See also XML, DOM] DocumentElement (XMLDocument class) documents Report 2nd Name property, setting reports, exporting 2nd 3rd 4th reports, printing 2nd XML creating (code) 2nd 3rd 4th 5th creating with XMLTextWriter 2nd 3rd 4th creating with XMLWriter 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th data tables, creating 2nd data, retrieving from SQL Server 2000 database 2nd 3rd 4th 5th 6th 7th datasets 2nd 3rd 4th 5th 6th 7th 8th 9th reading (code) 2nd reading into datasets (code) reading with XMLReader 2nd 3rd 4th 5th 6th 7th 8th 2nd 3rd reading with XMLTextReader (code) XMLTextWriter 2nd 3rd XML Web Services Discovery DoesC ustomerIDExist function code DOM. [See also XML, DOM] Page 614 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html domains Windows NT/2000 users, displaying 2nd double quotation marks ("") Drill Down reports drilling down to customer orders details down to data 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th DROP TABLE statement 2nd DropDown control loading code 2nd 3rd 4th 5th populating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th properties DropDown object properties 2nd 3rd dsC ustomerIndividual dataset records, adding (code) 2nd dsC ustomers.xsd Customers XSD, code 2nd DTD SQL-DTD objects tables, copying 2nd DTS (Data Transformation Services) 2nd packages tasks and workflows DTSPackage Object Library Dynamic type cursor 2nd [ Tea m LiB ] Page 615 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] Edit button Edit command code edit mode data grids, setting to (code) edit, remove SQL Server as subheading from servers main entry] editing data 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd command buttons in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th notifying users 2nd data grids cancelling (code) 2nd 2nd lookup table information records 2nd 3rd 4th canceling in DataGrid object (code) EditItemIndex editors Formula Editor displaying 2nd String Collection Editor 2nd edits canceling code element tags Ellipsis button 2nd Enabled properties on Windows forms 2nd 2nd 3rd 4th 5th enabled properties of buttons, toggling (code) EnableTightHorizontal property enabling btnC onnection button code 2nd Connect button encoding Unicode encrypted security ID (SID) END statement EndCurrentEdit method EndEdit method engines JET database engine Enterprise Manager Backup/Restore Wizard SQL Server authentication mode error handling with bound controls 2nd 3rd 4th 5th 6th 7th 8th 9th 10th error notices ListAvailableSQLServer method ErrorMessage property Page 616 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html errors 3621 of data, communicating to developers throwing 2nd unhandled Errors collection/Error object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th event handlers code for mFax variable code events buttons in DataGrid control 2nd buttons on data grids 2nd C heckC hanged code 2nd ItemC ommand Repeater control events, programming Load code 2nd of Repeater control programming SelectedIndexC hanged code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, adding routines, attaching TextC hanged code 2nd 3rd 4th wiring for DataGrid control (code) events. [See also click events]2nd [See also click events]3rd [See also click events] exception handling code exceptions 3621 error application ApplicationException catching (code) 2nd 3rd errors, unhandled InvalidC ustomerIDException declaring (code) InvalidPhoneNumberException code MaximumStringLengthExceededException class declaration, code passing (code) 2nd save trapping (code) system trapping with Try[ellipsis dots]Catch[ellipsis dots]End Try block Try[ellipsis dots]Catch[ellipsis dots]Finally block Try[ellipsis dots]Catch[ellipsis dots]Finally blocks Execute button Execute method execute object permission ExecuteABatchCommand routine ExecuteReader method 2nd 2nd 2nd executing Page 617 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html actions on forms batch updates 2nd 2nd 3rd 4th 5th bulk queries code 2nd 2nd 3rd 4th 5th 6th on-the-fly batch updates in ADO.NET parameterized stored procedures in ADO.NET 2nd 3rd 4th 5th 6th 7th 8th SQL Server stored procedures with ADO (ActiveX Data Objects) 2nd 3rd 4th SQL statements code 2nd 3rd 4th stored procedures code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 2nd objects, properties and methods update statement EXIST statement expanding routines Experts (Crystal Reports) experts Formula Expert Mailing Labels Expert Standard Report Expert dialog box tabs Experts. 2nd [See also Report Expert] EXPLICIT mode Export button Export method Export tab page objects properties ExportDestinationType (ExportOptions object) ExportFormatType (ExportOptions object) exporting data with SQL-DTS files 2nd reports 2nd 3rd 4th 5th 6th 7th 8th 9th code 2nd ExportOptions object 2nd DestinationOptions ExportDestinationType ExportFormatType FormatOptions expressions tables 2nd Extensible Markup Language. [See XML] extensions of files .vb .xsd [ Tea m LiB ] Page 618 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] fields adding in Report design as hyperlinks 2nd 3rd calculated, adding to reports 2nd 3rd 4th 5th defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th Details section of reports 2nd Formula HTML hidden definition in recordsets, updating in tables of mailing labels 2nd primary index functions 2nd primary key properties 2nd Fields tab Standard Report Wizard fields. [See also columns] 2nd file extensions *.asmx File menu commands New files *.asmx extension .vb extension .xsd extension attaching to databases exporting 2nd 2nd 2nd in databases finding and attaching (code) 2nd filling datasets code 2nd 3rd 4th Letter Button result sets, code 2nd 3rd 4th 5th filling and binding products to DataGrid object (code) FillSchema method 2nd Filter tab Standard Report Wizard filtering records with DataView object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th finding customers in combo boxes records 2nd 3rd 4th 5th 6th 7th 8th 9th 10th inner joins joins left outer joins 2nd right outer joins 2nd rows code Page 619 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html finding and attaching database files, code finding. 2nd [See also locating] fixed database roles db_accessadmin db_backupoperator db_datareader db_datawriter db_ddladmin db_denydatareader db_denydatawriter db_owner db_securityadmin public fixed database roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th fixed server roles bulkadmin dbcreator diskadmin processadmin securityadmin serveradmin setupadmin sysadmin fixed server roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th float data type (SQL Server) Flush (XMLTextWriter) foreign keys CustomerID column (Orders table) Form Letter reports Form reports Format dialog box FormatOptions (ExportOptions object) 2nd formats XML Web Services Wire Formats formatting code UDFs (user-defined functions) Formatting (XMLTextWriter) 2nd forms actions, executing 2nd closing code 2nd 3rd 2nd 2nd closing (code) command buttons, accessing controls arranging 2nd 3rd bound at runtime properties, setting controls, arranging 2nd creating data bound 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd frmHowTo1_9b DataSet controls 2nd 3rd OleDataAdapter controls 2nd 3rd frmMain Page 620 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html generic searches creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th 47th 48th 49th 50th 51st 52nd 53rd 54th 55th 56th 57th 58th 59th 60th 61st 62nd 63rd 64th 65th 66th 67th 68th 69th 70th 71st 72nd 73rd 74th 75th 76th 77th 78th 79th 80th 81st 82nd 83rd 84th 85th 86th 87th 88th 89th 90th 91st 92nd 93rd 94th 95th 96th 97th 98th 99th 100th 101st How-To 1.1, opening 2nd loading code 2nd loading (code) login XML Web Services authentication objects changes to 2nd opening code 2nd 3rd 4th 2nd 3rd 4th order information, displaying (code) public variables, declaring (code) 2nd record sources, searching records loading into text boxes (code) 2nd 3rd search calling 2nd custom properties, creating (code) 2nd 3rd 4th 5th 6th 7th SQL databases backing up and verifying tables searching 2nd 3rd 4th TextBox control, populating 2nd unbound controls user options Windows objects using in Web forms forms. [See also Windows forms]2nd [See also Windows Forms]3rd [See also Web Forms] Formula Editor displaying 2nd Formula Expert Formula fields formulas adding tables 2nd Forward Only type cursor frameworks. Friend object [See also DMF] frmHowTo.vb constructors, testing, code frmHowTo1_1 data sets, filling (code) frmHowTo1_2.vb code 2nd frmHowTo1_3 Label control property settings 2nd 3rd 4th TextBox control property settings 2nd 3rd 4th frmHowTo1_3.vb Page 621 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html datasets refreshing (code) 2nd RefreshIndividual routine calling (code) 2nd RefreshIndividual subroutine calls, code to add 2nd frmHowTo1_4.vb ActiveEditing subroutine calling (code) 2nd data canceling changes (code) saving to servers (code) 2nd 2nd SaveRecord routine calling (code) 2nd text boxes disabling (code) toggling (code) 2nd 3rd 4th 2nd frmHowTo1_5.vb data saving (code) 2nd dsC ustomerIndividual dataset records, adding (code) 2nd edits canceling (code) 2nd list boxes reloading (code) 2nd 3rd 4th 5th mbAddNew variable resetting (code) 2nd records deleting (code) 2nd 3rd text boxes toggling (code) 2nd 3rd 4th frmHowTo1_6.vb btnSave click event trapping save exceptions (code) 2nd exceptions catching (code) passing (code) 2nd 3rd 2nd frmHowTo1_7.vb enabled properties of buttons, toggling (code) forms, closing (code) 2nd 2nd 2nd 3rd 4th 5th records, saving before closing (code) frmHowTo1_8.vb DataGrid control refreshing (code) 2nd datasets filling (code) 2nd 3rd 4th frmHowTo1_9 forms opening (code) 2nd frmHowTo1_9b datasets loading (code) 2nd forms DataSet controls 2nd 3rd OleDataAdapter controls 2nd 3rd Page 622 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmHowTo10_4.vb reports exporting (code) printing (code) 2nd frmHowTo10_5.vb Selection combo box populating (code) 2nd 3rd SelectionFormula property setting (code) frmHowTo13_3.vb passwords, validating (code) usernames, validating (code) frmHowTo13_4.vb datasets, retrieving from XML Web Services (code) frmHowTo3_1.vb list boxes, loading (code) 2nd 3rd frmHowTo3_2.vb list boxes, loading (code) 2nd frmHowTo3_3.vb ComboBox control, loading (code) records, locating (code) 2nd 2nd 2nd 3rd text boxes, assigning values (code) frmHowTo3_4.vb button controls, adding click events (code) columns, sorting (code) 2nd 2nd 3rd ComboBox control, adding column names (code) data tables, loading (code) 2nd 3rd DataView object, setting RowFilter property (code) 2nd frmHowTo6_1.vb data, regenerating (code) forms, loading (code) SQL strings, building (code) frmHowTo6_2.vb SQL statements storing and executing (code) 2nd frmHowTo6_3.vb data, generating (code) 2nd 2nd 3rd GenerateData routine, calling (code) frmHowTo6_4.vb left outer joins, code frmHowTo6_5.vb SQL statements loading and executing frmHowTo6_6.vb PerformTask( ) function, calling (code) SQL statements, executing (code) SQL statements, loading (code) 2nd 2nd 3rd frmHowTo6_7.vb forms, loading (code) 2nd SQL statements, storing (code) 2nd frmHowTo6_8.vb UDFs (user-defined functions) assigning (code) creating (code) 2nd 2nd 3rd 4th 5th data, displaying (code) SELECT statement, updating (code) 2nd Page 623 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmHowTo7_1.vb btnC onnection button disabling (code) enabling (code) 2nd 2nd 2nd 3rd 4th database list boxes, loading (code) list boxes, repopulating (code) routines calling (code) 2nd 3rd 2nd list boxes, reloading (code) SQL Servers loading (code) 2nd frmHowTo7_2.vb 1stBackupDevices list box, populating (code) 1stDatabases list box, populating (code) backups, performing (code) 2nd 3rd 4th 5th 6th 7th routines SQL Servers, loading (code) frmHowTo7_3.vb 1stBackupDevices list box, populating (code) 1stDatabases list box, populating (code) backups, performing (code) routines, calling (code) SQL Servers, loading (code) frmHowTo7_4.vb 1stBackupDevices list box, populating (code) 1stDatabases list box, populating (code) forms, closing (code) routines, calling (code) SQL Servers, loading (code) tables, copying (code) 2nd 3rd 4th 5th 2nd 2nd 2nd 3rd frmHowTo7_5.vb 1stDatabases list box, populating (code) btnDetach button, toggling (code) database files, finding and attaching (code) forms, closing (code) routines, calling (code) SQL Server database, detaching (code) SQL Server databases, attaching (code) SQL Servers, loading (code) 2nd 2nd 2nd frmHowTo8_1.vb 1stUnSelected list box reloading (code) list boxes populating (code) 2nd 3rd 4th 5th 6th 2nd list boxes, loading categories (code) routines calling (code) servers updating (code) 2nd 3rd 4th 5th 6th frmHowTo8_2.vb 1stLookupTables pointing to items (code) 2nd connection strings establishing (code) 2nd DataGrid control populating (code) 2nd 3rd 4th 5th Page 624 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html frmHowTo8_3.vb columns listing in databases (code) DataGrid control, loading (code) SQL strings, creating (code) 2nd stored procedures, executing (code) 2nd 3rd 4th 5th 2nd tables listing in databases (code) 2nd 3rd frmHowTo8_4.vb search forms, creating custom properties (code) stored procedures, executing (code) 2nd tables listing in databases (code) frmHowTo8_4a.vb Letter Button result sets, filling (code) 2nd records loading into text boxes (code) 2nd 3rd frmHowTo8_4b.vb DialogResult, setting (code) key values, storing (code) 2nd 2nd Letter Button controls, click events (code) search forms, creating custom properties (code) stored procedures, executing (code) 2nd 3rd tables listing in databases (code) frmHowTo8_6.aspx data grids page indexes, updating (code) records, deleting (code) records, posting (code) 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th data tables records, adding (code) 2nd 3rd DataGrid object records, canceling editing/adding (code) special instructions (code) DataTable object tracking (code) 2nd 3rd 4th 5th frmHowTo8_7.vb columns listing in databases (code) 2nd DataGrid control loading (code) 2nd 3rd SQL strings creating (code) 2nd 3rd 4th 2nd 3rd 4th stored procedures, executing (code) tables listing in databases (code) 2nd frmHowTo8_8a.vb Letter Button result sets, filling (code) 2nd records loading (code) 2nd 3rd Session object values, storing (code) frmHowTo8_8b.vb calling pages, returning to (code) 2nd data grids Page 625 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html updating (code) key values, storing (code) 2nd Letter Button controls, click events (code) stored procedures, executing (code) tables listing in databases (code) frmHowTo9_2.vb C C ustomer class code 2nd property declarations (code) class variable declarations (code) C ustomer class code property declarations (VB .NET code) property declarations (VB 6 code) TextBoxC hange method text boxes, writing values (code) TextChanged event (code) 2nd ToString method property information output (code) 2nd frmHowTo9_4.vb CCustomer class, constructors (code) 2nd 2nd ReadValuesFromDataRow method, code frmHowTo9_5.vb Clear method, code 2nd constructors rows, inserting into tables (code) constructors, testing (code) Delete method, implementing (code) Delete method, testing (code) Save method, implementing (code) Save method, testing (code) WriteChangesToDB method, code 2nd 2nd 3rd 4th 5th frmHowTo9_6 ContactName property, code InvalidPhoneNumberException, code MaximumStringLengthExceededException class declaration, code phone numbers, validating (code) 2nd 3rd frmHowTo9_6.vb DoesCustomerIDExist function (code) If[ellipsis dots] Then block (code) InvalidCustomerIDException, declaring (code) ValidateCustomerID method (code) frmHowTo9_7.vb event handlers, code frmMain form frmMain.vb ADO connections opening and displaying (code) forms opening (code) 2nd routines calling (code) functions BuildCnnStr 2nd Page 626 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BuildCnnStr( ) 2nd built-in T-SQL 2nd CType( ) DateDiff Days_to_Ship, displaying DateDiff( ) Days_to_Ship, displaying DoesC ustomerIDExist code In-Line of indexes 2nd 2nd PerformTask( ) calling (code) scaler T-SQL commands 2nd 3rd 4th 5th 6th Table Trim 2nd 3rd UDFs (user-defined functions) calling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, formatting 2nd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th parameters, passing scalar types, returning 2nd table types, returning 2nd userk-defined functions. [See also UDFs] [ Tea m LiB ] Page 627 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] General properties in DataGrid control, setting 2nd General tab (DataGrid Property Builder) Generate Dataset command (pop-up menu) Generate Dataset dialog box Generate the SQL Statements page (DataAdapter Configuration Wizard) 2nd 2nd GenerateData routine calling code creating 2nd 3rd generating data code 2nd generic search forms creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th 47th 48th 49th 50th GetBackupDevices routine creating GetPageNum( ) routine GetPageRows( ) routine GetSQLDatabases routine 2nd creating GetString Display records displaying 2nd 3rd GetString method 2nd GetUserInfo method 2nd grant access level (object permissions) grant state (statement permissions) Grid pane (View Designer) properties grids data sorting, setting 2nd grids. [See also data grids] 2nd Group By property Group Name text box Group tab Standard Report Wizard Groupbox object properties GroupBox object properties groupings reports 2nd groups creating for Windows NT/2000 Names list 2nd 2nd 3rd 4th 5th 6th [ Team LiB ] Page 628 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] handlers. [See event handlers] handling exceptions code headers customer orders information, displaying 2nd Hello World method, testing 2nd help .NET Framework Developer's Guide hidden fields (HTML) definition How-To 1.1 form, opening 2nd how-to's database, design view 2nd HTML (Hypertext Markup Language) code repRegions Repeater control repTerritories Repeater control controls and Web server controls, comparing 2nd hidden fields definition http[colon, no spaces]//localhost/WebService1/Service1.asmx?WSDL XML Web Services, SOAP definition (code) 2nd 3rd 4th 5th HyperLink columns HyperLink control properties Hyperlink control properties Hyperlink object properties HyperLink object properties 2nd Hyperlink object properties 2nd HyperLink object properties Hyperlink object properties 2nd 3rd 4th 5th 6th 7th 8th hyperlinking in data grids, from rows to detail pages 2nd 3rd 4th 5th 6th 7th hyperlinks action options 2nd BorderColor property BottomLineStyle property detail pages 2nd EnableTightHorizontal property on-screen reports 2nd 3rd 4th 5th 6th fields as hyperlinks 2nd 3rd Web site fields, adding real-time 2nd 2nd Page 629 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html regional descriptions, displaying Hypertext Markup Language. [See HTML] [ Team LiB ] Page 630 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] icons Server Explorer Server Roles toolbox 2nd IC ustomer interface code properties code Identity property IDs CustomerID column (Customers table) CustomerID column (Orders table) RegionID, displaying SID (encrypted security ID) IF statement 2nd 2nd If[ellipsis dots] Then block code image data type (SQL Server) implementing intertaces 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th Implements ICustomer.[Property/Method Name] In-Line function 2nd indexes compound constraints creating with Property Pages dialog box 2nd data grid pages updating (code) 2nd defining 2nd 3rd 4th 5th 6th 7th 8th 9th functions 2nd performance 2nd 2nd Indexes/Keys command (View menu) indices Items (index) collection SelectedIndices (index) collection information retrieving from data grids 2nd infrastructures XML Web Services 2nd 3rd inheritance definition inheritance permission keywords of classes 2nd initializing local variables in T-SQL 2nd Web pages code 2nd 3rd inner joins records 2nd 3rd 4th 5th 6th records, finding inner joins (tables) Page 631 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html insert object permission inserting records instances of classes definition int data type (SQL Server) integrity referential (database tables) 2nd 3rd interfaces classes defining creating C ustomerInterface9_1.vb code 2nd delete method, declaring (code) ReadOnly keyword, code save method, declaring (code) IC ustomer code properties (code) implementing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 2nd 3rd methods, adding properties, adding XML Web Services international phone number extensions code 2nd interpreting null valuees InvalidC ustomerIDException declaring (code) InvalidPhoneNumberException code Invoke button IsPostBack property 2nd IsValid method declaring code IsValid property ItemC ommand event Repeater control events, programming Items (index) collection Items collection data, adding [ Team LiB ] Page 632 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] JET databases opening (code) JET database engine 2nd joining taables 2nd joins inner records 2nd 3rd 4th 5th records, finding reords inner (tables) left outer code records, finding 2nd records, finding right outer records, finding 2nd [ Team LiB ] Page 633 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] key values, storing (code) 2nd 3rd 4th keys Delete clicking, effects primary defining 2nd 3rd 4th 5th 6th 7th 8th 9th keys. [See primary keys]2nd [See also foreign keys] keywords class inheritance permissions 2nd Default member override MustInherit 2nd abstract classes MustOverride Nothing NotInheritable NotOverrideable Overrideable Overrides 2nd 2nd ReadOnly code [ Team LiB ] Page 634 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] Label control properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th settings 2nd 3rd 4th settings for frmHowto_3 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th Label object properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th property property settings 2nd Text property Label, TextBox, and C ommand button control property settings 2nd Label, TextBox, ListBox, and C ommand button property settings 2nd labels lblSQLString SQL statements, storing (code) 2nd mailing appearance control 2nd creating 2nd 3rd fields 2nd sorting 2nd printing 2nd 3rd 4th 5th 6th 7th 8th SQL statements displaying 2nd loading (code) 2nd UDFs (user-defined functions) assigning (code) languages. 2nd 3rd [See also XML]2nd [See also HTML]3rd [See also WSDL] LANs (local area networks) lblSQLString label SQL statements storing (code) 2nd left (<) left arrow button left outer joins code records, finding 2nd Length property Letter Button controls click events code 2nd Letter Button result sets, filling (code) 2nd 3rd 4th letters data, displaying in DataGrid control 2nd levels of access deny (object permissions) grant (object permissions) revoke (object permissions) librariees DTSPackage Object Library Page 635 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html libraries accessing COM type, registering SQLDMO Object Library type referencing with ADO (ActiveX Data Objects) 2nd 3rd licensing Crystal Reports LIKE statement data, generating (code) 2nd lines wavy blue (code) linking Web pages list boxes 1stBackupDevices populating (code) 2nd 3rd 4th 1stDatabases populating (code) 2nd 3rd 4th 5th 1stUnSelected reloading (code) 2nd 1stUnselected reloading (code) 2nd categories loading (code) 2nd 3rd 4th 5th data loading 2nd data-bound multi-select data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th databases loading (code) 2nd DataSource property DisplayMember property loading (code) 2nd 3rd 4th 5th lstSQLServers code multi-select on Web Forms 2nd populating code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th reloading code 2nd 3rd 2nd reloading (code) repopulating (code) Selected Products ListBox control SelectedIndexC hanged event code 2nd 3rd 4th 5th SQL Servers loading (code) 2nd 3rd 4th 5th 6th 7th 8th 9th text boxes binding 2nd binding and viewing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Unselected Products ListBox control ValueMember property Page 636 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ListAvailableSQLServer method error notice ListBox control loading populating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th properties 2nd 3rd 4th 5th setting to bind DataSet control 2nd settings 2nd 3rd 4th property settings 2nd 3rd 4th 5th 6th 7th ListBox controls properties 2nd ListBox object properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th property ListBox Web server control ListBox Windows Forms control ListBox1 frmHowTo1_1 data sets, filling (code) listing columns in databases code 2nd 3rd 4th customer information code SQL Servers in SQL-DMO 2nd tables in databases code 2nd 3rd 4th 5th 6th 7th 8th lists based on Customers table database, refreshing 2nd look of in ValidationSummary control Names groups and users 2nd region descriptions, displaying RegionID, displaying Tables in Report list 2nd territories, displaying 2nd 3rd lists. [See also bound list boxes] 2nd Load event code Load List button 2nd 3rd LoadIndividual routine creating 2nd creating (code) 2nd 3rd loading categories into list boxes (code) 2nd 3rd 4th 5th C omboBox control code 2nd 3rd data into list boxes 2nd data tables code 2nd 3rd database list boxes code 2nd 3rd 4th Page 637 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html DataGrid control code 2nd 3rd loading DataGrid object (code) 2nd datasets code 2nd DropDown control code 2nd 3rd 4th 5th forms code 2nd 3rd 4th list boxes code 2nd 3rd 4th 5th ListBox control ProductID detail information (code) 2nd records into text boxes (code) 2nd 3rd 4th 5th 6th repRegion Repeater control code repTerritories Repeater control code schemas into data tables 2nd SQL Servers code 2nd 3rd 4th 5th 6th 7th 8th 9th SQL statements code 2nd Table control code 2nd 3rd 4th 5th Web pages code 2nd LoadList routine creating (code) 2nd LoadProducts routine calling code LoadSelectedProducts routine creating 2nd LoadSQLServers routine 2nd LoadSQLString routine LoadTables( ) subroutine LoadUnSelectedProducts routine creating LoadUnSelectedProducts subroutine LoadUnUnselectedProducts subroutine LoadXML (XMLDocument class) local area networks. [See LANs] local databases ADO (ActiveX Data Objects) 2nd local variables declaring in T-SQL 2nd initializing in T-SQL 2nd Locate File button locating records Page 638 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html code 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th with DataTable object login forms XML Web Services authentication logins databases using Windows NT Integrated Security standard, creating 2nd 3rd 4th 5th Windows NT/2000 2nd 3rd 4th 5th 6th lookup tables data, adding 2nd 2nd information, managing updating 2nd data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th loosely coupled messages, definition lstSQLServers list box code [ Tea m LiB ] Page 639 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M ] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] m (adding to code) Mail Labels reports mailing labels appearance control 2nd creating 2nd 3rd fields 2nd sorting 2nd Mailing Labels Expert Main forms frmMain management state on clients server-side solutions 2nd 3rd 4th 5th Session object 2nd 3rd 4th managers Enterprise Manager Backup/Restore Wizard SQL Server authentication mode manipulating data 2nd many-to-many relationship (tables) mapping Table Mappings collection 2nd markup languages. [See also XML]2nd [See also HTML] MaximumStringLengthExceededException class declaration, code mbAddNew variable resetting code 2nd mdtProducts DataTable object rows finding (code) members of classes definition message boxes displaying messages displaying in validation controls loosely coupled, definition methodds AddNew BeginEdit MustOverride keyword RejectChanges methods AcceptChanges AcceptChanges method Add adding to interfaces 2nd 3rd AddNew Page 640 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html AddObjectForTransfer Application object AttachDBWithSingleFile 2nd AttributeCount Backup object BackupDevice object BackupDevices object BeginLoadData C lear code Close Command object CommandBuilder object Connection object CustomTask object data, handling 2nd 3rd 2nd DataAdapter object 2nd 3rd DataAdapter Update database updates DataBind Databind DataColumn object DataReader object datareader.Read( ) DataRow object DataSet object DataTable object 2nd 3rd 4th 5th 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th DataTable.Columns object DataTable.Rows object 2nd DefineValidC hars declaring (code) Delete 2nd delete declaring (code) Delete implementing implementing (code) testing (code) descriptions 2nd DetachDB 2nd Dispose EndCurrentEdit EndEdit Execute ExecuteReader Export FillSchema 2nd GetString 2nd GetUserInfo 2nd Hello World, testing 2nd Implements ICustomer.[Property/Method Name] 2nd 2nd IsValid declaring (code) ListAvailableSQLServer error notice NodeType Page 641 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html of objects executing stored procedures 2nd overloaded code overloading 2nd Option Strict overrideable Package object Page.Validate PrinterToPrinter QueryResults object Read 2nd ReadBackupHeader ReadValuesFromDataRow code 2nd 2nd RefreshReport RejectChanges RemoveAt Restore object Save 2nd save declaring (code) Save implementing implementing (code) testing (code) 2nd 3rd 4th 5th 6th 7th signature definition SQLBackup SQLRestore SQLServer object Step object Task object TestUserPassword 2nd 3rd TextBoxC hange text boxes, writing values (code) 2nd ThrowException declaring (code) ToString property information output (code) update Update 2nd 3rd UpdateCommand Validate ValidateC ustomerID code Value 2nd WebMethod passwords, validating (code) usernames, validating (code) 2nd 2nd WriteC hangesToDB code 2nd XML Web Services calling 2nd XML Web Services Description XMLDocument Page 642 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XMLDocument class XMLNode XMLNode class XMLTextWriter 2nd mFax variable event handlers code Microsoft Office 200x minus sign (-) mixed-mode authentication models XML DOM (Document Object Model) models. 2nd 3rd 4th 5th 6th 7th 8th 9th 10th [See also object models] modes authentication Windows NT/2000 AUTO 2nd 3rd 4th 5th 6th 7th 8th edit data grids, setting to (code) EXPLICIT mixed-mode authentication RAW modGeneralRoutines.vb 2nd 3rd 4th connection strings creating (code) 2nd 3rd 4th connection strings, creating (code) 2nd 3rd 4th 5th modifiers Public access 2nd VB .NET properties modifying tables 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th ALTER TABLE statement 2nd modPublicVariables.vb public variables, declaring (code) modSQLDMORoutines.vb backup device names, retrieving (code) connection strings, creating (code) 2nd database names, retrieving (code) 2nd 3rd SQL Servers loading (code) 2nd money data type (SQL Server) multi-select list boxes on Web Forms MustInherit keyword abstract classes MustOverride keyword 2nd 2nd [ Tea m LiB ] Page 643 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] Name property names of backup devices, retrieving (code) of databases, retrieving (code) 2nd 3rd Names list groups and users 2nd namespaces .NET bound list boxes, creating 2nd 3rd 4th 5th XML (Extensible Markup Language) System.XML System.XML.Schema System.XML.Xpath System.XML.XSL Visual Basic XML Web Services 2nd namespaces. 2nd [See also SQL-NS] naming objects reports with rptReportName Web Forms nchar data type (SQL Server) networks LANs (local area networks) New command (File menu) New Connection button New Database Role command (shortcut menu) New Database User command (shortcut menu) New Group command (Action menu) New Group dialog box 2nd New Login command (Actions menu) New Login command (context menu) New Login command (shortcut menu) New Prject dialog box New Role dialog box NodeType method 2nd 3rd 4th Northwind connections creating 2nd Unassigned Products Only check box Northwind database customers demographics, tracking Orders table Web site fields, adding 2nd Northwind SQL Server database Customers table list CustOrdersHist stored procedure, T-SQL code Nothing keyword NotInheritable keyword Page 644 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html NotOverrideable keyword ntext data type (SQL Server) NULL columns records null values Allow Nulls null values, interpreting number sign (#) numbers phone validating (code) 2nd 3rd numeric data type (SQL Server) nvarchar data type (SQL Server) [ Team LiB ] Page 645 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] object C omboBox properties DataGrid properties Label properties Object Browser object models ADO (ActiveX Data Objects) 2nd ADODB (ActiveX Data Objects 2.7 object model) 2nd 3rd object permissions delete deny access level execute grant access level insert revoke access level select update object permissions (SQL Server security) 2nd 3rd 4th 5th 6th object-based constructors for CCustomerID class (code) 2nd objects ADO.NET 2nd 3rd 4th 5th 6th 7th 8th 9th Application methods properties Backup 2nd methods properties BackupDevice methods properties BackupDevices methods properties BindingContext 2nd BindingManagerBase 2nd Button properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th C heckBox properties 2nd 3rd C omboBox properties 2nd 3rd 4th property settings 2nd Command 2nd 3rd actions, executing with SQL statements 2nd methods Page 646 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html properties TextBox control, populating with stored procedures 2nd C ommand Button properties 2nd 3rd 4th 5th 6th C ommandBuilder methods properties CommandBuilider C ompareValidator properties Connection 2nd ADO (ActiveX Data Objects) 2nd 3rd 4th 5th methods properties constructors creating 2nd with SQL syntax C rystalReportViewer property settings 2nd C ustomTask methods properties data, handling DataAdapter methods 2nd 3rd 2nd 3rd properties 2nd 3rd DataColumn methods properties DataDefinition DataGrid loading (code) 2nd 2nd products, filling and binding (code) properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st records, canceling editing/adding (code) setting to edit mode (code) special instructions (code) DataReader data, retrieving 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th list boxes, loading (code) methods properties DataRow methods 2nd 2nd 3rd properties 2nd DataRowView DataSet data, editing methods passing (code) properties 2nd 3rd 4th 5th 6th 7th 8th rows, adding rows, deleting DataTable ComboBox control, loading (code) creating (code) 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 2nd 3rd 4th 5th 6th Page 647 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html list boxes, loading (code) methods objects 2nd 2nd 3rd 4th 5th 2nd 3rd properties 2nd 3rd 4th 5th records, locating 2nd 3rd 4th 5th 6th 7th 8th 9th SQL Server, retrieving results 2nd 3rd 4th 5th 6th tracking (code) DataTable object 2nd 3rd 4th 5th 2nd 3rd DataTable.C olumns methods properties DataTable.Rows methods 2nd properties 2nd DataView records, filtering 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th records, sorting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th RowFilter property, setting (code) 2nd DateTimePicker properties definition DOC UMENT properties 2nd 3rd 4th 5th DropDown properties 2nd 3rd DTSPackage Object Library Errors collection/Error ExportOptions 2nd DestinationOptions ExportDestinationType ExportFormatType FormatOptions Friend Groupbox properties GroupBox properties Hyperlink properties HyperLink properties 2nd Hyperlink properties 2nd HyperLink properties Hyperlink properties 2nd 3rd 4th 5th 6th 7th 8th Label properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th property settings 2nd Text property ListBox properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th mdtProducts DataTable rows, finding (code) Page 648 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html methods for executing stored procedures 2nd OldDBC ommand CommandText property OleDataAdapter properties 2nd 3rd 4th 5th OleDb and SQLClient, comparing OleDbCommandBuilder OleDbDataAdapter properties 2nd 3rd on forms, changes to 2nd Package methods properties Panel properties 2nd 3rd Parameter PrimaryKey PrintOptions properties Private properties for executing stored procedures 2nd Protected Protected Friend Public QueryResults methods properties Radio Button properties RadioButton properties RangeValidator properties ReadOnly Recordset 2nd ADO (ActiveX Data Objects) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th RegularExpressionValidator properties Repeater properties RequiredFieldValidator properties Restore 2nd 2nd methods properties 2nd Session .NET Framework Developer's Guide Nothing keyword values, storing (code) SQL Server creating (code) creating with ADO (ActiveX Data Objects) 2nd 3rd 4th SQL-DMO 2nd 3rd 4th 5th 6th 7th 8th (SQL-Distributed Management Objects) Page 649 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html databases, backing up and verifying 2nd SQL-DTD tables, copying 2nd SQL-DTS data, exporting SQLDMO Object Library SQLServer methods properties state management values, storing Step methods properties Stream Table properties TableC ell properties TableRow properties Task methods properties TextArea properties 2nd TextBox 2nd properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd ValidationSummary properties values storing Windows forms using in Web forms WriteOnly XML DOM (Document Object Model) objects. 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th [See also SQL Server database objects]2nd [See also ADO]3rd [See also RDO]4th [See also DAO] objectscommand buttons properties objets naming OldDBC ommand object CommandText property OLE DB (ADO) data provider choosing 2nd 3rd 4th OLE DB (ADO) dialog box OleDataAdapter controls for frmHowTo1_9b forms 2nd 3rd OleDataAdapter object properties 2nd 3rd 4th 5th OleDb classes performance improvement 2nd OleDb objects and SQLClient objects, comparing OleDbC ommand Page 650 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html (data control) OleDbCommandBuilder object OleDbC onnection (data control) OleDbDataAdapter (data control) ? (question mark) controls 2nd OleDbDataAdapter object properties 2nd 3rd on-screen reports fields as hyperlinks 2nd 3rd Web site fields, adding 2nd on-screen reports, creating with hyperlinks 2nd 3rd 4th 5th 6th on-the-fly batch updates creating in ADO.NET 2nd 3rd 4th 5th 6th executing in ADO.NET 2nd 3rd 4th 5th 6th one-to-many relationship (tables) one-to-one relationship (tables) Open a Recordset button OpenAndDisplayADOConnection routine OpenFileDialog control 2nd opening ADO connections code 2nd forms code 2nd 3rd 4th 2nd How-To 1.1 form JET databases code 2nd Property Pages dialog box recordsets code 2nd 3rd 4th OpenNorthwindADOConnection subroutine operators BETWEEN syntax 2nd Option Strict (overloaded methods) Or property order information controls to display 2nd OrderID values 2nd orders details, drilling down to information displaying (code) Orders table CustomerID column 2nd 2nd 3rd 4th organizing reports groupings 2nd Output property overloaded methods code overloading Page 651 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html methods 2nd Option Strict Overrideable keyword overrideable methods Overrides keyword 2nd overriding member overriding keywords 2nd [ Tea m LiB ] Page 652 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] Package object methods properties packages DTS tasks and workflows 2nd page indexes updating in data grids (code) Page.IsValid property Page.Validate method PageIndexC hanged command code pages calling returning to (code) 2nd 3rd detail hyperlinks 2nd rows, hyperlinking to 2nd 3rd 4th 5th 6th 7th tab controls 2nd Paging properties setting for DataGrid control 2nd Paging tab (DataGrid Property Builder) paging through data grids code paging through data in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Panel object properties 2nd 3rd panes Diagram (View Designer) Grid (View Designer) properties Results (View Designer) SQL (View Designer) Parameter object parameterized properties classes, defining code parameterized stored procedures executing in ADO.NET 2nd 3rd 4th 5th 6th 7th 8th parameters at symbol (@) 2nd frmHowTo1_2.vb code 2nd passing UDFs (user-defined functions) XML Web Services, creating 2nd stored procedures calling (code) 2nd 3rd Page 653 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XML Web Services creating 2nd 3rd 4th 5th 6th 7th descriptions 2nd methods, descriptions 2nd parameters, passing 2nd security tables 2nd parent records cascade deletes passing DataSet object code datasets from XML Web Services 2nd 3rd 4th 5th 6th 7th 8th exceptions (code) 2nd parameters UDFs (user-defined functions) XML Web Services, creating 2nd passwords validating code 2nd Paste command (pop-up menu) percent sign (%) Perform Backup button performance of indexes 2nd performance improvement OleDb classes 2nd SQLClient classes 2nd performing backups, code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th PerformTask( ) function calling code 2nd 3rd permissions class inheritance permission keywords 2nd object delete deny access level execute grant access level insert revoke access level select update object (SQL Server security) 2nd 3rd 4th 5th 6th statement deny state grant state revoke state statement (SQL Server security) 2nd 3rd 4th 5th 6th 7th Permissions button 2nd Permissions tab (Database Role Properties dialog box) Permissions tab (Table Properties dialog box) 2nd 2nd persistence Table control persisting Page 654 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html recordsets 2nd 3rd 4th recordsets to disks code 2nd persisting records phone number extensions code international code phone numbers validating code 2nd 3rd PhoneDatatypes.vb C NumberString class code 2nd CNumberString class, code DefineValidChars method, declaring (code) event handlers code IsValid method, declaring (code) phone number extensions code international (code) StringValue property code ThrowException method, declaring (code) plus sign (+) 2nd point-and-click query tool creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th point-and-click SQL Server query tool creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th point-and-click Web form property settings pointers classes points break setting in stored procedures 2nd pop-up menu commands Copy Generate Dataset Paste Run as Server Control 2nd populating 1stBackupDevices list box, code 1stDatabases list box, code 2nd 3rd 4th 2nd 3rd 4th 5th DataGrid control code 2nd 3rd 4th 5th DropDown controls 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th list boxes code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 2nd repopulating (code) ListBox controls 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th Selection combo box code 2nd 3rd TextBox control 2nd posting Page 655 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html records in data grids (code) pound sign (#) 2nd 3rd 4th 5th 6th 7th 8th primary key field index functions 2nd primary keys CustomerID column (Customers table) 2nd defining 2nd 3rd 4th 5th 6th 7th 8th 9th field in tables PrimaryKey object Print button 2nd Print tab page objects properties printing labels 2nd 3rd 4th 5th 6th 7th 8th records 2nd 3rd 4th 5th 6th 7th 8th reports 2nd 3rd 4th 5th 6th 7th 8th 9th at run-time code options, setting 2nd SelectionFormula syntax 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th PrintOptions object properties PrintToPrinter method Private declarations Private object procedures stored creating procedures. [See also stored procedures]2nd [See stored procedures] 2nd processadmin (fixed server role) ProdAndCatTab table ProductID detail information, loading (code) 2nd products filling and binding to DataGrid object (code) LoadUnSelectedProducts subroutine LoadUnUnselectedProducts subroutine Selected Products ListBox control Table control loading (code) loading;code 2nd 2nd 3rd 4th 5th 6th 2nd Unassigned Products Only check box Unselected Products ListBox control programming Repeater control events stateless (Web pages) clients, state management 2nd 2nd 3rd 4th 5th server-side solutions, state management Session object 2nd 3rd 4th Project menu commands Add Reference 2nd Add Web Reference projects XML Web Services Page 656 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html propertes controls properties 2nd 3rd 4th 5th Action adding to interfaces Allow Nulls Anchor Application object AutoIncrement AutoPostBack Backup object BackupDevice object BackupDevices object BorderColor BottomLineStyle Button control 2nd 3rd 4th 5th 6th Button object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th buttons 2nd CheckBox object Column Name columns, binding to controls 2nd Combo control 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd 3rd 4th 5th 6th 7th 2nd 3rd ComboBox control ComboBox object Command button Command Button control Command Button object command buttons Command Object Command object CommandBuilder object CommandText CommandText, accessing CompareValidator object Connection object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 2nd 3rd 4th 5th 6th 2nd C ontactName code control settings Label, TextBox, and Command button 2nd C ontrol.ViewState definition controls 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st CrystalReportViewer control 2nd CrystalReportViewer object 2nd C ustomerID code CustomTask object data, handling 2nd 3rd DataAdapter object 2nd 3rd Database DataColumn object DataformatString DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th DataGrid object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd DataGrid Property Builder Page 657 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html General tab DataReader object DataRow object DataSet object DataSource DataSource (list boxes) DataTable object 2nd 3rd 4th 5th 2nd 2nd 3rd 4th 5th 6th 7th 8th DataTable.Columns object DataTable.Rows object DataTextField DataType DataValueField DateTimePicker object 2nd default classes, defining declaring (code) in VB 6 (code) Devices DisplayMember DisplayMember (list boxes) DOCUMENT object DropDown control DropDown object 2nd 3rd 2nd 3rd 4th 5th 2nd enabled of buttons, toggling (code) 2nd 3rd 4th 5th Enabled on Windows forms EnableTightHorizontal ErrorMessage 2nd General setting in DataGrid control 2nd Grid pane (View Designer) Groupbox object GroupBox object HyperLink control Hyperlink control Hyperlink object HyperLink object Hyperlink object HyperLink object Hyperlink object 2nd 3rd 4th 5th 6th 7th 8th 2nd 2nd IC ustomer interface code Identity Implements ICustomer.[Property/Method Name] IsPostBack 2nd IsValid Label control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd settings for frmHowto_3 Label object Label Object Label object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 2nd 3rd 2nd 3rd 4th 2nd 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th Length ListBox control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th Page 658 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html ListBox controls 2nd ListBox object ListBox Object ListBox object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th Name of buttons, setting of columns 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th of Command button of controls 2nd setting of controls, setting of fields of Label control 2nd 3rd 4th of Label, TextBox, ListBox, and Command button of ListBox control 2nd 3rd 4th setting to bind DataSet control 2nd 2nd of objects executing stored procedures 2nd of tables 2nd 3rd 2nd 3rd 4th of TextBox control OleDataAdapter object 2nd 3rd 4th 5th OleDbDataAdapter object 2nd 3rd Package object Page.IsValid Panel object 2nd 3rd parameterized classes, defining code point-and-click Web Forms PrintOptions object QueryResults object Radio Button object RadioButton object RangeValidator object read-only classes, defining 2nd ReadOnly RegularExpressionValidator object Repeater control Repeater object ReplaceDatabase ReportSource 2nd 3rd 4th RequiredFieldValidator object Restore object RowFilter setting for DataView object (code) RowStateFilter SelectedIndices.Count 2nd 2nd SelectionFormula setting (code) SelectionMode settings for controls Sort DESC SQLServer object Step object 2nd Page 659 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html StringValue code Table control Table object TableCell object TableRow object TabPages Task object Text of Label object setting validation controls TextArea object 2nd TextBox control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th settings for frmHowto_3 TextBox object TextBox Object TextBox object 24th 25th 26th ValidationExpression ValidationSummary object ValueMember ValueMember (list boxes) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 2nd 3rd 4th 2nd 3rd 4th 5th VB .NET modifiers Web Form validation controls 2nd 3rd 4th 5th 6th 7th 8th write-only classes, defining 2nd WriteOnly XMLDocument XMLDocument class XMLNode XMLNode class XMLTextWriter 2nd Properties command (Action menu) Properties command (context menu) Properties dialog box Windows Only option 2nd Properties window CommandText property, accessing 2nd propertis Alias Column Criteria Group By Or Output Sort Order Sort Type Table Property Builder dialog box property declarations of C C ustomer class code property information output of ToString method Page 660 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html code 2nd Property Pages dialog box indexes, creating opening Protected Friend object Protected object providers. 2nd [See data providers] public (fixed database role) Public access modifiers 2nd Public object public variables declaring (code) PushButton button 2nd [ Tea m LiB ] Page 661 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] queries bulk creating and executing (code) 2nd 3rd point-and-click query tool creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th point-and-click SQL Server query tool creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th records retrieving 2nd 3rd 4th 5th 6th 7th 8th 9th 10th SQL value ranges 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th wildcards 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th subqueries SQL statements, loading and executing (code) subqueries (T-SQL) 2nd 3rd 4th 5th 6th Query Builder 2nd 3rd SQL statements, building 2nd query strings definition QueryResults object methods properties question mark (?) quotation marks double ("") [ Team LiB ] Page 662 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R] [S] [T] [U] [V] [W] [X] Radio Button object properties radio buttons rbDistinct Radio Button control RadioButton object properties ranges of values SQL queries 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th RangeValidator control RangeValidator object properties RAW mode rbDistinct Radio Button control RDO (Remote Data Objects) Read method 2nd Read XML File button read-only properties classes, defining 2nd ReadBackupHeader method reading XML documents code 2nd into datasets (code) with XMLReader 2nd 3rd 4th 5th 6th 7th 8th 2nd 3rd with XMLTextReader (code) ReadOnly keyword code ReadOnly object ReadOnly property ReadValuesFromDataRow method code 2nd 2nd real data type (SQL Server) real-time hyperlinks 2nd reattaching databases record sets ADODB.CursorTypeEnum.adOpenForwardOnly cursor type records adding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th buttons to data tables (code) 2nd 2nd to dsCustomerIndividual dataset (code) adding to data tables (code) 2nd 3rd canceling editing/adding in DataGrid object (code) Cascade Delete Related Records cascade deletes Delete Record, creating deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th buttons code 2nd 3rd 2nd 3rd exceptions, catching (code) Page 663 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html in data grids (code) displaying 2nd 3rd in DISTINCT clause 2nd DISTINCT clause editing 2nd 3rd 4th filtering with DataView object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 2nd 3rd 4th 5th 6th finding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th inner joins 2nd 3rd 4th 5th 6th 7th inserting joins left outer joins 2nd loading into text boxes (code) locating (code) 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th 6th locating with DataTable object NULL persisting posting in data grids (code) 2nd 3rd 4th 5th 6th printing 2nd 3rd 4th 5th 6th 7th 8th retrieving 2nd 3rd 4th 5th 6th 7th 8th 9th 10th right outer joins 2nd saving before closing (code) sorting with DataView object 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th sources searching stored procedures updating 2nd 3rd 4th Recordset object 2nd ADO (ActiveX Data Objects) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th records displaying 2nd 3rd editing 2nd 3rd 4th updating 2nd 3rd 4th recordsets persisting 2nd 3rd 4th recordsets Dynamic type cursor fields updating Forward Only type cursor opening code 2nd 3rd 4th persisting 2nd 3rd 4th persisting to disks code 2nd retrieving code 2nd 3rd 4th 2nd red X (Windows NT/2000 accounts) Red/Blue border style reports 2nd references for SQL APIs (Application Programming Interfaces) setting 2nd 3rd Web viewing 2nd Page 664 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XML Web Services 2nd 3rd referencing type libraries with ADO (ActiveX Data Objects) 2nd 3rd referential integrity (database tables) RefreshIndividual routine 2nd 3rd calling code 2nd 3rd RefreshIndividual subroutine calls, code to add 2nd refreshing database lists 2nd DataGrid control code 2nd datasets code 2nd RefreshReport method regenerating data code 2nd RegionID, displaying regions DataItem.RegionURL column descriptions, displaying repRegion Repeater control loading (code) repRegions Repeater control HTML code 2nd repTerritories Repeater control code 2nd 2nd HTML code loading (code) territories, displaying 2nd 3rd registering COM type libraries Regular ExpressionValidator control RegularExpressionValidator object properties RejectChanges method 2nd relationships tables many-to-many one-to-many one-to-one relationships between tables, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd relationships of databases Create Relationships dialog box 2nd reloading 1stUnSelected list box code 1stUnselected list box code list boxes code 2nd 3rd 4th 5th reloading list boxes code 2nd Page 665 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Remote Data Objects. RemoveAt method [See RDO] removing temporary users reoirtsLFormula Editor Repeater control data displaying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th events programming lists buttons hyperlinks territories (regional), displaying 2nd 3rd properties repRegion loading (code) repRegions HTML code repTerritories code HTML code loading (code) templates 2nd 3rd URLs (uniform resource locators), creating 2nd Repeater object properties Repeater Web server control ReplaceDatabase property replacing SaveRecord routine code 2nd 3rd repopulating list boxes code repopulating list boxes (code) Report design fields, adding Report Designer Report document 2nd Name property, setting reports printing 2nd reports, exporting 2nd 3rd 4th Report Expert Crosstab reports Drill Down reports Form Letter reports Form reports Formula Editor displaying 2nd Mail Labels reports reports creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th Standard reports SubReport reports Page 666 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html tables 2nd tabs viewing Report menu commands Report Options Report Options command (Report menu) Report Options dialog box reports, customizing 2nd ReportDocument reports, assigning 2nd reports assigning with ReportDocument 2nd calculated fields, adding 2nd 3rd 4th 5th creating with Report Expert Crosstab customizing 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th Details section fields 2nd displaying 2nd 3rd 4th 5th 6th 7th displaying in Design view 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th displaying with Crystal Report Viewer Drill Down exporting 2nd 3rd 4th 5th 6th 7th 8th 9th code 2nd ExportOptions object 2nd DestinationOptions ExportDestinationType ExportFormatType FormatOptions Form Form Letter Formula Editor displaying 2nd Formula fields formulas adding groupings 2nd hyperlinks action options 2nd labels printing 2nd 3rd 4th 5th 6th 7th 8th Mail Labels mailing labels creating 2nd 3rd modifying naming with rptReportName OLE DB (ADO) data provider choosing 2nd on-screen creating with hyperlinks 2nd 3rd 4th 5th 6th fields as hyperlinks 2nd 3rd Web site fields, adding options, setting 2nd printing 2nd 3rd 4th 5th 6th 7th 8th 9th code 2nd Page 667 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html printing at run-time 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th real-time hyperlinks 2nd records printing 2nd 3rd 4th 5th 6th 7th 8th Red/Blue border style 2nd ReportSource property 2nd 3rd SelectionFormula syntax 2nd sort order controlling at run-time 2nd Standard stringly typed strongly typed ReportSource property 2nd SubReport Tables in Report list user flexibility 2nd users controlling data viewed 2nd reports. 2nd [See also C rystal Reports] ReportSource property 2nd 3rd 4th repRegion Repeater control loading code repRegions Repeater control HTML code repTerritories Repeater control code HTML code loading code 2nd RequiredFieldValidator control RequiredFieldValidator object properties resetting mbAddNew variable code 2nd resources .NET Framework Developer's Guide Restore object methods 2nd 2nd properties 2nd restoring SQL Server databases 2nd 3rd 4th 5th 6th 7th 8th 9th 10th result sets Letter Button, filling (code) 2nd 3rd 4th results of tables displaying Results pane (View Designer) retrieving backup device names (code) data from SQL Server 2000 database 2nd 3rd 4th 5th 6th 7th with DataReader object 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th database names code 2nd 3rd datasets from XML Web Services (code) Page 668 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html information from data grids 2nd records 2nd 3rd 4th 5th 6th 7th 8th 9th 10th recordsets code 2nd 3rd 4th SQL Server results with DataTable object 2nd 3rd 4th 5th 6th return values ProdAndCatTab table 2nd returning scalar types UDFs (user-defined functions) Table data type 2nd table types UDFs (user-defined functions) 2nd to calling pages code 2nd revoke access level (object permissions) revoke state (statement permissions) right (>) arrow button right outer joins records, finding 2nd rights sharing on databases roles application roles (SQL Server security) 2nd 3rd 4th 5th bulkadmin (fixed server role) custom database roles (SQL Server security) 2nd 3rd 4th 5th 6th db_accessadmin (fixed database role) db_backupoperator (fixed database role) db_datareader (fixed database role) db_datawriter (fixed database role) db_ddladmin (fixed database role) db_denydatareader (fixed database role) db_denydatawriter (fixed database role) db_owner (fixed database role) db_securityadmin (fixed database role) dbcreator (fixed server role) diskadmin (fixed server role) fixed database roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th fixed server roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th processadmin (fixed server role) public (fixed database role) securityadmin (fixed server role) serveradmin (fixed server role) setupadmin (fixed server role) sysadmin (fixed server role) routinees GetSQLDatabases routines ActivateEditing creating (code) 2nd ActiveEditing subroutine calling (code) 2nd attaching to SelectedIndexChanged event BindTheGrid 2nd Page 669 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BuildCnnStr calling code code collapsing dgRegion_CancelCommand dgRegion_DeleteCommand dgRegion_EditCommand dgRegion_UpdateCommand ExecuteABatchCommand expanding 2nd 3rd 4th 5th 6th 7th 8th 9th GenerateData calling calling (code) creating 2nd 3rd GetBackupDevices creating GetPageNum( ) GetPageRows( ) GetSQLDatabases creating list boxes reloading (code) 2nd LoadIndividual creating 2nd creating (code) 2nd 3rd LoadList creating (code) 2nd LoadProducts calling (code) 2nd LoadSelectedProducts creating 2nd LoadSQLServers 2nd LoadSQLString LoadTables( ) subroutine LoadUnSelectedProducts creating LoadUnSelectedProducts subroutine LoadUnUnselectedProducts subroutine modGeneralRoutines.vb connection strings, creating (code) 2nd 3rd 4th modSQLDMORoutines.vb database names, retrieving (code) SQL Servers;loading (code) 2nd OpenAndDisplayADOConnection OpenNorthwindADOConnection subroutine RefreshIndividual calling (code) 2nd 3rd 4th 2nd 3rd RefreshIndividual subroutine calls, code to add SaveRecord calling (code) creating (code) replacing (code) 2nd 2nd 3rd 2nd 3rd 2nd SaveRecord subroutine code Page 670 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SetData subroutine SQL Servers loading (code) subroutines errors, throwing 2nd UseAStoredProcedureWithAParameter code RowFilter property setting for DataView object (code) 2nd rows adding in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th deleting in data grids (code) 2nd 3rd in DataSet objects 2nd 3rd 4th 5th 6th 7th 8th 9th 10th finding code in data grids, hyperlinking to detail pages 2nd 3rd 4th 5th 6th 7th SQL Server database objects 2nd RowStateFilter property rptReportName reports naming rules business data constraints 2nd Run as Server Control command (pop-up menu) Run Query button Run Time check box Create Columns Automatically, unchecking run-time reports options, setting 2nd printing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th SelectionFormula syntax 2nd sort order controlling 2nd runtime bound controls on Web Forms 2nd [ Tea m LiB ] Page 671 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S ] [T] [U] [V] [W] [X] Sams Web site source code for chapters in book Save (XMLDocument class) Save button clicking, effects save exceptions trapping (code) Save method 2nd save method declaring code Save method implementing code 2nd 3rd 4th 5th testing code SaveRecord routine calling (code) creating (code) replacing (code) 2nd 2nd 3rd 2nd 3rd SaveRecord subroutine code saving data code 2nd 2nd command buttons to servers 2nd records before closing (code) tables Web Forms 2nd saving to servers data code saving. 2nd [See also persisting] scalar types returning UDFs (user-defined functions) Scaler function 2nd schemas loading into data tables 2nd XSD (XML Schema Definition) Search button search forms calling 2nd custom properties creating (code) 2nd 3rd 4th 5th searching record sources tables 2nd 3rd 4th security Page 672 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SID (encrypted security ID) Windows NT Integrated Security users, logging into databases XML Web Services, testing 2nd security tables Web Services, creating with parameters 2nd security. [See also SQL Server security] securityadmin (fixed server role) SecurityServices.asmx.vb DataSet object, passing (code) passwords, validating (code) usernames, validating (code) SecurityWebServices Web site SELECT command text, code select object permission SELECT statement ALL clause data displaying (code) DISTINCT clause updating code 2nd SELEC T string columns Selected Products ListBox control SelectedIndexC hanged event code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, adding routines, attaching SelectedIndices (index) collection SelectedIndices.Count property Selection combo box populating code 2nd 3rd SelectionFormula reports printing options, setting 2nd syntax reports, printing 2nd SelectionFormula property setting code SelectionMode property Server Explorer Create Database dialog box Customers table databases 2nd 2nd icon on screen Visual Studio .NET 2nd Server Role Properties dialog box Server Roles icon 2nd 2nd server-side solutions state management 2nd 3rd 4th 5th Session object 2nd 3rd 4th serveradmin (fixed server role) servers Page 673 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html bulkadmin (fixed server role) changes updating (code) 2nd 3rd 4th data saving to (code) 2nd data grids records, deleting (code) records, posting (code) DataGrid Web server control DataList Web server control 2nd 3rd 4th 5th 6th 2nd 3rd 4th 5th 6th DataTable object tracking (code) 2nd 3rd 4th 5th 6th dbcreator (fixed server role) diskadmin (fixed server role) fixed server roles (SQL Server security) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Northwind SQL Server database Customers table list processadmin (fixed server role) Repeater Web server control securityadmin (fixed server role) serveradmin (fixed server role) setupadmin (fixed server role) SQL Server bigint data type binary data type bit data type char data type cursor data type data types 2nd 3rd 4th 5th datetime data type decimal data type fixed database roles float data type image data type int data type money data type nchar data type ntext data type numeric data type nvarchar data type real data type smalldatetime data type smallint data type smallmoney data type sql_variant data type table data type text data type timestamp data type tinyint data type uniqueidentifier data type varbinary data type varchar data type 2nd SQL Server database constraints, defining 2nd 3rd 4th 5th 6th creating 2nd 3rd 4th 5th 6th default values, defining 2nd 3rd 4th 5th 6th Page 674 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html fields, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd 3rd 4th 5th 6th 7th 8th 9th indexes, defining primary keys, defining stored procedures, creating 2nd 3rd 4th 5th tables, defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th tables, defining relationships 2nd 3rd 4th 5th 6th 7th 8th 9th views, creating 2nd 3rd 4th 5th 6th 7th 8th SQL Server database objects column properties 2nd 3rd columns 2nd creating rows 2nd table properties 2nd 3rd tables 2nd SQL Servers loading (code) sysadmin (fixed server role) Table Web server control objects, creating 2nd 2nd 3rd updating code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th Web pages break points servers. [See also SQL Server]2nd [See also Web servers]3rd [See also SQL Server] Session object Nothing keyword state management 2nd 3rd 4th values storing (code) Session objects .NET Framework Developer's Guide session variables tracking (code) 2nd 3rd sessions states SetData subroutine setting DialogResult code 2nd setting to edit mode data grids (code) setupadmin (fixed server role) sharing rights on databases shortcut menu commands New Database Role New Database User New Login SID (encrypted security ID) signatures of methods, definition single tier applications ADO (ActiveX Data Objects) 2nd smalldatetime data type (SQL Server) smallint data type (SQL Server) smallmoney data type (SQL Server) SOAP Page 675 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html XML Web Services definition (code) 2nd 3rd 4th 5th Solution Explorer Web references, viewing 2nd solutions XML Web Services sort order controlling at run-time 2nd Sort Order property Sort property DESC Sort Type property sorting columns data in DataGrid control 2nd 3rd 4th 5th 6th 7th 8th 9th 10th data grids code mailing labels 2nd records with DataView object setting in data grids 2nd setting on data grids 2nd source code for chapters in book, Web site 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th sources of records, searching sources of data choosing sp_tables stored procedure testing 2nd SQL auto-generated VB .NET tools, writing ADO.NET code 2nd 3rd BACKUP DATABASE statement BACKUP LOG statement CREATE DATABASE statement CREATE DEFAULT statement CREATE FUNCTION statement CREATE PROCEDURE statement CREATE RULE statement CREATE TABLE statement CREATE VIEW statement DTS (Data Transformation Services) strings creating (code) 2nd 3rd 4th syntax objects, creating SQL APIs (Application Programming Interfaces) 2nd 3rd references, setting 2nd 3rd SQL databases backing up verifying SQL Namespace. [See SQL-NS] SQL pane (View Designer) Page 676 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SQL queries value ranges 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th wildcards 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th SQL Server authentication mode Enterprise Manager batch updates executing 2nd 3rd 4th 5th bigint data type binary data type bit data type bulkadmin (fixed server role) char data type cursor data type data types 2nd 3rd 4th 5th databases backing up 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th restoring 2nd 3rd 4th 5th 6th 7th 8th 9th 10th tables, copying between verifying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th datetime data type db_accessadmin (fixed database role) db_backupoperator (fixed database role) db_datareader (fixed database role) db_datawriter (fixed database role) db_ddladmin (fixed database role) db_denydatareader (fixed database role) db_denydatawriter (fixed database role) db_owner (fixed database role) db_securityadmin (fixed database role) dbcreator (fixed server role) decimal data type Detach/Attach SQL Server Database dialog box creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th diskadmin (fixed server role) DMF (Distributed Management Framework) APIs (Application Programming Interfaces) 2nd 3rd float data type image data type int data type money data type nchar data type ntext data type numeric data type nvarchar data type objects creating with ADO (ActiveX Data Objects) 2nd 3rd 4th point-and-click SQL Server query tool creating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th processadmin (fixed server role) public (fixed database role) real data type results retrieving with DataTable object securityadmin (fixed server role) 2nd 3rd 4th 5th 6th Page 677 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html serveradmin (fixed server role) setupadmin (fixed server role) smalldatetime data type smallint data type smallmoney data type sql_variant data type stored procedures executing (code) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th executing with ADO (ActiveX Data Objects) 2nd 3rd 4th sysadmin (fixed server role) T-SQL commands 2nd table data type text data type timestamp data type tinyint data type trusted connections UDFs (user-defined functions) calling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, formatting 2nd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th creating (code) 2nd 3rd parameters, passing scalar types, returning 2nd table types, returning 2nd uniqueidentifier data type varbinary data type varchar data type views flexibility Windows NT Integrated Security users, logging into databases SQL Server 2000 database data, retrieving 2nd 3rd 4th 5th 6th 7th fixed database roles SQL Server 7.0 SQL Server Authentication button 2nd SQL Server database constraints defining 2nd 3rd 4th 5th 6th creating 2nd 3rd 4th 5th 6th default values defining 2nd 3rd 4th 5th 6th detaching (code) fields defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th indexes defining 2nd 3rd 4th 5th 6th 7th 8th 9th Northwind CustOrdersHist stored procedure, T-SQL code primary keys defining 2nd 3rd 4th 5th 6th 7th 8th 9th stored procedures creating 2nd 3rd 4th 5th tables defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th Page 678 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html relationships, defining 2nd 3rd 4th 5th 6th 7th 8th 9th views creating 2nd 3rd 4th 5th 6th 7th 8th SQL Server database objects column properties 2nd 3rd columns 2nd creating rows 2nd table properties 2nd 3rd tables 2nd SQL Server databases attaching code 2nd SQL Server Login Properties dialog box 2nd SQL Server objects creating code SQL Server security 2nd application roles 2nd 3rd 4th 5th authentication, mixed-mode custom database roles 2nd 3rd 4th 2nd 3rd 4th 5th 6th database user accounts, creating 2nd 3rd 4th 5th 6th fixed database roles fixed server roles 2nd 3rd 4th 5th 6th 7th 8th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th object permissions 2nd 3rd 4th 5th 6th standard logins, creating 2nd 3rd 4th 5th statement permissions 2nd 3rd 4th 5th 6th 7th Windows NT/2000 authentication mode 2nd 3rd 4th 5th 6th 7th 8th groups, creating 2nd 3rd 4th 5th 6th logins, creating 2nd 3rd 4th 5th 6th users, adding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th SQL Servers backup devices names, retrieving (code) 2nd SQL servers database names, retrieving (code) 2nd 3rd SQL Servers listing in SQL-DMO 2nd loading code 2nd 3rd 4th 5th 6th 7th loading (code) SQL statements actions, executing 2nd building with Query Builder creating displaying in labels 2nd executing code 2nd 2nd executing (code) loading code 2nd 3rd storing code 2nd 2nd storing (code) Page 679 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html SQL strings building (code) creating code 2nd SQL-Distributed Management Objects. [See SQL-DMO] SQL-DMO (SQL-Distributed Management Objects) 2nd 3rd collections 2nd databases backing up connecting to 2nd Detach/Attach SQL Server Database dialog box, creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th dialog boxes connecting to databases 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th objects 2nd 3rd 4th 5th 6th 7th 8th 9th 2nd databases, backing up and verifying SQL APIs (Application Programming Interfaces) references, setting 2nd 3rd SQL Server DMF APIs (Application Programming Interfaces) 2nd 3rd SQL Server databases backing up 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th restoring 2nd 3rd 4th 5th 6th 7th 8th 9th 10th tables, copying between verifying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th SQL Servers listing 2nd SQL-DTD objects tables, copying SQL-DTS 2nd (Data Transformation Services) 2nd data exporting objects data, exporting SQL-NS (SQL Namespace) SQL. [See also T-SQL] sql_variant data type (SQL Server) SQLBackup method SQLC lient classes performance improvement 2nd SQLC lient objects and OleDb objects, comparing SqlC ommand (data control) SqlC onnection (data control) SqlDataAdapter (data control) ? (question mark) SQLDMO Object Library SQLRestore method SQLServer object Page 680 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html methods properties square brackets ([ ]) standard logins, creating 2nd 3rd 4th 5th Standard Report Expert dialog box tabs 2nd Standard Report Wizard Chart tab Data tab Fields tab Filter tab Group tab Style tab tabs 2nd 3rd 4th Top N tab Total tab Standard reports state management on clients 2nd server-side solutions 2nd 3rd 4th 5th Session object 2nd 3rd 4th state management objects values, storing stateless programming (Web pages) clients state management 2nd server-side solutions state management 2nd 3rd 4th 5th Session object 2nd 3rd 4th statement permissions deny state grant state revoke state statement permissions (SQL Server security) 2nd 3rd 4th 5th 6th 7th statements ALTER TABLE 2nd BACKUP DATABASE BACKUP LOG BEGIN BETWEEN data, generating (code) 2nd 3rd C atch in Try[ellipsis dots]Catch[ellipsis dots]End Try block CREATE DATABASE CREATE DEFAULT CREATE FUNCTION CREATE PROCEDURE CREATE RULE CREATE TABLE 2nd 3rd 4th CREATE VIEW DECLARE DROP TABLE 2nd END EXIST IF LIKE Page 681 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html data, generating (code) SELECT ALL clause data, displaying (code) DISTINCT clause updating (code) 2nd 2nd SQL actions, executing 2nd building with Query Builder creating displaying in labels 2nd executing (code) loading (code) storing (code) 2nd 3rd 4th 2nd 3rd 2nd 3rd 4th update executing states application database support deny (statement permissions) grant (statement permissions) revoke (statement permissions) session Step object methods properties Stored Procedure with Parameter button stored procedures break points, setting 2nd calling code 2nd 3rd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th C ustOrdersHist T-SQL code executing code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 2nd objects, properties and methods parameterized, executing in ADO.NET 2nd 3rd 4th 5th 6th 7th 8th records sp-tables testing 2nd T-SQL (Transact-SQL) TextBox control, populating 2nd stored procedures (SQL Server) executing with ADO (ActiveX Data Objects) 2nd 3rd 4th storing key values code 2nd 3rd 4th SQL statements code values to Session object (code) Stream object String Collection Editor 2nd 2nd 2nd 3rd 4th strings connection Page 682 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html BuildCnnStr( ) function creating (code) 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd establishing (code) text, displaying 2nd LoadSQLString routine query definition SELEC T columns SQL building (code) creating (code) strings. 2nd 2nd 3rd 4th 5th 6th [See also connection strings] StringValue property code strongly typed datasets VB .NET tools ADO.NET code, writing 2nd 3rd strongly typed reports 2nd ReportSource property 2nd strSQL SQL statements executing (code) 2nd Style tab Standard Report Wizard styles Red/Blue border 2nd subqueries SQL statements loading and executing (code) T-SQL 2nd 3rd 4th 5th 6th SubReport reports subroutines ActiveEditing calling (code) 2nd errors, throwing 2nd LoadTables( ) LoadUnSelectedProducts LoadUnUnselectedProducts OpenNorthwindADOConnection RefreshIndividual calls, code to add 2nd SaveRecord code SetData syntax SelectionFormula reports, printing 2nd SQL objects, creating variables assigning sysadmin (fixed server role) System.XML namespace System.XML.Schema namespace System.XML.Xpath namespace Page 683 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html System.XML.XSL namespace systems exceptions sysxlogins table [ Tea m LiB ] Page 684 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] T-SQL (Transact-SQL) CustOrdersHist stored procedure, code Server objects creating;code 2nd T-SQL (Transact-SQL) stored procedures, creating T-SQL commands BETWEEN operator 2nd built-in functions 2nd creating 2nd functions 2nd 3rd 4th 5th local variables declaring 2nd initializing 2nd records finding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th inner joins joins left outer joins 2nd right outer joins 2nd records, retrieving 2nd 3rd 4th 5th 6th 7th 8th 9th 10th SQL queries value ranges 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th wildcards 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th SQL Server SQL Server UDFs (user-defined functions) calling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, formatting 2nd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th parameters, passing scalar types, returning 2nd table types, returning 2nd subqueries 2nd 3rd 4th 5th 6th tables ALTER TABLE statement 2nd CREATE TABLE statement 2nd 3rd creating 2nd 3rd 4th 5th 6th creating, modifying, deleting DROP TABLE statement 2nd variables 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th tab pages controls 2nd Table control data displaying 2nd 3rd 4th 5th 6th 7th 8th 9th loading code 2nd 3rd 4th 5th persistence properties Table controls tables, displaying 2nd Page 685 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Table data type creating and returning table data type (SQL Server) Table Designer Table function Table Mappings collection 2nd Table object properties Table Properties dialog box Permissions tab 2nd Table property 2nd table types returning UDFs (user-defined functions) Table Web server control objects, creating 2nd 2nd 3rd 2nd TableC ell object properties TableRow object properties tables 1stLookupTables pointing to items (code) Alias property ALTER TABLE statement 2nd Column property 2nd columns adding data, entering listing in databases (code) sorting sorting (code) 2nd 2nd 3rd copying between SQL Server databases code 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th CREATE TABLE statement 2nd 3rd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th Criteria property customer demographics, tracking C ustomers CustomerID column 2nd Server Explorer Customers table list Customers, CustomerCustomerDemo, and CustomerDemographics data adding data (code) binding (code) creating 2nd data, adding (code) loading (code) 2nd 3rd 2nd 3rd 4th 5th 6th 7th 8th 2nd 3rd 2nd 3rd 2nd records, adding (code) records, locating (code) schemas, loading 2nd text boxes, assigning values (code) DataItem.RegionURL column 2nd defining 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th Page 686 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html deleting 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th displaying with Table control 2nd DROP TABLE statement 2nd EXIST statement expressions 2nd fields properties formulas 2nd Group By property IF statement in datasets inner joins joining 2nd listing in databases code 2nd 3rd 4th 5th 6th 7th 8th LoadTables( ) subroutine lookup data, adding 2nd 2nd information, managing updating 2nd updating, data-driven techniques 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th many-to-many relationship modifying 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 2nd one-to-many relationship one-to-one relationship Or property Orders CustomerID column 2nd Output property primary key field ProdAndCatTab 2nd 2nd properties 2nd 3rd records adding to data tables (code) cascade deletes finding 2nd 3rd 4th 5th 6th 7th 8th 9th 10th inner joins 2nd joins left outer joins 2nd 2nd right outer joins 2nd referential integrity 2nd 3rd relationships defining 2nd 3rd 4th 5th 6th 7th 8th 9th Report Expert 2nd results displaying rows deleting in data grids (code) saving searching 2nd 3rd 4th 2nd 3rd security Web Services, creating with parameters 2nd SELECT statement Page 687 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Sort Order property Sort Type property SQL Server database objects 2nd 3rd 4th 5th sysxlogins Table property tblCustomerPhones, creating tblCustomers 2nd tblPhones View Designer 2nd wrapping Tables in Report list TabPages property 2nd tabs of Report Expert, viewing Standard Report Expert dialog box 2nd Standard Report Wizard 2nd 3rd 4th tags element Task object methods properties tasks DTS packages 2nd tblCustomerPhones table, creating tblCustomers table tblPhones table techniques. telephone. 2nd [See also data-driven techniques] [See phone] templates ASP.NET Web Service 2nd 3rd data grids Repeater control data, displaying 2nd 3rd temporary users, removing territories repTerritories Repeater control code HTML code loading (code) territories (regional), displaying 2nd 3rd testing constructors code 2nd 3rd 4th Delete method code Hello World method 2nd Save method code sp_tables stored procedure 2nd XML Web Services 2nd 3rd 4th 5th 6th XML Web Services security 2nd TestUserPassword method 2nd 3rd text of connection strings, displaying 2nd text boxes binding Page 688 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html to datasets to list boxes 2nd 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 2nd binding and viewing Confirm Password Description 2nd disabling (code) 2nd 3rd 4th frmHowTo1_3.vb datasets, refreshing (code) Group Name 2nd 2nd records loading (code) 2nd 3rd 4th 5th 6th 7th 8th Text property, setting toggling (code) 2nd 3rd 4th 5th 6th values assigning (code) values, writing (code) text data type (SQL Server) 2nd 2nd Text property of Label object setting validation controls TextArea control TextArea object properties 2nd TextBox control populating 2nd properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th settings 2nd 3rd 4th settings for frmHowto_3 2nd 3rd 4th property settings 2nd 3rd 4th TextBox object 2nd properties 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd TextBoxC hange method text boxes, writing values (code) 2nd TextC hanged event code 2nd 3rd ThrowException method declaring code throwing errors 2nd timestamp data type (SQL Server) tinyint data type (SQL Server) toggling btnDetach button, code enabled properties of buttons (code) 2nd 3rd 4th 5th text boxes code 2nd 3rd 4th 5th 6th toolbox icon on screen tools Administrative Tools groups and users, adding VB .NET ADO.NET code, writing 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th ADO.NET code, writing;XSDs 2nd 3rd Page 689 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html Top N tab Standard Report Wizard ToString method property information output (code) 2nd Total tab Standard Report Wizard tracking customer demographics DataTable object code 2nd 3rd 4th 5th 2nd 3rd session variables (code) Transact-SQL (T-SQL) stored procedures, creating Transact-SQL. transfer. [See T-SQL] [See copy] trapping exceptions with Try[ellipsis dots]Catch[ellipsis dots]End Try block save exceptions (code) Trim function trusted connections (SQL Server) 2nd Try[ellipsis dots]C atch[ellipsis dots]End Try block Catch statements controls, ignoring exceptions, trapping Try[ellipsis dots]Catch[ellipsis dots]Finally block Try[ellipsis dots]C atch[ellipsis dots]Finally blocks exceptions 2nd type libraries C OM registering referencing with ADO (ActiveX Data Objects) 2nd 3rd types scalar returning for UDFs (user-defined functions) 2nd table returning for UDFs (user-defined functions) types. 2nd [See also data types] [ Tea m LiB ] Page 690 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U ] [V] [W] [X] UDFs (user-defined functions) assigning code 2nd calling 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code, formatting 2nd creating 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th code 2nd 3rd 4th 5th data displaying (code) parameters, passing scalar types, returning 2nd SELEC T statement, updating code 2nd table types, returning 2nd Unassigned Products Only check box 2nd 3rd unbound controls on forms underscore (_) Unicode uniform resource locators. [See URLs] uniqueidentifier data type (SQL Server) Unselected Products ListBox control Update command code Update command text, code Update method 2nd 3rd 2nd 3rd 4th update object permission update statements executing UpdateCommand method updates batch executing 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th batch (on-the-fly), executing in ADO.NET updating changes to servers (code) data 2nd 3rd 4th 5th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th data grids code databases methods, implementing lookup tables 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th data-driven techniques 22nd 23rd 24th 25th 26th 27th 28th 29th 30th 31st 32nd 33rd 34th 35th 36th 37th 38th 39th 40th 41st 42nd 43rd 44th 45th 46th page indexes in data grids (code) records 2nd 3rd 4th recordset fields SELEC T statement code 2nd Page 691 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html servers code 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th URLs creating 2nd DataItem.RegionURL column Use Distinct button Use UDF button UseAStoredProcedureWithAParameter routine code user accounts for databases, creating 2nd 3rd 4th 5th 6th user-defined functions user-defined functions. [See UDFs] usernames validating code 2nd users adding to Windows NT/2000 2nd 3rd 4th 5th 6th 7th 8th 9th 10th data notifying to edit 2nd files exporting 2nd logging into databases Names list 2nd of reports, flexibility 2nd records saving before closing (code) 2nd reports controlling data viewed temporary, removing Windows NT/2000 domains, displaying 2nd 2nd 2nd Users Must Enter a User Name and Password to Use This Computer check box [ Team LiB ] Page 692 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html [ Team LiB ] [SYMBOL] [A] [B] [C ] [D] [E] [F ] [G] [H] [I] [J ] [K ] [L] [M] [N] [O] [P] [Q] [R ] [S] [T] [U] [V] [W] [X] Validate method ValidateC ustomerID method code validating data 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th data on Web Forms passwords code 2nd 2nd 3rd 4th phone numbers (code) usernames code 2nd 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th 13th 14th 15th 16th 17th 18th 19th 20th 21st 22nd 23rd validation code, writing 24th 25th 26th 27th validation controls code CompareValidator CustomValidator 2nd for Web Forms property settings 2nd 3rd messages, displaying on Web Forms RangeValidator Regular ExpressionValidator RequiredFieldValidator ValidationSummary 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th validation controls (Web Forms) property settings 2nd 3rd 4th 5th validation errors for controls 2nd Validation Web server controls 2nd 3rd ValidationExpression property ValidationSummary control lists, look of ValidationSummary object properties validator controls reaction inconsistencies Value method value ranges SQL queries 2nd 3rd 4th 5th 6th 7th 8th 9th 10th 11th 12th ValueMember property ValueMember property (list boxes) values default, defining DeliveryDate 2nd 3rd 4th 5th 6th 2nd 2nd in text boxes, writing (code) key, storing (code) 2nd 3rd 4th lookup tables updating 2nd null Allow Nulls null, interpreting OrderID 2nd Page 693 ABC Amber CHM Converter Trial version, http://www.processtext.com/abcchm.html return ProdAndCatTab table storing to Session object (code) varbinary data type (SQL Server) varchar data type (SQL Server) 2nd variables ampersand ( & ) variables, declaring assigning syntax class, declarations (code) DECLARE statement local declaring in T-SQL 2nd initializing in T-SQL 2nd mbAddNew resetting;code 2nd mFax event handlers (code) placing under forms code 2nd public declaring (code) session tracking (code) 2nd 3rd 4th 5th T-SQL commands 2nd 3rd 4th 5th VB .NET ADO.NET code, writing SQL (auto-generated) strongly typed datasets XSDs 2nd 3rd 2nd 3rd 2nd 3rd classes default properties defining 2nd 3rd 4th 5th methods;adding to interfaces parameterized properties properties 2nd 3rd 4th properties;adding to interfaces read-only properties 2nd 2nd 3rd write-only properties 2nd properties modifiers property declarations Public access modifiers 2nd reports displaying 2nd 3rd 4th 5th 6th 7th exporting 2nd 3rd 4th 5th 6th 7th 8th 9th printing 2nd 3