To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Introduction
-----------

What's On The CD-ROM About the Authors Part I—Basics Of Client/Server Development With Visual Basic 6 Chapter 1—An Introduction To Client/Server And Networks
A History Of Files What The Heck Is Client/Server? Designing The Client/Server System Network Topologies And Architectures Network Protocols Network Operating Systems Where To Go From Here

Chapter 2—Relational Database Management Systems
Relational Databases Vs. Relational Database Management Systems Considerations In Selecting An RDBMS A Survey Of Available RDBMSs Database Organization

Database Design Data Definition Language Data Control Language Where To Go From Here

Chapter 3—An Introduction To SQL Data Manipulation Language
What Is SQL? A Note About ODBC Data Manipulation Language (DML) Where To Go From Here

Chapter 4—Visual Basic 6 Data Access
Visual Basic Data Access Trends What’s Behind Door Number One? So…What Flavor Tastes Best? Where To Go From Here

Part II—Visual Basic 6 Database Programming Chapter 5—Data Access Objects (DAO)
DAO Object Models DAO Objects The Data Control Where To Go From Here

Chapter 6—Remote Data Objects (RDO)
What Is RDO? Overview Of Remote Data Objects Exploring Remote Data Objects The Remote Data Control Bonus: The RDO Ad Hoc Report Writer Where To Go From Here

Chapter 7—Introducing ADO And OLE DB
Microsoft Data Access Components ADO Overview Using ADO Objects

The Active Data Control Where To Go From Here

Chapter 8—Converting To ADO
ADO Compared To DAO And RDO Converting The Application Where To Go From Here

Chapter 9—Advanced ADO Client/Server Techniques
The Data View Window Using The DataEnvironment Object Using The DataReport Object Command And Recordset Hierarchies Other Data Access Tools In Visual Basic 6 Where To Go From Here

Chapter 10—Creating Business Objects With Visual Basic 6
Introducing The Business Object The Business Object Relocating The Business Object Where To Go From Here

Chapter 11—Visual Basic 6 Advanced Database Topics
Data Validation Keeping Common Data In Memory Stored Procedures And Triggers Generating Primary Keys Result Set Size The Nature Of Transactions Where To Go From Here

Part III—Visual Basic 6 And The Internet Chapter 12—The ABCs Of XML
Regaining Context With XML

Leveraging The MS XML API Describing Your Data: The DTD Building An XML Application Where To Go From Here

Chapter 13—Serving Up The Web
Serving With Distinction: A History Of CGI The Problem With Scripting Beyond The Canon Linking Events Getting Browser Capabilities Where To Go From Here

Chapter 14—The Dynamic Client
The Role Of The Client The Dynamic HTML Application Exploring The Internet Explorer Object Model Building Tables Understanding Input Where To Go From Here

Chapter 15—Power Tools
Image Handling Doing It With Style Maintaining A Dialog Box Accessing ActiveX And Applets The Future Of Internet Programming… Summary Bibliography

Part IV—Appendixes Appendix A—Creating The Sample Database Appendix B—Differences Between Jet SQL And ANSI SQL Appendix C—ODBC Functions

Index
Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Table of Contents

-----------

Introduction I have a confession to make. As recently as a year ago, Visual Basic was not
my preferred tool to develop client/server applications. I have been developing database applications for two decades and have used many languages and tools. While I will never claim to know it all, I have a good sense for what works in the real world and what doesn’t work. As far as client/server development is concerned, Visual Basic 5 seemed to me to be right on the edge as far as being a viable tool for large applications. Visual Basic 6 has changed my attitude. The client/server developer needs a development tool, not a language. The tool needs to be robust, needs to support a myriad of different backends (data sources) and needs to be able to produce a variety of different types of applications from single-user desktop solutions to multi-tiered applications deployed on the Internet. Visual Basic 6 is a superb tool adaptable to those types of projects and more. VB 6 is not best of breed in all categories. Weaknesses remain in areas such as object-orientation and data modeling. The tools that are there sometimes lack a little in how well they are integrated. Even still, VB6 is today’s best choice for rapid application development of data driven applications in a client/server environment. In this book, my co-author Kurt Cagle and I have gleaned what works and what doesn’t from months of work with VB6 betas using a variety of backends and application platforms. Between us, we have almost four decades of real-world experience. We have put together a book that is neither a rehash of the Help files nor a pie-in-the-sky Microsoft marketing brochure. We have assembled a guide to the development of client/server applications that will scale as you need and that will comfortably accommodate the rapid changes in

technology. We have kept our eye to the target audience, the experienced Visual Basic developer, while acknowledging that “experienced” means many different things in many different environments. We do not insult the reader’s intelligence with blow-by-blow details of using the Application Wizard, for instance. But, we also do not assume that the reader has previously built large-scale, multi-tiered, client/server systems. In fact, very few VB developers have built such applications. So, we lay the groundwork as we incrementally build the core knowledge from chapter to chapter. Chapters 1 through 3 concentrate on the environment within which the Visual Basic client/server application will be running. We discuss the whys and therefores of client/server in terms of the network and the database. We discuss and summarize network issues and database platform issues. We show you how to intelligently design a database and how to use SQL. In Chapter 4, we cover the gamut of Visual Basic 6 database access techniques, including DAO, RDO, ODBC, VBSQL, and ADO. We offer specific advice on when to use what as well as our opinions on the relative merits (and de-merits) of each approach. Chapters 5 and 6 cover development using DAO and RDO respectively. While most developers will eventually move to ADO, both DAO and RDO will be around for some time to come. Chapter 7 introduces ADO and OLE DB. We then show you how to use these new tools, taking the time to compare and contrast with the more familiar DAO and RDO models. In Chapter 8 we guide you through the conversion of existing DAO and RDO projects to ADO. We use as scenarios example projects built in Chapters 5 and 6 and provide detailed step-by-step guidance. Again, we provide this guidance in a real-mode manner, resorting to brute-force techniques when such techniques work best. Chapter 9 gets into more advanced and efficient techniques using ADO and OLE DB. We show you some of the newer tools with detailed examples. We discuss the DataEnvironment object, the DataRepeater object, the Format object, and so on. We make no bones where things are a little rough around the edges, showing you how to get around the flaws in hierarchical data presentations and similar gotchas. Chapter 10 is where we start hammering away at solid object-oriented development techniques instead of just paying lip service to them. We detail the advantages and disadvantages of different approaches to object-oriented development using classes. We discuss the efficiencies and inefficiencies in different binding techniques. From there, we develop business objects from classes that act as data providers to different objects, optimizing each for the circumstances under which they are deployed. We show you critical gotchas when moving the local business object to a remote platform and, frankly, show you how to plain make it work. Chapter 11 takes advantage of the knowledge assembled in the first ten chapters to explore advanced database techniques, including the creation and use of stored procedures and triggers. We deliberately placed this chapter at this point in the book both because these techniques help to solidify the traditional client/server application and because the techniques are absolutely

critical to the success of Web-based applications, which we discuss in the remainder of the book. Because so much is said about stored procedures and triggers, and because so few shops actually make effective use of them, we explore unusual uses of them both in terms of data validation and in the creation of a self-referencing data dictionary. And that brings us to the last third of the book: VB6 and the Internet. While client/server applications are, by definition, network applications, the Internet is the mother of all networks. The Internet connects 79 million people in the United States alone. With servers in excess of 10 million and Web pages in excess of 300 million, the Internet only continues to accelerate its growth. The astonishing thing is each of those 79 million plus people are all connected to one another and to many millions more around the globe, each one redefining what we mean by client/server programming. As cable modems and DSL lines begin to replace 28Kbps and 56Kbps analog modems, the number of people and uses for the Internet will jump astronomically as will the expectations of users. Client/server programming is all about getting data to and from the user. Visual Basic 6 dramatically redefines the boundaries between client and server, between data and user, offering a combination of one of the best RAD development environments on the planet with all the power of Active Server Pages and Dynamic HTML. In essence, with Visual Basic 6 you can create sophisticated Web applications targeted to the widest possible audience using the same tools that you have already mastered for other client/server development. The final four chapters of this book focus on this new technology, with an in-depth look at Internet Information Services applications and Dynamic HTML applications. Additionally, one of the hottest topics in data communications, Extensible Markup Language (also known as XML), is explored in detail, showing how you can take advantage of this new data standard in your own programs. Finally, this book looks at several useful technologies for the Internet-savvy database engineer, including remote component servers, client- and server-side scriptlets, data persistence, and more. There is no right way or wrong way to use this book. (Well, using it as a door stop or as something to raise your monitor probably isn’t the best use we could imagine.) The experienced client/server developer may skim or skip over the first three chapters. Those readers new to client/server may wish to spend extra time on those chapters. Those readers that are making a commitment to ADO should at least read Chapters 7 and 9 before skipping ahead to the fun stuff (Web development). Those looking to check out the viability of Web-based development may well want to skip ahead to Chapter 12 before coming back to other portions of the book. We have tried to include at the front of each chapter some keywords to highlight topics to be covered and have tried to include at the end of each chapter some suggestions for where you may want to go next. Also be sure to check out the code samples on the enclosed CD-ROM. Several

people checked each piece of code. Although we have strived to make sure that every application works properly, the nature of the material is such that it was not possible to test on every single combination of platforms. As an example, you may need to make minor alterations in SQL syntax depending on what database you are connected to. Please pay particular attention to the fact that you will need to do some setup on your own system. Many of the examples use an ODBC data source—after creating the database (we have included the SQL statements to do so on the CD-ROM), you will need to set up the ODBC data source in the Control Panel. The paths to the data in some of the examples may need to be changed to reflect your paths. Also, pay particular attention to the fact that some samples connect to server applications. Since these sever applications need to be registered (see Chapter 10 in particular), you will need to compile them, go to the References dialog box, and reselect the references. Otherwise, you will get mysterious error messages. For the Internet chapters, please note that many of the examples were done using Internet Explorer version 5. You may wish to download that from the Microsoft Web site. We would have included it on the CD-ROM but it was in beta as this book was going to press and a more current release will surely be posted before you read this. You can use Access for most of the examples from this book if you want to experiment at home or otherwise do not have access to a relational database. You can also download trial versions of a number of different good single-user database engines. Sybase SQL Anywhere (renamed Sybase Adaptive Server Anywhere as this book was going to press) is an easy-to-set-up and use product available from www.sybase.com/products/anywhere/index.html for a free 60-day trial. If you like the book, please buy a couple dozen more. You can give them to your kids, your spouse, your mother (she will be impressed and thankful) and your boss (he or she will also be impressed and will give you a raise). Coriolis always invites comments, suggestions, criticisms, and so on. Visit their Web page at www.coriolis.com to find contact information or to check out any updates to the book. Thank you, Michael MacDonald (mikemacd@tiac.net) Kurt Cagle (cagle@olywa.net)

Table of Contents

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Table of Contents

-----------

What’s On The CD-ROM
The enclosed CD-ROM contains all of the source code examples from this book, plus many bonus examples. You will find them organized by chapter. Please remember to make any changes needed to reflect your own environment. See the readme file on the CD-ROM for more information. Also included on the CD-ROM is a collection of utilities that I believe you will find helpful. Please note that this book was written while Visual Basic 6 was being beta tested; therefore some of these utilities may have been updated to take advantage of VB6 after the book went to press. • Advantageware VB Advantage—A design-time add-in that gives you the power to quickly and easily customize your design environment with a broad range of powerful tools. (Trial version) • Apex Software: True DBGrid Pro, True DBInput, True DBList Pro, True DBWizard—Enhanced controls to help speed up your coding. • Bokler Software Hashcypher—An ActiveX control that allows you to easily provide robust data encryption using the Secure Hash Algorithm (SHA-1). (Trial version) • Caladonia Systems Code Print Pro— Allows you to generate formatted, professional documentation that spans multiple projects or specific sets of routines. (Trial version) • Catalyst Socket Tools—A collection of TCP/IP networking components and libraries for Windows that assist you in developing Internet and intranet applications. (Trial version) • CoffeeCup HTML Editor—A top-rated, WYSIWYG HTML editor with many new and cool features to create and deploy web pages with “attitude.” (Trial version) • DeltaPoint QuickSite—The most productive way to create, manage,

and sell through your Web site. (Trial version) • Suprasoft Crystal Reports Crystal Design Component—A custom component that encapsulates the previewing of Crystal Reports reports inside of an easy-to-use control. This is an efficient and productive building block to create a unique and customized preview application or front end for your software. (Limited version)

Requirements:
• • • • Minimum of 486 or equivalent processor 16MB RAM Windows 95/98/NT Visual Basic 6

Table of Contents

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Table of Contents

-----------

About the Authors
Author of seven books and dozens of magazine articles, Michael MacDonald has nearly 20 years of experience in software development covering all major platforms. An independent consultant specializing in client/server and databases, Michael is also an instructor in the client/server certificate program for Worcester Polytechnic Institute and a courseware developer. Kurt Cagle is an Internet developer and multimedia specialist with 18 years of experience in the field, concentrating on client-side and interface issues. He is the author of 3 books and more than 50 magazine articles on many aspects of the computer revolution, and has done work for Microsoft, AT&T, RealNetworks, Starwave, and many other major computer and technology-related corporations.

Acknowledgements
This is the area where I always get to thank everyone who so much as returned a phone call. But, there were some very special people behind this book. I am especially indebted and grateful to the publisher itself, Coriolis Group Books, for allowing the extra time to produce a book that was solid instead of a book that was early to market. It says a lot about the integrity of an organization that puts quality ahead of profits. I want to thank the Acquisitions Editor for this project, Stephanie Wall, for giving me the opportunity to do this book and for a lot of cheeriness and professionalism. Toni Zuccarini was the project editor, which is a job that does not get near enough thanks or recognition. Toni coordinated a myriad of details with grace and aplomb. John Lueders was the technical editor and painfully (to me as well as to him I am sure) reviewed every line of code in the book and on the CD-ROM, offering advice and criticisms, and did it well. Kristine Simmons was the copy editor for the project. Copy editors are those people who review manuscripts for clarity and

grammatical correctness. Kris offered many fine suggestions and untangled sentences and thoughts far better than I ever could have. I have worked with many copy editors and (I mean this in all sincerity) Kris is probably the best. I have to acknowledge the contributions of my co-author, Kurt Cagle, who stepped up to bat to handle Chapters 12 through 15 and really did a fantastic job. There are many people who go into the creation of a book who work behind the scenes without much in the way of recognition: Alan Pratt is the Technology Director and keeps, well, technical things moving between Coriolis and authors; Robert Clarfield coordinates a blizzard of details in getting that CD-ROM into the back of this book; Wendy Littley is the Production Coordinator and is in charge of getting the text laid out, getting proofs, coordinating among a zillion people, and so on; Tony Stock designed the cover of this book (and you thought I did that myself!) invisibly but professionally; and there are many others. To all of them—thanks. I need a vacation!

Dedication
As always, to my family—my wife, Patricia, and my children, Amanda and Peter—who are the ones that truly make the sacrifices when I work past midnight. Also, to some very special colleagues who it has been my privilege to work with for more than a decade, including Larry Altrich, Steve Remmes, and Randy Vance. And finally, to a person who took a neophyte under his wing almost 20 years ago, Dr. Thomas Gross. —Michael MacDonald To my parents, who taught me that humor and compassion will defeat arrogance and stupidity every time. —Kurt Cagle

Table of Contents

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Part I Basics Of Client/Server Development With Visual Basic 6 Chapter 1 An Introduction To Client/Server And Networks
Key Topics: • How we arrived at the relational data model • Distributed computing • The definition of client/server • 2-tiered, 3-tiered, and n-tiered architectures • The Microsoft Services model • COM/DCOM and the Component model • Application partitioning • Network topologies and architectures

The migration to client/server development has its roots in the nature of
networks, which excel in the sharing of data and devices and the cooperative processing of multiple clients, but are hampered by problems endemic to the limited amount of data that can be transmitted at the same time. Client/server solutions seek to maximize the strengths of networks while limiting their weaknesses.

In this chapter, I introduce the underpinnings of client/server and how it evolved from the distributed data model of the 1970s and 1980s to the multi-tiered model of today. For some readers, this material is old hat; skim it or move on to the next chapter. For others, however, the material provides real-world background upon which to set in context the remainder of the book. The material is as applicable to development with any language as it is to development with Visual Basic (VB). Organizationally, this chapter is far ranging in the topics covered. I discuss the evolution of file formats and how they led to the relational model of today and the object model of tomorrow, as well as how these files evolved to support the distributed data format that was a direct ancestor of client/server today. I define basic and advanced client/server architectures, and I conclude with a review of the network topologies and architectures upon which client/server is based.

A History Of Files
Since the inception of the computer, there have really been only three file types: sequential, navigational, and relational. We are now seeing the introduction of a fourth type, the object model, along with relational/object hybrids. Concomitant with this evolution has been a shift of responsibility from the application to the database. For instance, in the sequential model, the application was responsible for the location of any given record as well as for the enforcement of all business rules. In the following sections, I review the evolution of files; in other sections of the chapter, I point out how this evolution mirrors the move to client/server development.

Sequential Model
Sequential files consist of fixed-length records, each of which typically contains fixed-length fields. The 80-column cards of old were essentially sequential files as were (and are) files stored on magnetic tape. A variation on the sequential model, text files, evolved when computer languages evolved to the point where they could use a character (such as a carriage return) as a record delimiter instead of depending on the end of a record being in a fixed location. Files such as AUTOEXEC.BAT and CONFIG.SYS are text files. Visual Basic supports both forms of sequential files, using the Open keyword to open the file, Close to close the file, and a variety of keywords to read from and write to the file depending on the nature of the file’s use. I review these in Chapter 4. The key advantages of the sequential file model are simplicity of programming file access and the speed with which an entire file can be processed. On the other hand, it is not possible with sequential files to locate any one record without first reading all other records before it. For instance, to pull up John Smith’s customer record, it is necessary for the program to read the first record in the file and determine whether it is the correct one. If it is not, the program must read the next record and so on until the desired customer is found. As a result, the sequential file model also does not support any type of ad hoc

reporting capabilities. The application program is responsible for all file I/O, for all record searches and updates, and for all data integrity measures (such as ensuring that an order has a valid customer). Some improvements were realized by using random access techniques. In theory, if your application knew that John Smith’s record was the 318th record in the file, the program could move directly to that record without reading the first 317 records. The caveat, of course, is that the application was then responsible for creating and maintaining some sort of index into the file—not an easy piece of logic to code. Programming languages had to evolve to support this as Visual Basic does when files are opened in Random mode. Random access requires that every record be fixed length. A variation is Binary mode where, instead of accessing a record by specifying its record number, the program uses a byte offset from the beginning of the file.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

Often. On the mainframe. the details of this navigation were hidden from the developer so that the database did the dirty work of locating a specific record.To access the contents. Using a file opened in random access mode. Common examples were dBase and Btrieve files. click the chapter and section titles. The term stems from the fact that it was usually necessary to “navigate” to a desired record by first accessing other records. Each table has a unique identifier. An Orders table would be related to a Customer table via a common customer number column: Each table has a column containing customer number. Although the interface provided is SQL. the underlying file is still accessed navigationally. this method is implemented in a manner similar to what C programmers know as linked lists. Visual Basic also allows connection to navigational databases via the Microsoft Jet engine. An example of a primary key might be customer number. Visual Basic supports the navigational model in two ways. The foreign key is a special type of index on the database that . which allows the retrieval of any one row without referring to any other row. Microsoft refers to this as Indexed Sequential Access Method (ISAM). The relationship is enforced via a foreign key. you can manually maintain some sort of hashing algorithm to navigate from record to record. Relational Model The relational model organizes data into related tables. called a primary key. Often. A table is a two-dimensional grid of columns and rows where each row is a record and each column is a field in that record. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Navigational Model The navigational file model—sometimes called the hierarchical model—was a major improvement. the navigation model was implemented with Virtual Sequential Access Method (VSAM). Tables are related by common information. A linked list essentially maintains a series of pointers into a structure or file allowing navigation by (for example) account number or customer name.

Networks were (and are) a natural platform on which to distribute data. With the increased use of networks. There are a number of vendors of relational database management systems (RDBMSs). On the other hand. This solution had the added benefit of spreading processing loads to multiple machines.” This enforcement is called referential integrity. These enforced rules are called constraints. it was difficult to update information that was spread over multiple computers. Microsoft. including Oracle. Contrary to popular belief. the United States government contracted with the Rand Corporation to design a network that could continue communicating even if a portion of the network was destroyed in a disaster. for a company with offices around the country or around the globe. Informix. sharing data on file servers was a natural happenstance. including techniques for maximizing performance of the database as well as maximizing developer productivity. As the expense of networks decreased and capabilities increased throughout the late 1980s. As networked computers evolved. however. As an . IBM. this created practical problems: If the home office (and the computer system) was in Chicago. such as printers and other expensive hardware. However. The result. such as restricting the value of gender to male or female. networks have been around almost as long as computers. The next two chapters introduce RDBMSs and the use of SQL. It was also difficult to merge the data back together for reporting. This development. resided within the confines of a centralized computer. ARPANET. Sybase. along with the application programs written to manipulate that data. The database typically sports other methods of maintaining data integrity. For a company with a single office in Boston or Chicago. came online in 1968 and eventually evolved to what is known today as the Internet. and so on. Distributed Computing To understand the move toward client/server. All data.enforces a business rule such as “no order may exist without a valid customer number. In 1964. the network exploded into prominence in corporate America. it is necessary to digress briefly to the problems inherent in the centralized processing models of the mainframes of the 1960s and 1970s. so did the proliferation of DCE. office workers in Boston and Los Angeles had no practical access to data relevant to their operations. revealed the weakness of networks: The bottleneck on nearly any network was and is the low bandwidth—the amount of data that can be moved over the cabling. The concept of the Distributed Computing Environment (DCE) sought to mitigate this problem by moving data closer to users on multiple machines. Networks stretched the definition of DCE by adding the concept of sharing resources. The majority of this book is devoted to using Visual Basic in an environment with an RDBMS such as Oracle. All of the RDBMS engines use SQL as a language for accessing and manipulating data. this arrangement was fine.

When this happens.example. All rights reserved. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. Thus. a “high-speed” Ethernet network can theoretically move data at 100Mbps (megabits per second). Worse. as more users are added. the data has to be retransmitted. the “wire” (the network cabling) is shared by many users. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Any time there is a collision. In reality. Therefore. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. a data collision results. it dwindles as more users are added to the network. so even though the theoretical throughput sounds high. the potential for two users attempting to send data at the same time increases. as network utilization increases. Client/server solutions seek to take performance issues into account by minimizing the amount of data being moved. the wire can only send one piece of data at a time. performance degrades very rapidly.

In fact. the client will create an SQL request for data and send that request to the database. With a shared file. (I discuss this concept further in Chapter 2 where I define the term RDBMS engine. the program has to read the entire file and determine . Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- What The Heck Is Client/Server? Client/server is a term much bandied. We want to find all customers who live in California. sometimes by people who don’t have a clue about what it means. With a shared file. The client is responsible for providing an interface to the user. and the two are connected via a network. there is no separate process—program—running. which processes the request and returns only those records that meet the criterion. click the chapter and section titles. perhaps an Access database.To access the contents. is merely shared by multiple users. Typically. Nonsense. many industry pundits will stand on a podium and tell you that there is no single definition of client/server. Figure 1.000 customers for whom we store information. Here we see a client program communicating with a database engine running on a remote server.1. fulfills it.) Let’s assume that we have 10. Suppose 50 customers are from the Golden State. and sends the data back to the client. client/server application. the client requests records from the database server.1 In a two-tiered. The simplest and most common example is the classic two-tiered database application shown in Figure 1. The file. The database then evaluates the request. Client/server computing simply means that two (or more) processes run independently in a cooperative manner. Contrast this setup with just a shared file on a server.

Each time the application needs to be maintained. The simplistic model that I have just illustrated works fairly well when the number of simultaneous users—such as in a departmental application—is not too high.1. Because only 50 records are sent to the client (instead of 10. the obvious answer is to offload as much processing as possible to an application server. Assume you do manage to get 1. In the sections that follow. the network will still be crushed. This structure was shown in Figure 1.000 PCs must be updated. The user is going to wait a very long time for a response. you construct a two-tiered application. In a client/server environment. Other complications come from the sheer complexity of maintaining that many clients. The database is primarily responsible for returning data to the client. The request is sent to the database server. you tend to reach a point where the network traffic still becomes too high. Although a goal of client/server is to minimize network traffic. Beyond those 50 to 100 users. For instance. simply due to a lack of resources (memory and so on). In this scenario. If you write an application program that communicates with a database server. we are referring to the number of layers of communications that make up an application. The application server manages connections to the database and performs all data requests of the database. However. all 10. three-tiered. simultaneous connections before it begins to sag performance-wise. today’s graphic-heavy environments and intensive computations require ever bigger and faster PCs.000). To do that. the client application is mainly concerned with presenting a user interface and does as little business logic as possible. the database itself can support only so many active.000 records are sent from the server to the client. Therefore. There are a number of problems with this approach. creating an endless cycle of expensive PC upgrades and replacements. The server then evaluates the request and finds the 50 records before sending any data back to the client. That is a Herculean task for which no good administrative tools exist. all 1. the fact remains that if you add enough users. The business logic is moved to a server that performs business-oriented processing. Multitiered Architectures With the terms two-tiered. the two-tiered client/server equivalent could probably support 50 or 100 (because the client/server approach puts much less strain on network resources than does the shared-file approach used in a FoxPro application). it begins to sag when we try to scale (grow) it to the enterprise level. The database also performs a limited amount of logic by . or even n-tiered architectures. the network still can’t handle the amount of data being moved around. Also. Each term represents a division of duties. however. network traffic is reduced dramatically. I address this issue as well. the client creates a SQL statement such as Select * From Customer Where State = ‘CA’.which customers are from the state of California. If your multiuser FoxPro system could support 5 or 10 users. Further.000 users on your client/server application. The client is primarily responsible for providing the user interface and the business logic.

This three-tiered model is illustrated in Figure 1. Read EarthWeb's privacy statement. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Figure 1.2.2 In this three-tiered system. All rights reserved. . the client connects to the application server.enforcing business rules on the server. which in turn connects to the database server.

Figure 1.To access the contents. a multi-tiered design offers other advantages that exploit the location and nature of each physical tier.amazon. but only the application server communicates with the database server.com (an online bookstore) and search for books with “Visual Basic” in their titles. . It connects to a Web server at Amazon’s site. This arrangement has the effect of reducing a certain amount of data traffic on the network because the database server isn’t even on the network. The database server processes the request and sends the result back to the Web server. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- A more familiar example of a three-tiered application might be what you see on the Internet. Visit a site such as www. Thus. Beyond overcoming practical limitations imposed by the two-tiered design. Your PC is the client in this model with the Web browser containing the user interface. The Web server then formats the result set into an HTML page and sends that back to the client for presentation within the Web browser. Extensions on the Web server perform some business logic and interact with a database server. click the chapter and section titles. PCs on the network that are not part of the client/server application itself suffer minimal impact on network performance. The Web server’s main job is to create Hypertext Markup Language (HTML) pages to be sent to the Web browser on the client. The Web server sends a request to the database server asking for all titles that match your search criterion.3 shows a group of PCs networked together with the application server on the same ring. Notice that the client PCs can communicate with the application server.

3 A three-tiered configuration with the client computers communicating with the application server via the network. such as editing a customer record or decrementing inventory levels. or object that supports . Together. Encapsulated within this object is logic that enforces business rules such as “a customer may not exceed $500 in credit” and “a customer must have a date of birth less than today’s date. as a simple example. The Component Model With Visual Basic. Assume you use Visual Basic 6 to build an ActiveX object called custUpdate. As such. which typically partition the application into three discrete tiers. When we look at a client/server model as a group of services (user. the objects become components in what is called component-based development. Consider the word “component. The object is nongraphical. Any tool. consisting only of code that updates customer records. then each service is a collection of assembled components. such as updating tables. platform. we create one routine as an object that we can then use almost as a building block in other applications. transaction management. rather than re-create it yourself every time you need that functionality.” Your custUpdate object is a component that can be deployed at the client level with no special coding because of the benefits of Microsoft’s Component Object Model (COM) technology. Each of these areas is encapsulated into a tier of the client/server system.Figure 1. Visual C++. The application is broken into three key service areas. • Data services—The maintenance of the database itself. the Common Dialog control that you add to your application when you need a File Open or Printer Setup dialog. • Business services—The processing necessary to accomplish business goals. the component model extends into the client/server environment. for example. These objects have functionality embedded in them that can be used repeatedly in many different projects. these tiers are known as the services model: • User services—Essentially the way the application interacts with the user. I expand upon these concepts throughout the book. Rather than re-create a routine to calculate the sum of all line orders on an invoice. The client handles the user interface.” Visual Basic supports the creation and use of objects developed with Visual Basic. the application server handles the business logic. The Services Model Visual Basic supports an approach to client/server in three-tiered and n-tiered designs known as partitioning. you have a prebuilt component that you can reuse from project to project. and many other development tools by independent teams of developers. and the database server performs data-handling chores. and data). business. Consider. and concurrency support (row and table locking).

and so on) is not. Copyright © 1996-2000 EarthWeb Inc. This includes forms. For efficiency of design and practicality of deployment. strictly speaking. anything that is not a client service or a data service is usually lumped into the business services bucket. controls. All rights reserved. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Other items that can be shared by multiple clients (or the data services partition) then become a part of the business services partition. and so on. it is not a good candidate to be deployed on each client nor should it be placed on the database server. However. The user interface clearly belongs on the individual user PC. Anything that performs physical data retrieval or maintenance—that is. The most convenient place to put it is on the application server as part of the business services partition. More On Business Services Client and data services tend to be easy to define. pagination.COM automatically “knows” how to communicate with the object and can take advantage of its methods and properties. An object deployed to handle multiple print chores (reports. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. a business service. the database engine—belongs in the data services area. Read EarthWeb's privacy statement. screen navigation. but the definition of the term “business services” can be somewhat muddled.

Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Distributed Component Object Model (DCOM) technology extends this concept by allowing a component to be placed anywhere on a network. Should a business rule change (perhaps you will allow a customer credit of up to $1. By moving the business services to an application server. you have effectively partitioned the business services from the user services (and from the data services). Assume you have a client/server application that uses the Internet as its network. click the chapter and section titles. as we (client/server developers) write programs that are increasingly graphical in nature. The object operates independently of any client and independently of the database server. This arrangement places a strain on the client because the programs tend to be big and slow and contribute to the need to continually upgrade PCs across an organization. whereas the database server handles the data services. Unfortunately.To access the contents. you have only one place to make the change and that change is instantly made available and enforced for all clients. the object is located only at the server. Your Visual Basic application can invoke methods of custUpdate (without any change in coding) regardless of whether it is located on your computer or on a server on the other side of the world. You can take advantage of DCOM by deploying all your business logic on an application server. Any other object can communicate with it without knowing or caring where it is on the network. the client need do . Instead of having a custUpdate object on every client in the network. In the two-tiered client/server model.000 instead of $500). By placing all your business logic on an application server. that’s two words). The Thin Client One of the buzzwords of the day is “thin client” (okay. we contribute to this bloat. all of the user services and all of the business services are located on the client.

The direction we are heading. If the network supports TCP/IP. Visual Basic 5 introduced the capability to create applications that actually run within a Web browser. what does the application have to do and where should it be done? Part of the process of ferreting out this information is traditional system analysis. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. and the final part is the somewhat less clear process of properly partitioning the results. is towards a thin client. It also means that your application is operating system independent. sort of. All of a sudden. You may be constrained by network limitations.) The range of database connectivity options and methodologies (a major subject in this book) is confusing to say the least. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. has been known to get bogged down from time to time and that is beyond your control. let me be the first to say that the technology is not perfect. If the user wants to access a client/server order entry system. it is housed in the browser. If he or she wants to access the accounting client/server application. Your Visual Basic application system is portable over multiple operating systems. and it will ultimately simplify development enormously. it is powerful enough to run any of the client/server applications. disk space. All rights reserved. it is probably wise to tread lightly and test carefully. and CPU) are needed. If the client has a Web browser that supports active clients. No form or menu runs on the client. Copyright © 1996-2000 EarthWeb Inc. we are actually taking some of the strain off the client and fewer resources (such as memory. This method is how you implement a thin client. As the technology matures. It means that the application is truly network independent. .little more than present forms. If the PC is powerful enough to run Internet Explorer. then. it supports your application. for instance. Can you do everything I just said in the preceding paragraph? Yes. he or she launches Internet Explorer. The browser then becomes the user interface. it is an exciting trend. (The Internet. and the like to the user. Read EarthWeb's privacy statement. he or she launches Internet Explorer (or Netscape Communicator). menus. Still. Designing The Client/Server System One of the keys to implementing Microsoft’s DCOM in a client/server environment is proper identification of both service requirements and their logical location in the physical implementation. it can run your application. Put in simpler terms. Lest I sound like a walking billboard advertisement for Microsoft. part is the application of well-defined object-oriented principals.

To access the contents. update. typical functions will include the following: • Add. update. and delete (to ensure that there is a mechanism to add a customer). The first step is to gather detailed requirements from users. . and delete customer. In these JAD meetings. normally. It is useful to compare the functions to the database design in order to verify that each database entity has at least one occurrence of add. It is often helpful to bring senior management to at least the initial JAD meeting to clarify the organization’s goals. users and technicians meet to hammer out first the functionality of a system and. Management can provide a mission statement from which all functionality is derived: “Sell widgets worldwide. For instance. The latter form the basis for the database design. We can use a number of well-established. In this day and age of rapid application development (RAD). It is not uncommon to encounter a sizable disjoint between what senior management sees as the organization’s philosophy and what the rank and file sees. formal methodologies (on which whole books have been written). many companies turn to joint application development (JAD) brainstorming sessions. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Systems Analysis Assume that we are building a traditional order entry system.4). update. which I review in Chapter 2. in an order entry system. the data elements to be captured. • Add. click the chapter and section titles. That function can be decomposed into smaller units that define how the overall mission is accomplished (see Figure 1. Those experienced in the field often use a somewhat less formal approach. and delete order.” The mission statement then can be viewed as the highest-level function of the organization.

) Encapsulating Functionality Another source of confusion is the concept of encapsulating functionality. An example of an output is a report or a table being updated. It places an entry in the transaction log and informs your program whether the update was successful. I have to tell them that there is no one right answer. it is encapsulated within the database server itself. I end up stressing that the whole process of systems design comes down to practicing common sense. you are not doing the actual update. You cannot access the underlying data or functionality directly. The database engine edits your SQL statement for validity.Figure 1. Okay. ensures that the customer number is valid. I spend a good 40 hours teaching these skills to students in what is still a compressed format. Each function is decomposed further until an atomic-level function statement is achieved.4 The beginning of a simplified functional decomposition. All that this intimidating word (encapsulation) means is embedding functionality into another object such that its behavior is exposed but its integrity is protected. If the decomposed functions accomplish the goals of the system. When you send an SQL statement to the server asking it to update the address of a customer. the server is. you are not defining how the application will accomplish a task. Because of space constraints in this book. Decomposing functionality is particularly troublesome to my students who invariably are looking for the one right answer. In general.) As you can see. there is a one-to-one correspondence between an atomic-level function and a “program” (such as a Visual Basic form or report). maybe that is not so easy to understand. you may then opt to combine two functions to make the application more functional. I discuss how to design a database. However. Instead. then performs the physical update. Once application functionality has been defined. then it is correct. I cannot explain all of the ins and outs of the different approaches to systems analysis and design. you are ready to think in terms of how to make it happen. There are two aspects to this: defining the data that needs to be captured and a description of how the data will be manipulated. at this stage. In designing your system. it is common to maintain order headers and associated line items on the same form. (In Chapter 2. verifies the state or province and postal code. you seek to do the same thing—encapsulate your . (In practical terms. you are merely concerned with what the task is. A function that has been decomposed to the atomic level generally provides one and only one output. Consider the database server. For instance.

you need to create two (or more) Visual Basic applications. you force all requests to update the data through the object’s methods. and I expand upon this concept in the following section. Visual Basic provides a rich set of tools to build these portions.application logic. in updating a customer’s address. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. If you need to perform customer maintenance. needing only to provide an interface to the user and the knowledge of how to communicate with the business services tier. Read EarthWeb's privacy statement. the hard work has already been done for you. By embedding the data in that object. you break each function into three discrete sets of services: user. This partitioning can be seen in Figure 1. All rights reserved. The logic to process a customer record and an associated address record is localized to the middle tier under business services. In partitioning an application using Microsoft’s DCOM. partitioning the application allows you to reuse objects and locate those objects at their proper place in a multi-tiered client/server application.5 An application broken into three tiers of services. . For instance. Partitioning The Application Hand in hand with encapsulating functionality. The business services portion is a separate program running remotely (from the client) to which multiple clients connect. However. and data. The database server handles data services. you might want to validate the state or province code as well as the postal code. Copyright © 1996-2000 EarthWeb Inc. Isolating the data allows you to guarantee the integrity of the data. Figure 1. you could embed that logic into an object. This embedding is a recurring theme throughout this book.5. The client interface is localized to the client computer under user services. To build such an application. The client services portion is actually rather simple. you seek to isolate the data and logic. business. Therefore. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

A proxy is an object provided by COM that runs in the same memory space as the user. .To access the contents. The workings of DCOM are almost identical. DCOM also adds network transport services in a manner that is invisible to the application.6. which communicates with the component’s remote automation stub. If your application is communicating with an ActiveX component. This communication works both ways. COM provides a proxy and a stub for each side of the connection between your application and the component. unpackages the parameters received from the proxy. on the other hand. This provides for tremendous flexibility in design. runs in the address space of the receiving object. The application houses a remote automation proxy. Visual Basic (Enterprise Edition) provides tools to register components. The stub. making the location of the component on the network irrelevant to the client. It packages together parameters and acts as a bridge between the two objects. Figure 1. I review step-by-step in Chapter 10 the entire procedure for implementing the DCOM. It collects arguments to be passed to the ActiveX control’s methods and properties and communicates with the component’s stub. as shown in Figure 1. allowing two objects to communicate with one another with little to no intervention on the part of the developer. click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Distributed COM When you build an ActiveX component and then use it in a VB project. and passes them to the component.6 COM and DCOM automatically provide proxy and stub services. the proxy runs in the memory space of your application.

these jacks accept RJ-11 pins (similar to the connectors on your phone cord). there are minimal security constraints. Each computer examines the packet to see if it is addressed to that workstation. The packet is continually sent from computer to computer. the expression network architecture refers to how the network is implemented on that topology. I review some of the key concepts of the underlying network architecture. Each PC typically contains a LAN adapter or Network Interface Card (NIC) with two jacks. and because the network has no server. Multiple hubs are connected to one another. It is the network that moves data from the server to the user. A multiplexing unit monitors the network. It is vulnerable to any individual workstation being powered down or crashing. I briefly discuss the more common topologies and architectures. The network might be a 10Mbps Ethernet or it might be the Internet itself. Peer-To-Peer Networks A peer-to-peer network is one in which the computers are connected to one another directly in series. Star Networks The star network topology implies a network where all computers are connected to a hub (a hub is a box similar to a telephone switchboard containing minimal intelligence). it is helpful to understand the basics of the physical model upon which the application is based. the multiplexer recreates it. Although the client/server developer does not need to be a network engineer. In contrast. If the packet is accidentally destroyed. In the following sections. the entire network goes down. allowing only one packet to circle the network at a time. A Windows 95 or Windows 98 network is a peer-to-peer network. The multiplexing unit gives permission to each workstation in turn in a procedure that is akin to a parliament (giving each “member” a turn to speak but also allowing for higher priority speeches such as error messages). Ring Networks In a ring network. such a network is typically slow because data passes through each computer. If a hub goes down. Although network design is well beyond the scope of this book. the Visual Basic client/server developer should have a grasp of how his or her data is moved in order to properly model the application. The expression network topology refers to how the network is physically laid out. Typically. Although it is simple to set up. all computers are connected via a continuous cable. . it waits for the packet and attaches a “request” to transmit. A line is run from one computer to the next serially.In the remainder of this chapter. If a computer needs to send information. Network Topologies And Architectures The backbone of any client/server system is the network on which it is installed. Star networks are simple to maintain but offer minimal security constraints.

Only one packet can travel on the network at a time. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Still. The most common implementation of bus technology is Ethernet. . it is somewhat expensive to maintain and does not scale to a large number of users. To maintain satisfactory performance. performance can degrade drastically. Copyright © 1996-2000 EarthWeb Inc. network engineers break a large Ethernet network into smaller LANs connected via bridges.IBM’s Token Ring architecture runs on a ring technology. as more users are added to the network. the internal wiring of the hub still connects each computer serially. All rights reserved. Further. Ethernet is by far the most common architecture. Bus Networks The bus topology connects computers in a single line of cable. a packet collision occurs. waits a random amount of time and then resends the packet. Although fairly simple and inexpensive to install and maintain. when they are detected. When a workstation wants to send a packet of information. but because of the extra overhead of packet monitoring. it “listens” for the line to be clear through a process known as electronic sensing. Although each computer is typically connected to a hub. Read EarthWeb's privacy statement. Each workstation listens for such collisions and. the network is vulnerable to any breaks in the cable. It has the advantage of being very reliable. and if two computers happen to transmit at the same time. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

A protocol is a low-level language with which two or more computers communicate. The file is broken into packets. The most common protocol in use is TCP/IP. Most are based on the Open System Interconnection (OSI) Reference Model. protocols that adhere to this standard can generally intercommunicate with relatively inexpensive translation hardware. A number of protocols are commonly used in organizations today.To access the contents. you can think of a network protocol as similar to an agreement at the United Nations to speak in one certain language that everyone understands. • Sequence number—A number that enables the receiving computer to reassemble all the packets into one file and to tell the sending computer which packets to resend in the event of transmission errors. the language of the Internet. Each packet has various pieces of information in it: • Destination address—The computer to which the packet is being sent. we said the two computers were “shaking hands”—agreeing on how to communicate with one another. when we logged onto a bulletin board. An in-depth discussion of these protocols is beyond the scope of this book. Imagine you send a 2MB file to a friend across the company or across the globe. • Checksum—A mechanism by which the receiving computer can verify the integrity of the data being sent. which defines standard network layers of communications. we more accurately refer to this process as agreeing to a protocol. click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Network Protocols In the 1980s. • Usually a “from” address—The computer or person from which the file was sent. Today. In general. The TCP (Transport Control Protocol) portion refers to how a packet moves from . • Data—The actual data being sent. However.

understand that different networks employ different protocols and often employ more than one protocol simultaneously. The network itself consists of one or more servers. A large-scale client/server migration introduces a lot of change as it is. The IP (Internet Protocol) refers to how data is moved from computer to computer. for instance. However. The choice of NOS can have a dramatic impact both on performance and on productivity. and group services (such as email and calendar functions). However. TCP is widely implemented on various internal networks within organizations. IBM LAN Manager’s native protocol is NetBIOS. IPX/SPX is the native protocol of NetWare networks. the highly graphical nature of the administrative tools in Windows NT may more than offset the tedious command-line . each providing one or more services. Other protocols that you may run into range from NetBEUI (Microsoft Windows NT) to AppleTalk (Apple Macintosh). Network Operating Systems Like the individual client PC. you need to ask a few questions: • What NOS does my organization currently use? Often. Oracle presents a prettier face on Windows NT than it does on Unix. If your staff’s skills lie in the area of Windows NT. When you consider the database server. For now. a given computer may be responsible for both email and print services. it may not be the best time to also introduce a new network operating system. shared services (such as print and file services). I strongly urge every organization to minimize the number of different components. the considerations for one are often the same as for the other. An in-depth discussion of protocols is beyond the scope of this book. Strictly speaking.application to application. • How many resources can I dedicate to administering my network environment? For organizations that cannot afford a great deal of devoted resources. For instance. Throughout this section. If you are going to use Novell NetWare as your network operating system. security. Further. the database platform’s operating system is independent of the network’s NOS. • What expertise does my organization have on staff? NOS skills are often hard to find. The best choice for overall NOS may not be the best choice for your database server’s operating system. it is best to stay with what you have. • What is the overall load on my network? Some NOSs lend themselves to certain types of environments better than others. It is the NOS that is responsible for network traffic. the Unix platform under many conditions will outperform the equivalent NT environment. Although it is used on the Internet. I highly recommend that you consider it for your database server as well. I deliberately mix consideration of NOS with the database server’s operating system. usually called the Network Operating System (NOS). In evaluating what NOS to use. the network server runs an operating system. you might not want to even consider a Unix or NetWare platform unless you are confident that you can hire people with the necessary skill sets.

the damage had been done. They can take advantage of operating system services (such as file I/O) without going through intermediate drivers and link libraries. any NLMs load as well and become part of the operating system itself.interface of a Unix platform. . You accomplish this arrangement by compiling the other program (email or database are examples) into a NetWare Loadable Module (NLM). Copyright © 1996-2000 EarthWeb Inc. particularly Microsoft. Many in the industry believe this was a serious tactical blunder. and allowing competitors. where it had always been the market leader. Read EarthWeb's privacy statement. Novell eventually sold those products to Corel. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. When the NOS loads. they run much faster than they otherwise might. In the following sections. A few years ago. Novell NetWare Once the king of the hill. There is a clear advantage to this system in that. Novell sought to expand its presence in the workplace with the acquisition of Quattro Pro and WordPerfect. On the other hand. Regardless. Other programs you want to run must actually be part of the operating system. NetWare has a large presence in the corporate arena and a strong suite of tools. but by then. NetWare has seen its market share steadily decline relative to the Microsoft Windows NT juggernaut in the past few years. because the NLMs are part of the operating system. Whether the declining market share is deserved is a subject for conjecture. I review the more common network operating systems that you are likely to encounter. removing Novell’s focus from the network arena. An ironic side benefit of NetWare’s market erosion is a relative abundance of talent to support the product set. NetWare is known as a dedicated operating system. meaning that the server can run no programs other than the operating system itself. to make inroads. the operating system will also crash (because the application and the operating system are one and the same). if the application crashes or is otherwise poorly behaved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved.

Like Windows itself. Although it is a solid platform for file services. Windows NT The Microsoft juggernaut seems to roll on with Windows NT. IBM and Microsoft codeveloped LAN Manager.x. It can run other programs independent of the operating system. click the chapter and section titles. its directory services are weak in comparison to Novell . OS/2 itself has been unfairly maligned for its lack of software products because it is capable of running a large subset of Windows applications. LAN Manager is not a dedicated operating system. Coupled with OS/2 and various DB2 tools. The operating system was developed to replace Microsoft LAN Manager. Like Novell NetWare. which was jointly developed with IBM in the 1980s. I am not aware of any major database products that run on it. always operating in the shadow of other players in the marketplace. IBM nevertheless remains a healthy company with a wide variety of tools. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- IBM LAN Manager Once upon a time. NT version 4 is a robust operating system. Likewise. Never a large player in the network arena. Banyan Vines Banyan’s product has never garnered as large a market share as it probably should have. NT version 3. NT did not enjoy widespread acceptance for several years. Vines is a dedicated operating system.To access the contents. Arguably. it forms a strong platform for shops with IBM mainframes. Unlike NetWare. although arguably not as powerful or scalable as Novell NetWare 4. it is a more stable platform than some Windows platforms (although probably not as stable as Windows NT itself). the word among network professionals is that Windows NT 4 seems to hit a wall at about 1.100 users.51 seemed to have been the right answer for organizations that began to embrace it as a viable network platform. In particular.

NT 5 (in beta as of this writing) seems to answer many of these complaints. Microsoft traded some resource intensiveness (Windows NT really needs more memory and CPU speed than most other NOSs to run comfortably) against a high degree of stability. the database and database access techniques. The operating system spends a fair amount of CPU cycles enforcing integrity of operations. if somewhat complicated. Windows NT is a nondedicated server. However. Many of the following chapters concentrate on specific techniques. For instance. in fact. it does not permit any program to directly address any hardware. such as DAO. Read EarthWeb's privacy statement. My recommendation if you do seek out these texts is to find ones written in the past few years to ensure that the most modern approaches are reviewed. Many fine books are devoted to small subsets of the subjects discussed in this chapter. Reportedly. The next two chapters deal specifically with the database server portion of the network. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. and a review of the underlying network architectures. if you are unfamiliar with database design. which is a high-level overview of Visual Basic and data access. an introduction to Visual Basic’s role in the network. you will want to read Chapter 2. The heart and soul of client/server are. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. is appropriate for his or her situation. If you are not familiar with SQL usage for retrieving and updating the database. and it also prevents applications from writing to memory outside of their own address spaces. and Chapter 4 attempts to steer the developer to which of those techniques. . or ADO. whereas most of the remainder of the book deals with Visual Basic’s role in the creation of two-tiered and three-tiered client/server applications. All rights reserved. Windows NT sports a solid set of graphical. Therefore.NetWare’s. you will want to read Chapter 3. tuning devices to maximize performance. Where To Go From Here This chapter has been a high-level overview of the nature and evolution of client/server. meaning that other programs can run along with the NOS itself. Windows NT represented 50 percent of all network server licenses as of February 1998. Experienced database developers may want to skim Chapters 2 and 3 and begin with Chapter 4. RDO.

no skill is more important in client/server development than properly designing a database. reliable client/server application. RDBMSs • How a relational database is organized • Database integrity constraints • Database design • Data Definition Language • Data Control Language In this chapter. Therefore. With a well-designed database. When training students or corporate clients in client/server development techniques. if the database is poorly designed. click the chapter and section titles.To access the contents. On the other hand. you have a good chance of deploying a successful client/server application. I stress that properly designing a database is 80 percent of the battle in constructing and deploying a successful client/server application. all the development skills in the world cannot create a robust. A properly designed database accomplishes three essential things for the client/server developer: . Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 2 Relational Database Management Systems Key Topics: • Relational databases vs. Although a Visual Basic program can run against almost any back-end database. I guide you through the essentials of what is the heart and soul of any client/server system: the database. it is the Relational Database Management System (RDBMS) that brings the “server” to client/server.

The latter implies an engine that is running independent of any client program. it employs object-oriented techniques to store and access data as discrete objects. you can define certain columns as containing objects and employ extensions to the database that “understand” how to manipulate those objects. and validation processing to the server. hybrids tend to be slow in indexing and accessing the objects that they store. which implement intelligent database design. most notably Oracle and Informix. Some vendors. I overview some of the popular relational databases. you enhance application performance by minimizing network traffic and by moving some of the intensive processing from the client to the server (which. and conclude with an overview of SQL statements. For instance. Relational Databases Vs. These are referred to as hybrid databases. is a high-end machine optimized for the load). Recently. presumably. Unfortunately. retrieval.• Through a properly normalized data schema. before the OOD encroaches upon the more tried and true RDBMS. With a hybrid database. the database can assume much of the burden of validating basic business rules. instead. Relational Database Management Systems Before embarking on a survey of available relational database products. complete with intelligently designed integrity constraints. . • By using the referential integrity tools made available by the database. have introduced object-oriented extensions to their relational products. if ever. you minimize or eliminate altogether the chances of data corruption problems. A Note About Object-Oriented Databases New to the database scene in the past couple of years is the emergence of object-oriented databases (OODs). as yet. The technology is. such as requiring that an order have a valid customer. it is important to draw a distinction between relational databases and relational database management systems. immature and sales are a tiny percentage of the overall database market. None of the major database vendors offers a true object-oriented database. Sybase and IBM have both announced object-oriented extensions to their database products. An OOD does not store its data referentially. and it will be years. discuss the theory of relational database design. • By moving data update. Informix and third parties market Data Blades. One vendor sells a Data Blade that enables a table to store facial images and then search by those images. which make it possible to store and manipulate specific types of objects in a relational table. In the following pages.

it is not an appropriate choice for client/server development. especially if 10. The database engine manages the data and enforces the integrity constraints. Copyright © 1996-2000 EarthWeb Inc. Now. The application receives 100 times as much data as required. and demo.Any database that organizes data in related tables and that can enforce those relationships via referential integrity can lay claim to being a relational database. the SQL request is sent to the RDBMS. The server sends back to your application only the 50 records that are required. the responsibility falls on the application program to perform those roles. which processes the request on the server. The moral? A wolf in sheep’s clothing is still a wolf.000 customers. or 500 client programs all make the same types of requests. and the application itself then reads through those records to find the 50 that you need. Network traffic is reduced by 99 percent. However. This inefficient data processing occurs because the Access database is just a file with no engine to process the data request.ldb is a file used to manage record locking (the LDB is for lock database file). Contrast this example with one involving an RDBMS. suppose you want to see all the customers from California. which are true database engines. but if it is not a relational database engine. You will see that there are actually two files: demo. Your application generates an SQL statement that looks something like: SELECT * FROM CUSTOMER WHERE STATE = 'CA' Assume there are 50 customers from California on a table of 5.mdb is the actual database file (MDB stands for Microsoft database file). All 5. . All rights reserved. such as Oracle or Microsoft SQL Server. Read EarthWeb's privacy statement. In this scenario. It is unquestionably a relational database. If there is no engine. It is easy to imagine how this activity bogs down network performance. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Consider a Microsoft Access database that I call “demo”. 50. A database might be relational (such as Microsoft Access) or present an SQL front end (such as dBase).000 records are returned to your application. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. assume I put the database file on a server and then access it from multiple client programs.

click the chapter and section titles. your choice of RDBMS can have a dramatic impact on both the performance and the maintainability of your application. In the following pages. It is easy to jump to the conclusion that—assuming money. the most powerful engine may also be the most difficult to administer or it may simply be overkill for your organization. and the same guidance is presented in more detail. it is not possible to reach any definitive conclusions because the . it is the assumptions each makes about operating environments that renders one more powerful than the other in one test versus another. In truth. These considerations include: • Network operating system • Typical database usage • Number of users and volume of data • Database administration • Database cost • Vendor stability and reputation Of necessity. I provide some general considerations in selecting an RDBMS for your client/server environment. Unfortunately.To access the contents. Open any database magazine and you can see ads from Sybase and Oracle both proclaiming how each clobbers the other in side-by-side comparisons. Choosing the RDBMS is then a critical decision point in your overall client/server strategy. things are seldom that clear-cut. Visit either vendor’s Web site. The marketing hype that passes for serious advertising from the various database vendors doesn’t lend much light to the discussion either. In any case. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Considerations In Selecting An RDBMS As shown with the simple Microsoft Access illustration. the claims of all the vendors can probably be substantiated. hardware. and so on are not an issue—you should simply purchase the most powerful engine on the market.

For instance. my recommendation is to always keep the environment as simple as possible. the database cannot use the processors. On the other hand. Assuming your NOS supports multiple processors. you might want to consider products that make this easier. although I have. you may have other environments with which you need to integrate. However. Of course. OS/2. the field of viable candidates is automatically reduced. and even eight processors. An online transaction processing (OLTP) system. database applications tend to fall into two categories: transaction processing and decision support. a decision support system (DSS) is typically a large database upon which sits all or a large subset of corporate data.proper choice is highly dependent on each organization’s needs and environment. four. The system may have many . Typical Database Usage In general. get a cup of coffee and then move on to the next section. and any specific recommendations are likely to be somewhat subjective.1x runs quite comfortably on an Intel-based machine running dual processors. is typically transaction oriented. However. Along the same lines. An additional consideration with your NOS arises with the subject of multiple processors. Few vendors support all server operating systems. to run a different operating system for your database server than you do for other portions of your network (and many organizations do just that). in fact. Network Operating System Perhaps the first consideration in choosing a database is the network operating system (NOS) upon which it is to run. if the NOS is incapable of using the processors. larger systems may need to process many transactions per second (TPS). high-end servers come configured with two. IMS. Further. XDB Systems also markets a capable database product that can run against DB2. Increasingly. used most of the products that I discuss in the next section (“A Survey Of Available RDBMSs”). NetWare 4.x does take advantage of the additional processors. It is possible. of course. I have not used all of them. Often. say. Novel NetWare 3. and VSAM data on the mainframe. IBM’s DB2 running on OS/2 is a popular choice for shops with this need. such as an order-entry application or a banking system. so if you are constrained to choosing from vendors whose product runs on. which people analyze to make informed management decisions. In that case. your organization may have already deployed an RDBMS that is serving you quite well. If you need to run your client/server applications with mainframe data. your database may not (or you might need to tell the database to use those processors). That recommendation includes avoiding running multiple operating systems across the network if possible. it simply ignores the second CPU.

Read EarthWeb's privacy statement.thousands or millions of detail records that are queried and summarized but are not typically updated. Executive information systems (EIS) and data warehouses are examples of these types of applications. All rights reserved. The record locking has implications if several users are trying to update different records on the same page. My recommendation is to talk to peers who have used the products in environments similar to your own. on the other hand. the users have to wait until the first user has released the lock on that page. performs row-level locking—only those rows that are to be updated get locked. On the other hand. In addition. you might want to consider such factors as how a given database performs record locking. for instance.0 performs page-level locking.0 performs true row-level locking. With the Sybase product. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Most of the major vendors support some sort of variation on massively parallel processing (MPP). Determining which database will best handle your needs for an OLTP or a DSS is not an easy undertaking. Either way. the nature of your data may be such that a page contains few rows. check out the computer press for its independent benchmarking results. If you have a busy OLTP system.5 does pseudo row-level locking: The rows immediately before and after the row to be updated are also locked. Oracle. the needs are quite a bit different than those for an OLTP system. Copyright © 1996-2000 EarthWeb Inc. where a long-running query is executed in multiple threads to better handle the intensive querying and to speed up processing. uses what is called page-level locking—all records on a database page are locked when an update is to occur. you should consider how well the database handles very large volumes of data. whereas SQL Server 6. Sybase. which makes the issue of row-level versus page-level locking less important. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. If you are planning a DSS. SQL Server 7. Microsoft SQL Server 6. consider searching the Internet (but avoid the vendor’s own biased claims). Lastly.

To access the contents. To squeeze the best performance out of a complex database product such as Oracle. and so on. this power comes at the expense of more complicated administration. For moderately sized databases. If. you need to examine the beefier databases such as Oracle. such as defining the frequency of checkpoints. However. Sybase. it is a viable platform for a DSS but does not offer the tools that an Oracle or Sybase SQL Server offers for massively parallel processing. you might want to consider Sybase SQL Anywhere. consider a product such as Microsoft Access. . My experiences with this product are that it can satisfy the needs of up to 50 users in a moderately heavy OLTP environment. Database Administration My own subjective experience is that Oracle’s database engine is probably the most powerful in a high-transaction environment. you have many thousands of simultaneous users chasing terabytes of data. For low volumes of data. by all means. (The particulars of database administration vary from database to database and are beyond the scope of this book. on the other hand. Informix. click the chapter and section titles. If you have two users who need access to only a few thousand records. the database administrator (DBA) needs to monitor and refine a variety of operating parameters. you may be able to push the number of users to 100. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Number Of Users And Volume Of Data Considering both the number of users and the volume of data actually goes hand-in-hand with the prior discussion of database usage patterns.) How much administration is required also depends on the nature of the applications that the database supports in your own organization. Microsoft SQL Server. and DB2. If your needs are greater than what Access can satisfy but are perhaps less than what a database such as Oracle warrants. partitioning the data.

but it can also yield horrific performance problems. (Refer to my discussion of network architectures in Chapter 1. Your capacity will increase at least tenfold. I discuss the service model in Chapter 1. that weak link may well be the DBA. spreading the database over two 10GB disk drives yields better performance than over one 20GB hard drive (because you have two heads reading and writing data. the database is only as good as its weakest link. If you are running a 10MB Ethernet network. Place the database server on that LAN where it will receive the most use (thus minimizing traffic that has to traverse the bridges). A low-end RDBMS product that uses most or all available memory performs much better than a high-end RDBMS that has not been configured to take advantage of the available resources. a poorly configured database yields poor performance. creating the illusion that the fault is with the RDBMS. Consider Microsoft SQL Server running on a Windows NT server with 1GB of RAM. • The database design—A poorly designed database can not only cause potential data integrity problems. and often. Under most processing loads. The environment includes: • The server—The computer on which the database is running should be a high-end machine loaded with plenty of memory and disk space and possibly multiple processors. consider moving to a switched 100MB Ethernet architecture. Don’t skimp on this critical piece of the RDBMS performance puzzle. performance can degrade rapidly as a result of escalating packet collisions. SQL Server uses only the first 16MB of RAM.) Consider splitting the network into smaller LANs connected via bridges. • The service model—This can be a critical source of performance degradation. you are likely to encounter two wildly different reports on how well the database performs. As is true in so much else in life. If the network is bogged down by too many users. use common sense when configuring the database server. By default. An under-normalized design might . The overuse and underuse of indexes both cause undesirable results. which requires less head movement). Similarly. • The network—Data can only be sent to and received from the RDBMS as fast as the network is capable of moving it. An over-normalized design might force the database to join together too many tables. placing the proper type of processing at the proper place on the network can mean the difference between good performance and poor performance. About Database Administration In talking to two seemingly identical organizations about their experiences with the “Brand X” RDBMS. but for purposes of this discussion. Use common sense when configuring the computer. The RDBMS should normally be the only software running on the server other than the operating system. a properly configured environment should yield good performance with any of the major RDBMS engines.Although the good news is that most of the vendors (including Oracle) are simplifying administration. For instance.

Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. and so on) available. Ensure that the database is allowed to use all of the resources (memory. you might end up with 25. That means that each time the user wants to see one employee. If the tables are not properly joined. rapidly degrade through no fault of the RDBMS.000 employees? You can see where performance would. A list of employees showing their departments should. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.require the database to work too hard to locate the desired data or force it to read through too many records to return the desired result set. . again. Consider a department table that has 50 rows and an employee table that has 500 rows. Copyright © 1996-2000 EarthWeb Inc. disk. Study the tuning manual that comes with each database.000 records instead! Now. Worse. • The application data logic—The application (or user) can easily throttle performance with poorly phrased queries that do not. Inexperienced developers invariably seek to present a drop-down list box containing all 500 employees. for instance. what if the company has 5. consider a program that allows the selection of an employee for maintenance. correctly specify table joins. Update the system statistics frequently (system tables maintained by the database that give the query optimizer information about the types and volumes of data that is stored on the tables). the database must return 500—hardly the purpose of client/server. • The RDBMS—The RDBMS itself can easily be so badly maintained as to produce unbearable results when even minimal performance tuning might yield improvements on the order of a 90 percent reduction in response time. produce 500 records. Periodically reorganize the database—a task that is similar to defragmenting your hard drive. of course. All rights reserved.

Most organizations running Oracle have somewhat more than five users. the reality is that some shops do have to live within certain monetary constraints.To access the contents. the maintenance fee. A talented DBA can tremendously enhance the performance of the RDBMS (while commanding a salary that would make the corporate CEO blush). When factoring costs. Telephone support can easily run into thousands of dollars per year. It should be noted than many vendors will wheel and deal on price negotiations. whereas a product such as SQL Anywhere might cost only several hundred dollars. you might want to consider that the hardware requirements of the different RDBMS products differ (ignore the stated minimum requirements and concentrate on the recommended configuration) as do the internal support costs.450 (at the time of this writing). Above and beyond licensing. and quite possibly a separate telephone support fee. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Database Cost Although I personally hate to see the cost of an RDBMS become a major consideration. click the chapter and section titles. and support costs. maintenance. The fine print near the bottom of the page reveals that this is for five concurrent users. the maximum number of concurrent users. A visit to Oracle’s Web site shows you that the licensing fee to run the RDBMS on a single server is $1. you need to consider the number of servers upon which the database is to run. A final consideration in database cost is the so-called cost-of-ownership term so often bandied about when discussing PCs. A database engine such as Oracle might run into a licensing fee of many thousands of dollars. Be careful when comparing prices. Vendor Stability And Reputation . The maintenance fee is often 12 to 18 percent of the licensing fee annually.

and its ability to support the product. such as true database replication. Sybase was posting large losses and laying off 10 percent of the company’s employees. I briefly mention some of the more popular RDBMSs available. Access Version 8 is bundled with Microsoft Office 98 Professional and is available as a standalone product.com/access/. I use it in examples throughout the book. Such news may be of concern in terms of a company’s long-term viability (will they be in business five years from now?). Microsoft Access is not truly an RDBMS. The product is sophisticated in its . However. because it is popular and because Visual Basic offers easy support for Access. (The product was renamed when Sybase acquired Powersoft Corporation. visit the Microsoft Web site at www. Nevertheless. it is a popular development back end and offers some fairly sophisticated features. it does not offer a complete SQL implementation (see Appendix B for a comparison of Jet SQL to ANSI SQL). On the other hand. it is a popular RDBMS. and because it is not truly client/server.You might want to consider the financial stability of the RDBMS vendor. (Please note that although Sybase’s woes cannot be construed as good news for any customers. including: • Microsoft Access • Sybase SQL Anywhere • Sybase Adaptive Server Enterprise (System 11) • Oracle • Informix • Microsoft SQL Server • IBM DB2 • XDB Microsoft Access As discussed earlier in this chapter.microsoft. you can use Visual Basic to write to and read from Access databases even if you don’t own Access itself.) A Survey Of Available RDBMSs In the following section. which owned Watcom. Sybase SQL Anywhere Sybase SQL Anywhere was formerly known as Watcom SQL. For more information on Microsoft Access.) Because it is both inexpensive and widely bundled with various development tools. The Sybase product set is excellent and the company continues to boast a top-notch technical development staff across a diverse product line. There were also questions regarding Informix’s financial results. However. the organization’s ability to develop and improve the product. I personally do not predict an organization that large will go under. its performance pales against even the least expensive of the true client/server database engines. As of this writing.

com. Copyright © 1996-2000 EarthWeb Inc. (T-SQL is a dialect of SQL used by Sybase SQL Server and Microsoft’s SQL Server 6. OS/2. Despite the popular misconception that the relational database was pioneered by IBM. Like its little brother. and NetWare. Throughout various sections of the book. MS-DOS. Adaptive Server is an enterprise-level server offering robust performance under a variety of configurations. and offers full support for Transact-SQL. Windows 3. has a complete implementation of SQL (I discuss the ANSI SQL standard in Chapter 3). Sybase Adaptive Server Enterprise Sybase Adaptive Server Enterprise (System 11) runs on Windows NT and on various Unix platforms.x. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . For many years. Sybase’s database server products are powerful.implementation. visit the Sybase Web site at www. Sybase was number two in sales (behind Oracle).5.sybase. The current version of SQL Anywhere (as of this writing) is 5. For more information. it was actually Sybase that was first to market in the late 1970s. and the company enjoys a large installed base of users. but a reputation for customer service woes and a couple of years of poor financial results led to the company falling behind Informix in database sales volume. visit Sybase’s Web site at www. Windows NT. It runs as either a server or a standalone (single-user) RDBMS on Windows 95. I present examples using T-SQL. Sybase Adaptive Server uses a dialect of SQL known as T-SQL. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.sybase. For more information.5. Sybase has joined the move toward hybrid databases with the addition of Data Stores to store and manipulate objects. Still. SQL Anywhere.) The product requires almost no administration but does not scale to the enterprise level.com. All rights reserved.

In recent years.com. NetWare. Windows NT. the Informix product line has grown in sales until it is now solidly entrenched as the number two vendor of RDBMSs. Although Oracle was once considered a pricey product. As with T-SQL. For more information. visit the Oracle Web site at www.infor-mix. and SCO).com. Web connectivity. A personal edition of Oracle runs on Windows 95/98. . visit the Informix site at www. Still. including OS/2. and robust OLTP. Oracle uses a robust dialect known as PL/SQL. Oracle has been the number one vendor for many years. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Oracle Oracle Version 8 runs on a wide variety of platforms. competition has driven the costs down. The Informix products scale well from the department to the enterprise level and offer well-integrated Web connectivity options. IBM’s AIX. Whereas the two Sybase products offer extensions to SQL known as T-SQL. Informix For years. For more information. HP-UX. the gap in processing capabilities between Oracle and its competitors has eroded and perhaps disappeared under certain circumstances.To access the contents. Sybase and Oracle. Oracle has long enjoyed a reputation as the most powerful database on the market with advanced features optimizing large volume data processing. distributed data management.oracle. click the chapter and section titles. I also present samples in this book using PL/SQL. and Unix (including Sun Solaris. Informix sells versions of its enterprise server that run on most types of Unix and on Windows NT. Informix was a distant runner-up in terms of sales to the two giants.

SQL Server uses Transact-SQL. By itself. For more information.microsoft. visit the Microsoft Web site at www. its latest version has tested well on Windows NT. perform its own thread management.5 saw major performance boosts and Version 7 looks even better. would be of interest to shops also running a mainframe. the RDBMS engine has had to be written with a separate layer to interact with the operating system. SQL Server has been rapidly gaining in popularity. Historically. Although that obviously might be limiting. Windows NT. it also offers some advantages. DB2. including most types of Unix. IBM DB2 IBM’s relational database. XDB XDB Systems offers a well-done RDBMS that offers a high degree of compatibility with IBM’s DB2 and. SQL Server 6. com/sql/. although I feel it is probably not as powerful as the very top-end RDBMSs. Unlike the other database offerings. Because MS SQL Server is written to run on only one operating system.0 was the first large-scale departure from its Sybase roots.ibm. XDB is a capable RDBMS. SQL Server probably offers the easiest-to-use administrative tools. My own experiences with XDB have been positive. OS/2. and so on. That performance issue might not be a consideration for your organization if you are not attempting to connect several thousand users or manage several terabytes of data. I am no longer nervous about the company’s long-term prospects because it has announced its acquisition by Micro Focus. and Windows 95/98. Like the Sybase products. Version 6. runs on a wide variety of platforms. it can be more closely integrated with the operating system.com. like DB2 on the network. Although in the past its network-level database products have not fared well in comparison to the products of other vendors. For more information. In addition. DB2 is of particular interest to those organizations that need a high degree of compatibility or interoperability with their mainframe database. as well as VAX VMS and IBM MVS and VSE. makers of COBOL tools for the network. visit the IBM Web site at www. MS SQL Server runs on Windows NT only. although Microsoft has begun moving in its own direction and away from the Sybase standard.Microsoft SQL Server Microsoft SQL Server was originally jointly developed with Sybase SQL Server (now Sybase Adaptive Server Enterprise). This is a logical pairing because Micro Focus tools have always . it has extensions that enable the querying of DB2 and IMS databases and VSAM files on the mainframe (though VSAM files cannot be updated). although it probably has yet to achieve parity in performance with the most powerful of the products listed here.

Additionally. Read EarthWeb's privacy statement. Any of these may be suitable for smaller-scale development efforts. be construed as a positive or negative comment about a product. dBase. All rights reserved.xdb. although not organized relationally. For more information. Besides RDBMSs. and so on. These formats and products include Btrieve. Paradox.com.integrated well with XDB. Copyright © 1996-2000 EarthWeb Inc. visit XDB’s site at www. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. other relational databases such as Lotus Approach might be logical alternatives to Microsoft Access. FoxPro. of course. Any listing or failure to list a given product should not. front ends or ODBC drivers (I discuss ODBC in Chapter 3) allow the access of other file formats in a relational manner. . even though I have attempted to cover most of the major vendors. The choice of XDB is appropriate for shops interested in leveraging legacy COBOL applications by migrating them to a client/server environment. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Other Relational Databases Space precludes the listing of all RDBMS vendors.

The nonrelational approach illustrates how you might build the database with dBase files: There are a total of six files with no true logical association between them. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Database Organization A relational database. On the right side of Figure 2. unlike sequential files. After doing so. nothing stops me from opening the ORDERS. Figure 2. nothing stops me from exiting to DOS and typing “DEL CUSTOMER. organizes all of its data in a single file. Relational databases contain all of their tables and indexes inside a single file. Tables A database table is organized into rows and columns much like a spreadsheet.1 Nonrelational databases are typically a collection of un-associated files. I have two indexes serving no purpose and a whole lot of orders for which I have no clue about the customers. . These files are actually stored as tables.1 is a single file managed by an RDBMS. For instance. containing the two files and four indexes.DBF file and adding an order even if no valid customer is associated with that order.1 illustrates a nonrelational and a relational design of a database with customers and orders. click the chapter and section titles.DBF”. Even worse.To access the contents. such as Microsoft SQL Server. Tables and indexes are both stored as objects within the database. Figure 2. Both cases have four indexes: two on the customer data and two on the orders data.

With a single table. You can. there can be only one primary key on a table.3. there can be one and only one customer 101. and so on. you may also have a Social Security number. in this case. Figure 2.2 A relational database table is organized into columns and rows. have an inventory table where the combination of the part number and date purchased columns together form the primary key. the relational model offers no particular advantage over a sequential file. Such a key is known as a compound key. Notice the column containing the customer number.2 illustrates this with a simple implementation of a Customer table. It is customary but not required that the primary key columns be the first columns on the table. not having one defeats the whole purpose of relational database design for reasons that will become apparent as we continue our discussion. You can begin to see where the “relational” in relational databases comes in. (In addition to an employee number. you can expand upon the example to include another table: Orders. On the Customer table. The primary key may actually be more than one column on the table. A primary key is actually implemented as what is known as a unique index by the RDBMS. Every row in a table must be able to be uniquely identified. Customer.The columns correspond to fields in a sequential file. the table is organized into rows and columns as shown in Figure 2. for instance. Cust_No represents a column.3 The second table. Figure 2. . the Cust_No value stored on the Orders table must exist within the Customer table. one and only one customer 102. The power of the database is achieved when rows and columns on tables are logically constrained by values stored on other tables. A Note About Primary Keys Technically. The rows correspond to records. Again. However. there must exist something on each row in a table that is different from any other row on that table. whereas John Smith represents a row in a two-dimensional grid.) However. the RDBMS does not require you to ensure that each table has a primary key. Figure 2. is related to the first table. which is also unique. In other words. However. A table may actually have multiple unique indexes. the Cust_No column is the primary key. This aspect that makes a row unique is called a primary key. Orders.

In other words. The foreign key must be the same number of columns as the related key on the parent table and each of those columns must be the same data type. the value stored in a foreign key column on a child table—such as the Cust_No column on Orders—must exist on the parent table.4 shows the relationship between the Customer table and the Orders table with the foreign key. In general. If the related key on the parent table is. the Cust_No column on the Customer table. in this case. itself. Some databases require that the foreign key relate to the primary key of another table. then the foreign key must also be a compound key. Read EarthWeb's privacy statement. . All rights reserved.via the common column Cust_No. Sometimes this relationship is called child-parent. Figure 2. Table Relationships The RDBMS enforces the rule that the customer number on the order must already exist on the Customer table through the use of referential integrity. The Orders table is dependent on the Customer table because values on it must already exist in the master table.4 The Customer and Orders tables with primary keys and a foreign key enforcing their relationship. a compound key. Others only require that the related key on the parent table be a unique index. Figure 2. Specifically. Remember that a primary key is itself a unique index. Copyright © 1996-2000 EarthWeb Inc. you can create a foreign key on the Orders table that states that the Cust_No column must relate to a key on the Customer table. TIP Foreign Keys And Primary Keys The foreign key on a child table is dependent on a key on the parent table. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the foreign key specifies that the values of a column (or columns) on a dependent table must exist uniquely on a master table. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

in general. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Database Integrity When designing a database. A foreign key enforces referential integrity. integrity constraints can be placed in three categories: • Referential integrity—Enforces relationships between two tables. for any one order. • Domain integrity—Enforces values that can occur in any column across an entire table. • User integrity—Enforces values that can occur in a column based upon values on the same row. I cover the details of this concept under “Database Design” later in this chapter. as mentioned earlier. the table that is the “many” end of the relationship is always the child table and there should always be a foreign key defined to enforce that relationship. for now. I review how to create foreign keys on the database in “Data Definition Language” later in this chapter. However. click the chapter and section titles. there might be many orders. Although databases differ in their capabilities. you should understand that related tables are always related in a one-to-many manner.To access the contents. there can only be one customer. However. I described a foreign key as constraining the values that a certain column can contain on a table. Wherever a one-to-many relationship exists. it is important to remember that the foreign key is always defined as a constraint on the child or dependent table and that table is always part of a one-to-many relationship.4 reveals that for any one customer. enforces the requirement that a value uniquely identify a row on a table. This is an example of domain integrity. Domain integrity and user integrity can be enforced using a variety of constraint types: • The primary key. . an examination of Figure 2. For example. This is but one type of constraint that the database can enforce.

Fortunately. A primary key is implemented as a unique key. For instance. Although a number is really just a number regardless of what database is storing it. you might define a check constraint. • A check constraint validates the contents of a column on a row at either the domain or the user level. On the other hand. a Social Security number might be defined as unique. I show the syntax for creating each type of constraint later in this chapter. you can create a check constraint that requires salary to be greater than zero. it is also a domain integrity constraint. For instance. such as date of hire must be greater than date of birth (to avoid problems with child labor laws. Typically. Data types tend to fall into four categories: • Character data • Numeric data • Date data • Binary data Character Data Character data types can hold any alphanumeric values. A row may be defined as Not Null. you cannot perform arithmetic operations on it. that is dependent on another column on the same row. it right-pads the field with 16 spaces to fill up the field. This is an example of a user integrity constraint. For instance. I discuss null more thoroughly in Chapter 3. of course). The two main types of character data types are CHAR and VAR-CHAR. Because this rule applies to any row on the table. A CHAR data type is a fixed-length field defined as follows: Cust_LName CHAR (21) If Cust_LName holds the value ‘Jones’.) You can also employ a check constraint. the RDBMS vendors tend to differ somewhat in what they call those types.• A unique key requires that any value in a given row be unique within that column. These values are usually referred to as strings or string literals. what Oracle calls number Sybase and Microsoft call numeric. which validates that a column’s values are absolutely restricted. meaning that the column is not allowed to be null. Data Types Relational databases define each column to be a certain data type. the database automatically trims the longer of two search conditions: SELECT * FROM Customer WHERE Cust_LName = 'Jones' . most RDBMSs do not require you to account for this when searching for values. (Null is the absence of any value at all and is not the same as an empty string. Even if the string happens to contain a number.

In this example. the column holds up to 21 characters. the database automatically takes into account that the search term ‘Jones’ is shorter than Cust_LName. . the CHAR data type can waste a lot of space in a database. The VARCHAR data type (called VARCHAR2 by Oracle). If you do end up using some VARCHARs. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. put those columns at the end of each row where the performance penalty is minimized. Read EarthWeb's privacy statement. it is only 5 characters long. but if the name ‘Jones’ is stored. My recommendation is to use fixed-length CHAR data types for all but the biggest columns (such as a column to record comments). It is difficult to say what the performance is exactly. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. is a variable-length data type and looks like the following: Cust_LName VARCHAR (21) TIP CHAR Vs. disk space is cheap now and the database has to work harder to find columns where variable-length data is used. However. In this case. This was an important decision when disk space cost many dollars per megabyte. All rights reserved. but I would speculate that the average database takes a 10 percent performance hit if it employs all variable-length character types. VARCHAR There is some debate about which is the better data type to use. as its name implies. Certainly. Copyright © 1996-2000 EarthWeb Inc.

Scope refers to how many digits the number is allowed to hold. A real number is any number that can be represented in a fixed number of decimal . • INTEGER is a data type that holds a whole number from –32. click the chapter and section titles. As with the INTEGER data type. Thus.9999. you will run into the following data types (refer to your vendor’s documentation for any specifics or differences in implementation): • NUMERIC (S. SINGLE. and DOUBLE PRECISION are all variations on floating-point numbers. a column defined as NUMERIC (4. Even if your number has no digits to the right of the decimal place. In general.1 billion.To access the contents. SINGLE PRECISION.2 billion. • FLOATING POINT. and precision refers to how many of those numbers are to the right of the decimal place.999. numeric data can take many forms and vary more from RDBMS to RDBMS than other data types.999. you can use only nine to the left of the decimal point. the largest number that can be stored is 999. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Numeric Data Unlike character data. UNSIGNED LONG. DOUBLE. A floating-point number can handle either real numbers or irrational numbers (as well as whole numbers. An UNSIGNED INTEGER is capable of holding positive whole numbers from 0 to 65.768 to +32.2) In this example. which holds a positive whole number of 0 to approximately 4. your database may also support an unsigned variation. • LONG numbers can be any whole number of approximately negative 2.4) can be no larger than 0.767.536.99. P)—S stands for scope and P stands for precision. of course).1 billion to positive 2. as in the following example: Ord_Amount NUMERIC (11.

one bit is reserved for the mantissa to indicate a negative or positive number. The DOUBLE data type generally supports an exponent of plus or minus 308.333333… (to infinity). Single precision numbers (SINGLE or SINGLE PRECISION. Therefore.767. Scientific formats for numbers consist of three parts: the root. for instance. Thus. Even in an 8-byte field.014434267. Visual Basic. Inputting dates into the database can sometimes be a chore. you should consider that your front-end development language might not support the same range of dates.places. it is specified as an optional parameter when starting the database engine on the server). and the exponent: 144. With signed numbers. therefore. for instance. Usually. it does allow the computer to approximate very large and very small numbers with a high degree of accuracy. An irrational number cannot be represented in a fixed number of decimal points. has a range of 1 January. The format of the date that the database expects is usually a startup option (that is. 4714 BC to 1 January. However. you can override this setting in an individual session by using the SET command. 100 to 31 December. An example is 1/3. reducing the potential number of values to 215. Computers use what is the known as the IEEE format to store floating-point numbers in scientific format to get around this limitation. Oracle’s default date format is: INSERT INTO… .768 to + 32. which accommodates the storage of a very large or very small number in a compact manner. a signed integer field stored in 2 bytes has a range of –32. yielding the number . Double precision numbers are usually 8 bytes long. Number Storage On The Database Although you and I represent numbers decimally—that is. effectively making them able to handle a much larger range of numbers. which is .536.34267E+4. An exponent of –4 would indicate that the decimal point should be moved four places to the left. such as 1. the exponent +4 indicates that the decimal point should be moved four places to the right: 1443426. Oracle’s DATE data type. there can only be 264 possible values. 9999. Although this does not allow the storage of an infinite range of numbers. If a number is stored in 2 bytes. In this example. there are a total of 16 bits with possible values of 0 or 1. The database stores these numbers in scientific format. the letter E. Date Data Dates are encoded on the database as numbers and are. using what is called base 10—computers store numbers in binary format using base 2.7. The major RDBMSs are generally Year 2000 compliant. the largest possible number of values that can be represented without some sort of encoding algorithm is 216 or 65.25. depending on your database) are usually 4 bytes long. limited in their range. has a range of 1 January. 4712 AD.

Read EarthWeb's privacy statement. such as “\DOCUMENTS\CONTRACTS\J819980347. Should You Store Objects In The Database? Assume you are building a database for a legal firm handling many legal documents. you generally need to plan in advance how you will display and manipulate this type of data.VALUES ('18-Dec-98') Sybase. The down side of this approach. allows dates to be entered as either ‘1998-12-18’ (December 18. Binary Data Generally. . however. and you need to carefully evaluate the pros and cons of either approach. To alter the default format. The down side. which could impact performance. the only time you will need to store binary data is when you want to embed objects such as bitmaps or word processing documents into the database. However. make it the last column on your table where it will have the least impact on performance. on the other hand. you can specify SET OPTION Date_Order ‘DMY’. and year order. which then causes dates to be interpreted in day. Although some RDBMSs are adding object-oriented extensions to automatically handle these objects (refer to “A Note About Object-Oriented Databases” earlier in this chapter). Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. of course. is that it makes each row on the database very large. Copyright © 1996-2000 EarthWeb Inc. You might want to store those documents on the database where it is easy to associate them with specific clients. if you do decide to store the object directly in the database. such as contracts and wills. is that there is no longer any integrity constraint preventing that document from being moved from the \DOCUMENTS\CONTRACTS directory or even from being deleted. month. You accomplish such a task with the BLOB (Binary Large Object) data type. An alternative is to simply store a string with the path and name of the document. The choice depends on your needs. 1998) or ‘1998/12/18’.DOC”. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

determine relationships between those entities. Entity-relationship modeling seeks to identify entities.To access the contents. You accomplish this task by reassigning columns to existing or new tables. Two approaches have a considerable amount of overlap. Entity-Relationship Modeling With entity-relationship modeling. Let’s assume that we are modeling a simple college. and then assign attributes to those entities. This approach provides a logical design of the database where entities map to tables and attributes map to columns. I provide an overview of the essentials in the next few pages. provide a unique identifier for each.5 Summary of the entity-relationship modeling process. The first thing to do is . provide a method for enforcing those relationships. Figure 2. This approach seeks to take an existing design and validate it against a number of design guideline “rules” to eliminate processing anomalies. The other approach is database normalization. Although entire books are written on the theory and practice of database design. you seek to identify those entities that represent a business and eventually map them into a physical database design. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Database Design The key to a solid client/server application is a solid database design. Figure 2. click the chapter and section titles.5 shows a graphical representation of the process.

we have Students and Courses. draw a single arrowhead next to the Courses entity. one. typical entities would be Customers. Figure 2. For our example. or more than one course. In our mail-order company. a student can take zero. as shown in Figure 2. you need to ask yourself two questions for each related pair of entities: For each occurrence of the first entity. Figure 2. how many occurrences of Courses might there be? If there can be only one occurrence of Courses per occurrence of Students. Items. also draw a 0 on the line just before the arrowheads. how many occurrences of Students might there be? For purposes of this exercise. If there can be more than one. For any given occurrence of Courses. In our example. If there can be zero occurrences of Courses for each occurrence of Students. relate them each to the new entity. Figure 2. and so on.identify the business entities. Therefore. The next step is to determine the nature of the relationship.7. draw two arrowheads. Instead of relating the students and courses to each other. Next. we will assume that it can be one or many but not zero. how many occurrences might there be of the second entity? In addition. In this case.8.6 Step 1 of the modeling process. You are not permitted to have many-to-many relationships in a referential relationship. When you have double arrows at each end. Students and Courses are indeed related. for each occurrence of Students. The 0 drawn at the Courses end of the relationship is called a conditional relationship.7 Step 2 of the modeling process. we draw a line to represent that relationship. you need to resolve this problem by creating a logical entity called an assignment entity or a relationship entity.6. The result is shown in Figure 2. Because every entity must have a primary . If we were modeling a mail-order company. as shown in Figure 2. Therefore. how many occurrences might there be of the first entity? Using our example. the relationship is called a many-to-many relationship. An entity is something physical with a unique identifier. To do this. for each pair of entities. which we call Student_Courses. Orders. Because an entity must be uniquely identifiable. for each occurrence of the second entity. It might be helpful to place some wording on the drawing to describe how the two entities are related. we would have determined that Customers are related to Orders (because customers place orders) and that Orders are related to Items (because items appear on orders) but that Customers are not related to Items.8 Step 3 of the modeling process identifies the nature of the relationship between the two entities. we determine whether there is a relationship between the two. we assign a primary key to each one and draw them on a piece of paper.

you need to assign foreign keys to enforce the relationships between the tables. The revised diagram is shown in Figure 2. The last step is to assign attributes. Also.key. the child entity). However. but typically. Figure 2. The attributes always include the primary key and any foreign keys.11 Step 6 of the modeling process assigns attributes to each of the entities. the foreign key of the child table always corresponds to the primary key of the parent table. The Stud_ID that appears in the Student_Courses entity is a foreign key referencing the Students entity. there is a foreign key relationship. it is done on a separate piece of paper using a matrix as shown in Figure 2. remember that wherever a one-to-many relationship occurs.9. Figure 2. there is room to assign attributes on the same drawing as the relationship diagram. Next. and primary and foreign keys are identified. Entities become tables. A primary key that consists of more than one item is called a compound key. we assign one to the Student_Courses entity. Stud_ID and Course_ID. there must be a corresponding value in the parent entity. Figure 2. In entity-relationship modeling.11. Whenever you create a relationship entity.10 shows two foreign keys in the Student_Courses entity. Figure 2. The relationship entity always has a one-to-many relationship with both of the original entities. and the new entity is always at the many end of the relationship (it is. its primary key is always a combination of the primary keys of the two other entities—in this case. With the output of the entity-relationship modeling process. therefore.10 Step 5 of the modeling process assigns foreign keys to enforce referential integrity rules. attributes become columns. Remember that a foreign key means that for each occurrence of a child entity. you .9 Step 4 of the modeling process resolves any many-to-many relationships by creating relationship entities. you have the information that you need to create a physical database design from the logical one (as represented by the final model). which are things that describe the entities. Sometimes.

All rights reserved. . Read EarthWeb's privacy statement.should first validate your database design by normalizing it. Copyright © 1996-2000 EarthWeb Inc. This process is described in the next section. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

However. For purposes of illustration. click the chapter and section titles. It is quite conceivable that you can properly design a database using either approach alone.” We do this by comparing our design to a series of normal forms.To access the contents. although it offers little help to ensure that attributes are assigned to the proper entities. Database normalization seeks to do just this—verify attribute assignment by the application of standardized “rules. In terms of database operations. I don’t recommend it because each approach has advantages that the other doesn’t. an anomaly is an action that either produces an undesirable effect or prevents us from performing a desired action in the database. The order-entry system has the following pieces of information to be stored in the database: ORDERS Ord_No Ord_Date Cust_No Cust_Name Cust_Address Cust_City Cust_State . The entity-relationship modeling process is particularly well suited for identifying database integrity constraints. and delete anomalies. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Database Normalization There is a lot of overlap between the entity-relationship modeling process discussed in the last section and the database normalization process discussed in this section. update. I use a simplified order-entry system. We say that our database is fully normalized when it is in third normal form. I discuss these anomalies throughout this section. Each normal form seeks to eliminate data redundancy and to insert.

Cust_Postal_Code Item_No Item_Desc Item_Qty Item_Price Further. For instance. and so on form a repeating group. Ord_No) and a key that uniquely identifies the repeating group (in this case. and that an order can be placed for any number of items. First Normal Form First normal form. the columns Item_No. any one item can appear on the order only once.) However. you must move the repeating group to a new table. The insert and update anomalies here are intuitively obvious: With our present design. Second is an update anomaly: If an item’s description changes. A repeating group of data is an item that can appear more than once in a row of data. that any given order has only one customer. To resolve a first normal form violation. we need to assign a primary key to our present design. it must be updated on every single order for that item. we have an update anomaly in that we cannot add an item to the database unless there is an order for that item (because the item number and item description are not recorded until there is a row in the ORDER_ITEMS table). we cannot stop here because we have some anomalies. We will call the primary key Ord_No. states that there can be no repeating groups of data. we need to move on to second normal form. the item’s description is deleted as well. Item_No). because an order can be placed for multiple items. To begin. Therefore. sometimes abbreviated as FNF or 1NF. there is no way for a customer to order more than one item. a customer can call and purchase a number of different items all on the same order. The primary key of the new table is a combination of the primary key of the first table (in this case. Our revised design looks like the following: ORDERS Ord_No (PK) Ord_Date Cust_No Cust_Name Cust_Address Cust_City Cust_State Cust_Postal_Code ORDER_ITEMS Ord_No (PK) Item_No (PK) Item_Desc Item_Qty Item_Price Unfortunately. Third is a delete anomaly: If an order is deleted. Second Normal Form . (In other words. First. Item_Desc. I make the assumptions that a customer can place any number of orders.

All rights reserved. an item’s description changes if the Item_No is different but not if the Ord_No is different. Finally. To determine whether we have any second normal form violations. Copyright © 1996-2000 EarthWeb Inc. we have resolved our delete anomaly because deleting an order no longer deletes the associated items. we still have anomalies. In other words. Read EarthWeb's privacy statement. An examination of the table shows that Item_Desc is dependent on Item_No in the primary key but not on Ord_No. the ORDER_ITEMS table). To resolve this problem. we have to update every order that customer has placed. . Item_No). Our new design looks like the following: ORDERS Ord_No (PK) Ord_Date Cust_No Cust_Name Cust_Address Cust_City Cust_State Cust_Postal_Code ORDER_ITEMS Ord_No (PK) Item_No (PK) Item_Qty Item_Price ITEMS Item_No (PK) Item_Desc This resolves our insert anomaly from the first normal form because we can now insert a new item into the database even if there are no orders for it. we move the partial-key dependencies to another table whose primary key is the partial key from the original table (in this case. We have an insert anomaly in that we can’t add a customer to the database unless that customer places an order. To resolve this. states that we can have no partial-key dependencies. It also resolves our update anomaly because we now have only one row to update if an item’s description changes. we also delete the customer.Second normal form. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. we move on to third normal form. However. We have an update anomaly in that if we need to change the customer’s name or city. usually abbreviated as SNF or 2NF. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. we examine all tables with compound keys (in this case. We have a delete anomaly in that if we delete an order. A partial-key dependency is a column that is dependent on only part of the primary key.

we have to move the non-key dependencies to a new table whose primary key is that non-key column on which the columns were dependent (in other words. usually abbreviated TNF or 3NF. states that there can be no non-key (or intra-data) dependencies. Sometimes. We also leave that non-key column in the original table. To resolve this. such as resolving circular references. Our new design now looks like the following: ORDERS Ord_No (PK) Ord_Date Cust_No ORDER_ITEMS Ord_No (PK) Item_No (PK) Item_Qty Item_Price ITEMS Item_No (PK) Item_Desc CUSTOMERS Cust_No (PK) Cust_Name Cust_Address Cust_City Cust_State Cust_Postal_Code We are now in third normal form. If you see that you are going to end up having to join too many tables. you need to step back and examine the design with a critical eye toward performance. and nearly always indicate a totally inappropriate data model. you can stop at third normal form and conclude that your database is fully normalized.To access the contents. address. I have never needed to consider anything beyond third normal form. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Third Normal Form Third normal form. and fifth normal form. the Cust_No column). In our example. click the chapter and section titles. every column must be dependent on the primary key and not on another column that is not the primary key. Normally. customer name. you . These normal forms are used for rare circumstances. There are actually other normal forms: Boyce-Code normal form. fourth normal form. city. In other words. In my 15 years of working with relational databases. and postal code are all dependent on the customer number and not the order number.

Data Definition Language Data Definition Language (DDL) is one of three parts of SQL. which is the subject of the next section. compare the design to the output of your system. If you do.” .. or third normal form. if you find that you have missed data elements that need to be captured and stored. examine those bottlenecks and decide if they warrant denormalization. although either will work alone. SQL returns an error message similar to “object not found. However. When you log in to the database. if you perform a SELECT against the EMPLOYEE table without prefixing it with the owner. Every object’s name consists of two parts—the owner name followed by the table name: Mike.. you have a user ID. FROM Jane. Objects are tables. indexes. If you find that you need to join four or five tables frequently. Make sure that you have identified the correct data elements and that you have not introduced a performance nightmare. and then run some benchmark tests against it to see if you have any performance bottlenecks. consider denormalizing your database. Thus. and so on. the reports and screens. the database assumes your ID is the owner. your user ID is considered the owner of that table.EMPLOYEE If there is no Jane. part art. DDL is the language we use to create and modify objects in the database.EMPLOYEE or if you do not have permission to access the table. and part experience. keys. and you may well find that as you put together a database design. Then. If you issue any kind of SQL statement against an object such as a table and omit the owner name. add them into the design and repeat the entity-relationship modeling and the database normalization processes. and your ID is Jane. go through the steps of both entity-relationship modeling and database normalization anyway to confirm your design assumptions. I discuss Data Control Language (DCL) later in this chapter and Data Manipulation Language (DML) in the next chapter. it is already in first. it is important to understand the concept of ownership. Database Design Summary Database design is part science. A lot of the design work is simply common sense.might want to consider selectively denormalizing back to second or first normal form. I provided you with two tools that. I urge you to use in tandem to double-check your design. second. especially in the online environment. Before proceeding. it is time to create the database. Mike is the user ID that created the table EMPLOYEE.EMPLOYEE In this example. If you create a table. Once the database design is in place. My recommendation is to build the database in third normal form. load it with some sample data. Regarding the former. SQL translates your statement to: SELECT.

Read EarthWeb's privacy statement. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.DDL consists of three statements: CREATE. Copyright © 1996-2000 EarthWeb Inc. the next three sections deal with using these statements to work with tables. For purposes of this discussion. I discuss other database objects such as indexes and keys. and DROP. . Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. ALTER. Following that.

Emp_Mgr_ID SMALLINT. Emp_Dept_No SMALLINT. Emp_Dental_Ins CHAR (1).) Following CREATE TABLE. Emp_FName VARCHAR (15). Emp_Gender CHAR (1). list the data type and. Inside parentheses. After each column name. col_name . Emp_Health_Ins CHAR (1). Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- CREATE TABLE The CREATE TABLE statement has the syntax: CREATE TABLE TABLE_NAME (col_name DATATYPE [NOT NULL]. Emp_Hire_Date DATE NOT NULL. NOT NULL if the column is not allowed to have a null value. list the columns separated by commas. Emp_Comments VARCHAR (255) ) .. The syntax to create the EMPLOYEE table that I use throughout the remainder of this book is as follows: CREATE TABLE EMPLOYEE (Emp_No SMALLINT NOT NULL. specify the name of the table.2). click the chapter and section titles.. optionally. Emp_DOB DATE. Emp_Term_Date DATE. Emp_SSN CHAR (9).To access the contents. Emp_Salary NUMERIC (9. Emp_LName VARCHAR (21) NOT NULL.

TIP About The Tables Throughout this book.2). Emp_Dept_No SMALLINT.2) to read Emp_Salary NUMBER (9. If your database is not included. Emp_Gender CHAR (1). Emp_Hire_Date DATE NOT NULL. I recommend that you create all your tables first and then add the constraints later with ALTER statements. When you create tables and add constraints with the same code. Because there are small differences between different databases. CONSTRAINT Fk_Emp_Dept FOREIGN KEY (Emp_Dept_No) REFERENCES DEPARTMENT (Dept_No) ) This syntax presupposes that the table DEPARTMENT already exists. you can generally add a column at any time using the following syntax: ALTER TABLE EMPLOYEE ADD Emp_Maiden CHAR (21) NOT NULL . foreign keys. Emp_LName VARCHAR (21) NOT NUll. Emp_Comments VARCHAR (255). the Oracle CREATE statements are in the directory \SAMPDATA\ORACLE. including the EMPLOYEE table here. If it doesn’t. Appendix A contains the syntax to create all of these tables along with primary keys. but if you change the line Emp_Salary NUMERIC (9. I use a series of tables. the CD-ROM includes the INSERT statements needed to create the data. ALTER TABLE The ALTER TABLE command changes a table’s structure in some way. Emp_Term_Date DATE. Otherwise.2). Emp_FName VARCHAR (15). it will work with Oracle as well: CREATE TABLE EMPLOYEE (Emp_No SMALLINT NOT NULL. the CD-ROM contains these statements in RDBMS-specific directories. Emp_Mgr_ID SMALLINT. you need to create that table first. Emp_SSN CHAR (9). Emp_Health_Ins CHAR (1). Emp_Dental_Ins CHAR (1). Emp_DOB DATE. CONSTRAINT Pk_Emp_Id PRIMARY KEY (Emp_No). Emp_Salary NUMERIC (9. Additionally. You can optionally specify various table constraints such as primary keys at the same time you create the table. and so on. The following syntax is for Sybase SQL Anywhere. Exactly what you can change and when you can change it is somewhat dependent on the exact RDBMS. However. the modifications should be simple. For instance. figuring out which table needs to be built first can get complicated. it is highly likely that one of the supplied syntax variations will work just fine.

This example adds a column named Emp_Maiden with a data type of CHAR (21). Also dropped are all integrity constraints and permissions (I discuss permissions under “Data Control Languages” later in this chapter). you can specify a column as NOT NULL even if it was not originally defined that way. It is specified NOT NULL. In other words. For instance. You can add constraints to a table using syntax similar to the following: ALTER TABLE EMPLOYEE ADD CONSTRAINT Pk_Emp_Id PRIMARY KEY (Emp_No) ALTER TABLE EMPLOYEE ADD CONSTRAINT Fk_Emp_Dept FOREIGN KEY (Emp_Dept_No) REFERENCES DEPARTMENT (Dept_No) This example adds a primary key to the EMPLOYEE table and a foreign key that references the Dept_No column in the DEPARTMENT table. You cannot. unfortunately. as long as there are no null values already stored in the column: ALTER TABLE EMPLOYEE MODIFY Emp_Gender NOT NULL DROP TABLE The DROP TABLE command deletes a table and all of its data from the database. Note that many databases assume the primary key when you don’t specify the column name on the parent table. The syntax is: DROP TABLE EMPLOYEE Previous Table of Contents Next . The column is always added to the end of the table. delete a column. the following statement causes SQL to assume that the primary key of the DEPARTMENT table is being referenced: ALTER TABLE EMPLOYEE ADD CONSTRAINT Fk_Emp_Dept FOREIGN KEY (Emp_Dept_No) REFERENCES DEPARTMENT Some databases allow you to modify the definition of an existing column as long as the currently stored data in that column does not violate the new column definition.

All rights reserved. Read EarthWeb's privacy statement. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. .Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

You will want to use indexes judiciously. an index tremendously speeds up retrieval time. For instance. or non-unique. if you need to list employees in last name. the rows are arranged in the same order as the index. The indexes may be unique. check your RDBMS documentation. Because the syntax for creating clustered indexes varies greatly from database to database. first name order. They can speed up database operations tremendously when you often access data in a certain manner. If you update a table on the database. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Indexes The database allows you to add indexes on one or more columns of any table. You can also use a unique index as a constraint to restrict the values in a column on a table. click the chapter and section titles. If more than one is listed. On the other hand. The syntax to create an index is as follows: CREATE [UNIQUE] INDEX INDEX_NAME ON TABLE_NAME (col_name. Thus. values. you must update all the indexes on that table as well. With a clustered index. indexes need to be maintained. The col_name must be a valid column on that table. the column names must be comma-delimited. For instance. Emp_FName) Most databases allow you to create one clustered index per table. col_name …) The TABLE_NAME must be any valid table name.To access the contents. meaning that the index does not permit duplicate. which speeds up retrieval. you might want to add a unique index on the Social Security number of an employee table. you want to . The following examples add a unique index on the Emp_SSN column and a non-unique index on the Emp_LName and Emp_FName columns: CREATE UNIQUE INDEX IDX_SSN ON EMPLOYEE (Emp_SSN) CREATE INDEX IDX_NAME ON EMPLOYEE (Emp_LName.

only use indexes where they are needed. When a check constraint references another column on the same row. it specifies that gender must be ‘M’ or ‘F’. it must be a valid value from the parent table. Fortunately. Even so. most modern query optimizers usually see this and don’t use the index. the optimizer attempts to determine the most efficient way of fulfilling the request. Different RDBMSs have some variance in how to create these constraints. (This is an example of a conditional foreign key constraint. which is not supported by all RDBMSs. You cannot use an SQL select in a check constraint. The syntax that I presented is fairly generic and works on most RDBMSs. However. A check constraint restricts the values of the columns by providing an SQL function. requiring that the value stored in Emp_Dept_No be a valid value in the Dept_No column on the DEPARTMENT table. which add three constraints to the EMPLOYEE table: ALTER TABLE EMPLOYEE ADD CONSTRAINT Pk_Emp_Id PRIMARY KEY (Emp_No) ALTER TABLE EMPLOYEE ADD CONSTRAINT Fk_Emp_Dept FOREIGN KEY (Emp_Dept_No) REFERENCES DEPARTMENT (Dept_No) ALTER TABLE EMPLOYEE ADD CONSTRAINT Ch_Gender CHECK (Emp_Gender IN ('M'. The second adds a foreign key constraint. it actually says that if the value is not null. Because the Emp_Dept_No column was not defined as NOT NULL. forcing the Emp_No column to be a unique identifier for the table. If indexes are available. In this case. A couple of notes are in order. For other options. you should consider the nature of the data in the columns that you are thinking about indexing. consult your RDBMS documentation. When you issue a query against the database. The constraint could also reference another column on the same row. it attempts to use them. it is called a user integrity constraint. Integrity Constraints In the previous discussion of CREATE TABLE and ALTER TABLE. the Emp_Gender column has only two values: F and M) it is actually more expensive to use the index than to ignore it.) The third example is an example of a check constraint. the column may also contain null values. I presented some sample syntax on creating primary key and foreign key constraints. TIP Indexes And The Query Optimizer All of the RDBMSs have a built-in query optimizer.'F') The first example adds a primary key constraint to the table. if a column has only three or four discrete values (for example. as in the following example: ALTER TABLE EMPLOYEE ADD CONSTRAINT Ch_Hire_Date CHECK (Emp_Hire_Date > Emp_DOB) This example requires that hire date be greater than date of birth. When it provides an absolute check . Consider the following statements. and most allow you to create constraints in a variety of different manners.

(such as being only ‘M’ or ‘F’ without regard for other columns on the row). Because the view EMPNOSAL does not contain the Emp_Salary column. the database responds with a message similar to “Update Failed . If you do not. it is called a domain integrity constraint. Emp_LName. you should also omit the CONSTRAINT keyword. if you attempt to set Emp_Gender = ‘X’. you do not need to provide a constraint name.'F')) Views A view is an SQL SELECT permanently stored on the database. select from it as though it were a table: SELECT * FROM EMPNOSAL ORDER BY Emp_LName. Emp_Mgr_ID FROM EMPLOYEE To use the view. Previous Table of Contents Next . For instance. Emp_FName A view is not a copy of the data—just a stored query. If you elect not to name the constraint. the employee’s department number was updated (I discuss the syntax for the UPDATE command in Chapter 3). A view can be convenient for your users because it helps them avoid typing complicated queries. My recommendation is that you do provide a name so that any messages from the database are meaningful. Also note that most databases allow you to update through a view. the user can’t update salary information. Emp_FName. Generally. It can also be used to show a user a portion of the table without revealing the entire underlying table. as in the following example: ALTER TABLE EMPLOYEE ADD CHECK (Emp_Gender IN ('M'. as in the following example: UPDATE EMPNOSAL SET Emp_Dept_No = 200 WHERE Emp_No = 100 In the example.Integrity Constraint: CH_GENDER”. the database generates one. The following example creates a view on the EMPLOYEE table that allows users to see information such as name but not salary: CREATE VIEW EMPNOSAL AS SELECT Emp_No. Emp_Dept_No.

. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Read EarthWeb's privacy statement.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

For instance. . Data Control Language Data Control Language (DCL) consists of two commands that control who has access to what objects on the database. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Triggers And Stored Procedures A trigger is a small program that is stored on the database and defined to run automatically as a result of a database action. another stored procedure. click the chapter and section titles. The program consists of SQL statements plus RDBMS-specific extensions. if you want to give another user access to an object that you created. a trigger written for an Oracle database is created using PL/SQL. This is an ideal candidate for a trigger that is tied to the address table and defined to run any time a row is updated or inserted.To access the contents. such as an insert or update of a certain table. The advantage of triggers and stored procedures is that they can move a good deal of business logic onto the server. A stored procedure is similar to a trigger except that it runs when called by a trigger. later in the book I introduce some examples to show how triggers and stored procedures are used by your Visual Basic programs. For example. Beyond that. the syntax for triggers and stored procedures is highly variable. Nevertheless. Implementing this rule as a trigger both reduces network traffic and relieves the client program of the burden of performing this edit. you must specifically grant him or her permission. the database administrator (DBA) has authorization to all objects. By definition. you might want the ZIP code to be validated every time an address is updated. or your program. Because each RDBMS uses different SQL dialects.

use the following syntax: GRANT CONNECT TO Jane IDENTIFIED BY new_password To grant access to individual objects (such as a table). To grant permissions to all users. Also. You can then grant permissions to and revoke permissions from the groups. where I provide the syntax used to create the sample databases in this book as well as the syntax for the constraints. you might want to look at Appendix A. we have taken away update and delete privileges from users Dick and Harry. . specify PUBLIC instead of a user list: GRANT SELECT ON DEPARTMENT TO PUBLIC You can selectively revoke permissions. The syntax to revoke privileges is similar to the following: REVOKE UPDATE. UPDATE. From here. he or she must first be granted connect privileges: GRANT CONNECT TO user_ID IDENTIFIED BY password This syntax creates a new user and password. you have to grant a comma-delimited list of permissions to a comma-delimited list of users on one table at a time: GRANT SELECT. Where To Go From Here This chapter covered the theory of relational databases from their history through the theory of database design to actually implementing that design. Dick. but you cannot revoke access from yourself. I discuss the key differences between Jet SQL and ANSI SQL.The two commands used are GRANT and REVOKE. AND Harry To grant all permissions. For a user to have access to the database. “An Introduction To SQL Data Manipulation Language. This technique helps simplify administration. which is a concern both for developers using Access databases and VB developers using Microsoft Jet in conjunction with DAO.” Data Manipulation Language (DML) is where you will spend most of your SQL time. you will want to read the next chapter. so it is a critical concept to learn. DELETE ON EMPLOYEE FROM Dick. use GRANT ALL PERMISSIONS. Harry In this example. DELETE ON EMPLOYEE TO Tom. Most databases allow you to create groups and assign users to groups. Assuming the user ID is Jane. to alter the password. In Appendix B. Their select privileges remain.

Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. . Read EarthWeb's privacy statement. All rights reserved.

but other. it is not a separate database engine. In this chapter. the application program is responsible both for creating the data request and for creating the . I also discussed the theory of relational database design and showed you the SQL syntax used to implement that design. for example). including self-joins • SQL subqueries • Performance considerations in tuning an SQL statement In Chapter 2. I need to stress again that SQL is not a database nor does it necessarily imply the existence of a back-end relational database engine. I guide you through the essential concepts of using Structured Query Language (SQL) to access and manipulate your database. click the chapter and section titles. although a product such as Microsoft Access is a fully relational database. mentioning at the same time that SQL is used to access and manipulate the database. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 3 An Introduction To SQL Data Manipulation Language Key Topics: • The definition and purpose of SQL • Data Manipulation Language • Scalar and aggregate functions • Grouping data and the HAVING clause • Joining tables. All RDBMSs use SQL as an interface (to extract data or to create tables. non-relational data models such as dBase may offer SQL as an access language.To access the contents. I discussed the concept of the relational database. Further.

SQL-92 is an ANSI definition of what features must be supported in a full implementation of SQL. still evolving. • OLE DB—A new. The RDBMS processes the statements and sends the results back to the application program. the developer can write code to access virtually any back-end database while being shielded from the complexities of the different access methods. for instance. I discuss the differences in Appendix B. API that exposes the underlying functionality of a wide variety of databases in an object-oriented manner. The back end might be an RDBMS. they create SQL statements and send them to the RDBMS. Microsoft has been moving away from the Sybase model of T-SQL. such as Oracle. it is ANSI-92 compliant. which defines each character to be 1-byte long with the decimal value 65 representing the letter A.) Additionally. (Microsoft Access uses Jet SQL. To shelter the developer from the intricacies of learning different APIs for each RDBMS. • ODBC (Open Database Connectivity)—An API that applications can address to further expose the underlying functionality of a wide variety of databases. This shielding is accomplished by providing a .query result. Mostly. OLE DB also allows the joining of disparate data sources. (I expanded upon this in Chapter 2 when I defined the term RDBMS. it is not ANSI-92 compliant. or it might be an Indexed Sequential Access Method (ISAM) file. All of the major relational database products. are 100 percent ANSI-92 compliant. the language needs to support the SELECT statement and the SUM function. Although Jet SQL is close. We are all familiar with the ANSI character set. Visual Basic provides varying levels of intermediate drivers (such as Microsoft Jet) that shelter you from the need to write API calls. whereas Sybase and Microsoft use Transact-SQL (usually called T-SQL). most vendors add extensions (additional features) implemented as what are commonly called dialects of SQL. such as a FoxPro database. A Note About ODBC ODBC is itself an API that application programs can use to gain access to a variety of database back ends using standard SQL. The many variations on how this is done is the subject of much of this book. If a vendor’s database product is in full compliance with these standards. In theory.) What Is SQL? The American National Standards Institute (ANSI) defines various computer industry standards. Oracle uses PL/SQL. the dialects are close enough in syntax that moving from one to the other is relatively easy. three categories of drivers were developed to interface with Visual Basic: • VBSQL—A Visual-Basic-specific set of drivers that allow “native” interface to Microsoft SQL Server. For example. Each RDBMS exposes its functionality via an Application Programming Interface (API). When application programs access a relational database. Appendix C overviews the implementation of ODBC. such as Oracle and Microsoft SQL Server.

including statements such as ALTER TABLE as well as more advanced SELECT functionality. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Level 1. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.single API. and so on. refer to Appendix C in this book. is an implementation of SQL that is at least ANSI-92 compliant. There are actually three levels of ODBC compliance: Level 0. as well as to the ODBC 3. Finally. For technical information about ODBC standards and driver development. Figure 3. is a set of minimal functionalities that must be supplied by an ODBC driver. is a more thorough implementation of SQL. The exact definition of each of these compliance levels is discussed in Appendix C. . Level 2. sometimes called Minimum ODBC. Microsoft builds a variety of drivers for both Microsoft and non-Microsoft back-end database products. such as the MAX and MIN functions. All rights reserved. It is not always easy to determine the level of conformance of a given ODBC driver. including the ability to perform basic SQL SELECTs and so on. cursor-positioned UPDATEs. which communicates with ODBC drivers written for each of the different back-end databases.1 illustrates this communication process. some vendors create drivers for their own database products. which in turn communicates with the individual database-specific drivers. Read EarthWeb's privacy statement.1 Client programs communicate with the ODBC API. or Extended ODBC. and performances of the drivers vary from vendor to vendor. not all ODBC drivers are created equal. including outer joins. Intersolv also markets a wide variety of drivers that you can use in your programs. the most notable example is the very well implemented Level 2-compliant Sybase SQL Anywhere database. Figure 3. In reality. sometimes called Core ODBC.0 Programmer’s Reference And SDK Guide available from Microsoft Press. These drivers interact with the back-end databases. Copyright © 1996-2000 EarthWeb Inc.

To access the contents. Use the SELECT clause to list those columns that are to appear in the result set. SELECT The SELECT statement is used to retrieve rows from the database. UPDATE. DELETE. In Chapter 2. The following example selects three columns from the EMPLOYEE table: . click the chapter and section titles. Each column name must be separated by a comma. The basic syntax of the SELECT statement is: SELECT [DISTINCT] column-list| * FROM table-lisT [WHERE condition1 AND condition2…] [GROUP BY column-list [HAVING condition1 AND condition2…]] [ORDER BY column-list] All clauses except FROM are optional. separate the table names with commas. most developers will spend most of their time coding SQL SELECT statements. I discussed Data Control Language (DCL) and Data Definition Language (DDL). Of these four statements. I discuss the use of each of these statements. For more than one table. There are only four DML commands: INSERT. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Data Manipulation Language (DML) Most client/server developers will spend the majority of their time using DML—that portion of SQL used to manipulate the actual data stored in SQL tables. To select all columns. Use the FROM clause to list the tables that contain the columns being referenced. and SELECT. In the sections that follow. you can use the asterisk instead of listing each column separately.

08 FROM EMPLOYEE The next example creates a derived column that is actually a string literal: SELECT EMP_FNAME. system functions. Some RDBMSs provide a “dummy” table from which to select such non-data-related functions: SELECT SYSDATE FROM DUAL This example is from Oracle. EMP_LNAME. EMP_LNAME FROM EMPLOYEE The next example selects all the columns from the EMPLOYEE table: SELECT * FROM EMPLOYEE Derived Columns SQL allows you to “select” columns that are not part of the database by creating derived columns. Even still. The following SELECT creates a derived column that is the result of multiplying EMP_SALARY by 1. you get a result set of 100 lines of the current date and time.08: SELECT EMP_SALARY * 1. and if the table has 100 rows.SELECT EMP_ID. or the results of operations on table columns. These columns might be string literals. 'IS AN EMPLOYEE' FROM EMPLOYEE As shown in the following result set. TIP About The Examples Except where specifically noted. If you select SYSDATE from the EMPLOYEE table. . EMP_FNAME. which provides a table named DUAL with a single row so that you can select against system-level functions. the SELECT statement must have a FROM clause. See Appendix A for details on loading this information into your database. SYSDATE returns the current date and time from the database server. For instance. the string literal is returned for every row: EMP_FNAME --------ANN BOB CAROL EMP_LNAME --------CALLAHAN JOHNSON DEMORA 'IS AN EMPLOYEE' ---------------IS AN EMPLOYEE IS AN EMPLOYEE IS AN EMPLOYEE Some system functions are not truly related to any data at all. all of the examples in this chapter use the sample data provided on the CD-ROM.

000 as well as those employees who make more than . For specifying more than one search condition.000: SELECT * FROM EMPLOYEE WHERE EMP_GENDER = 'F' AND EMP_SALARY > 50000 The WHERE clause allows Boolean logic to determine which rows are to be returned. use the AND keyword. the column headings default to the column names. The following WHERE clause specifies that the result set should include females who make more than $50. Some databases require that you use double quotes all the time (regardless of whether there is a space in the name). The WHERE Clause The WHERE clause is used to restrict the rows returned in the result set by specifying search conditions. you can easily create one: CREATE TABLE DUMMY (DUM_COL CHAR(10) ) INSERT INTO DUMMY VALUES ('DUMMY') SELECT SYSDATE FROM DUMMY When the result set is displayed. You can rename a column heading using the AS keyword: SELECT EMP_NO AS 'EMPLOYEE NUMBER' FROM EMPLOYEE Some databases allow you to omit the AS keyword. If the new column name contains a space.If your database does not provide a dummy table. NOT negates the search condition: WHERE NOT EMP_GENDER = 'F' OR allows for the selection of rows based upon multiple criteria: WHERE EMP_GENDER = 'F' OR EMP_SALARY > 50000 Use NOT to negate a search condition: WHERE NOT (EMP_SALARY > 50000 AND EMP_GENDER = 'F') Use parentheses to perform algebraic evaluations of search conditions. you must surround the column name with double quotes. The following SELECT returns all rows in the EMPLOYEE table where gender is female and where salary is greater than 50.

The following example returns rows where the length of the last name is greater than five: WHERE LENGTH(EMP_LNAME) > 5 A column used in the WHERE clause does not have to appear in the SELECT statement. understand that a scalar function is one that operates on a single value at a time (such as returning the length of a last name). use the underscore (_) character to represent a single character and the percent sign (%) to represent any number of characters. EMP_LNAME FROM EMPLOYEE WHERE EMP_GENDER = 'F' You can perform wild-card searches using the LIKE keyword. To do so.000 (regardless of gender): WHERE (EMP_GENDER = 'F' AND EMP_SALARY > 50000) OR EMP_SALARY > 75000 You may use a scalar function in a WHERE clause but not an aggregate function. as shown in the following example: SELECT EMP_ID. All rights reserved. but for now. Read EarthWeb's privacy statement. EMP_FNAME. I discuss SQL functions later in this chapter. The following statement searches for all last names beginning with the letter B: WHERE EMP_LNAME LIKE 'B%' Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc. . whereas an aggregate function operates on a range of values (such as returning the sum of all salaries). Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.$75.

Testing for the existence of null values requires special functions. they must be in single quotes: WHERE EMP_LNAME IN ('BROWN'. click the chapter and section titles. The following statement locates rows where YEARS is null: . Later in this chapter. Though the SQL code samples in this book have all keywords in uppercase. Because any operation involving null is automatically null (I discuss this fully later in this chapter). You separate each value with commas and place the entire list inside parentheses.To access the contents. 'JOHNSON') TIP About Databases And Case Sensitivity When dealing with character data (strings). the database is case sensitive just as Visual Basic is case sensitive when comparing two strings. 'SMITH'. With BETWEEN. you can specify an inclusive range of values as in the following example. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The next example locates all those rows where the last names have the letter B in the second position and the letter D in the fourth position: WHERE EMP_LNAME LIKE '_B_D%' The WHERE clause also supports the use of the BETWEEN and IN modifiers. which returns rows where the salary is from $50.000: WHERE EMP_SALARY BETWEEN 50000 AND 60000 The IN keyword allows you to search a list of discrete values.000 to $60. If the values are strings. SQL provides the IS NULL and IS NOT NULL functions. databases are generally not case sensitive with column names unless you surround the column names with double quotes. I will introduce case conversion functions to help deal with this problem.

DEPARTMENT WHERE EMPLOYEE. EMP_LNAME FROM EMPLOYEE.EMP_NO. DEPARTMENT WHERE DEPT_NO = EMP_DEPT_NO Although I did not do so. EMP_FNAME. . especially when qualifying column names. both of which I discuss later in this chapter. EMP_LNAME FROM EMPLOYEE. Aliased names are often referred to as correlation names. you need to tell SQL how the tables are related. of course. You do this with the WHERE clause. Obviously then. Therefore. Table Aliasing Typing in all those table names can be tiring. If I want to produce a list of departments and all the employees in each of those departments. many developers use common column names between tables. Whereas I used EMP_DEPT_NO in the EMPLOYEE table to store the department number. you use the alias instead of the table name elsewhere in the query: SELECT EMP.WHERE YEARS IS NULL Joining Tables When you select data from more than one table. given a row in the DEPARTMENT table. There is nothing wrong with this at all. particularly when dealing with subqueries. I want to list all rows in the EMPLOYEE table where DEPT_NO is equal to EMP_DEPT_NO. EMP_NO. others might have simply used DEPT_NO.DEPT_NO = DEPARTMENT. DEPARTMENT DEP Once you have aliased a column. EMP_FNAME. and the DEPARTMENT table has a DEPT_NO column. However. The example assumes. the two tables both have a column with the same name (DEPT_NO). EMP_NO. I need to relate the EMPLOYEE table to the DEPARTMENT table. Consider the DEPARTMENT and EMPLOYEE tables (see Appendix A for how the tables are defined). DEPT_NAME. DEP. that the two column names are identical. Each row on the EMPLOYEE table has an EMP_DEPT_NO column.DEPT_NO Aliasing also has implications in correlated subqueries and self-joins.DEPT_NO This example shows how to qualify the column names where ambiguity exists.DEPT_NO. if an SQL query references a column name that appears in more than one table in the query. This forms a join condition: SELECT DEPT_NO. you have to qualify the column name with the table name to avoid ambiguity: SELECT DEPARTMENT. DEPT_NAME. SQL allows you to alias table names in the FROM clause: FROM EMPLOYEE EMP.

You can join together more than two tables. If in the previous example I want to add the location name (from the LOCATION table), I have to join that table to one of the other two tables. The DEPARTMENT table has a column DEPT_LOC_ID that corresponds to the LOC_ID column in the LOCATION table. Therefore, my query might look like this: SELECT DEPT_NO, DEPT_NAME, LOC_NAME, EMP_NO, EMP_FNAME, EMP_LNAME FROM EMPLOYEE, DEPARTMENT, LOCATION WHERE DEPT_NO = EMP_DEPT_NO AND DEPT_LOC_ID = LOC_ID Sample output based on the above query is shown here: DEPT_NO ------100 100 100 100 DEPT_NAME --------ACCOUNTING ACCOUNTING ACCOUNTING ACCOUNTING LOC_NAME -------NORTHEAST NORTHEAST NORTHEAST NORTHEAST EMP_NO -----133 101 105 113 EMP_FNAME --------MAUREEN ANN EUNICE MICHAEL EMP_LNAME --------PODANSKI CALLAHAN BROWN ANDERSON

Self-Joins
A confusing concept for many developers is that you can join a table to itself. Consider the EMPLOYEE table: One of the columns is EMP_MGR_ID, which represents the manager of the employee. If you select the contents of the EMPLOYEE table, you will see that employee number 126’s (David Madison) manager is employee 110 (John Smith). Assume I want a list of all employees and the names of their managers. In Figure 3.2, you can see where I need to join a column from one row (EMP_MGR_ID) with a column in another row (EMP_NO). Essentially, I need to “pretend” that there are two copies of the EMPLOYEE table.

Figure 3.2 To find the name of David Madison’s manager, I need to reference the EMP_MGR_ID column on David’s row and use it to find John Smith’s row. The query that I put together uses two aliases for the EMPLOYEE table. I use the first alias (EMP) to find the employee information and the second (MGR) to find the manager information: SELECT EMP.EMP_NO AS 'EMP NO', EMP.EMP_FNAME AS 'EMP FIRST', EMP.EMP_LNAME AS 'EMP LAST', MGR.EMP_NO AS 'MGR ID', MGR.EMP_FNAME AS 'MGR FIRST', MGR.EMP_LNAME AS 'MGR LAST' FROM EMPLOYEE EMP, EMPLOYEE MGR WHERE EMP.EMP_MGR_ID = MGR.EMP_NO

ORDER BY EMP.EMP_LNAME, EMP.EMP_FNAME

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

The join is on the EMP_NO column from the MGR copy of the EMPLOYEE table to the EMP_MGR_ID column of the EMP copy of the table. Sample output based on the query is presented here. Note that Ann Callahan has no manager: EMP NO -----111 113 106 105 101 EMP FIRST --------KATHRYN MICHAEL FRANK EUNICE ANN EMP LAST -------AMES ANDERSON BENSON BROWN CALLAHAN MGR ID -----119 101 110 101 101 MGR FIRST --------URSULA ANN JOHN ANN ANN MGR LAST -------SMITHSONIAN CALLAHAN SMITH CALLAHAN CALLAHAN

Self-joins are not terribly difficult once you get used to the idea of joining a table to itself; they can often be useful to find information in one row that is related to information in another row in the same table.

The ORDER BY Clause
You can ask the database to sort your result set by using the ORDER BY clause. Specify the column or columns by which you want to sort your result set. If ordering by more than one column, separate the column names with commas. The default sort sequence is ascending. If you want to sort in descending order, specify the DESC option. The following query lists employees and their salaries sorted by department number. Within each department number, the employees are sorted by salary in descending order: SELECT EMP_DEPT_NO, EMP_FNAME, EMP_LNAME, EMP_SALARY FROM EMPLOYEE ORDER BY EMP_DEPT_NO, EMP_SALARY DESC Sample output based on the query is presented here:

EMP_DEPT -------100 100 100 100 100 100 100 100 200 200 200

EMP_FNAME --------ANN MICHAEL ROSE EUNICE CHARLES WINIFRED MAUREEN GEORGE DAVID HENRIETTA BRIAN

EMP_LNAME --------CALLAHAN ANDERSON DANIELS BROWN GERRFON VANCE PODANSKI DE NORVA MADISON KEOUGH JOHNSON

EMP_SALARY ---------127500.00 72563.34 67572.42 61426.08 53496.87 37712.10 34591.90 21313.97 77492.47 72789.20 72750.62

The columns that you order by do not have to appear in the SELECT list, although it makes no sense not to include them. (How would the reader know that data was sorted by department if you did not display the department?) You can order positionally by specifying the column number instead of the column name, as shown in this example: ORDER BY 1, 4 DESC However, it is likely that the next ANSI SQL standard will remove this option as part of the SQL definition. You may, therefore, be better off ordering by the column names themselves. If you have renamed the columns (see the discussion of SELECT earlier in this chapter), you can order by the “new” column name as shown: SELECT EMP_FNAME AS 'FIRST', EMP_LNAME AS 'LAST' FROM EMPLOYEE ORDER BY 'LAST', 'FIRST' Under certain circumstances, you must order by the new column names. An example is performing a UNION (which I discuss next).

UNION And UNION ALL
The UNION statement allows you to combine the results of two queries. The only restrictions are that the queries must include the same number of columns and that the columns must be the same general data type. (For example, it is okay that one is a CHAR and the other is a VARCHAR.) You can combine as many queries as you want. Whereas UNION ALL combines all rows, UNION sorts the result set and eliminates any duplicate rows. Ordering a UNION query can be tricky because the column names from one query to another may be different (as in the following example). Positional ordering is most convenient. Some databases require that you order by the column names of the first query (EMP_NO and EMP_LNAME in the following example) or that you rename the columns and order by those new names. Check your RDBMS documentation or just try the query and experiment with the ORDER BY clause:

SELECT EMP_NO AS 'NUMBER', EMP_LNAME AS 'NAME' FROM EMPLOYEE UNION SELECT DEPT_NO, DEPT_NAME FROM DEPARTMENT ORDER BY 2, 1

SQL Functions
SQL provides a number of functions to manipulate information from the database. Functions fall into two categories: Scalar functions act on one item at a time and aggregate functions act on a range of values at a time. Deciding whether a function is scalar or aggregate is more than an academic exercise. Consider the WHERE and HAVING clauses (I discuss HAVING later in this chapter): • WHERE clause—You can use a scalar function as a search condition in a WHERE clause. For instance, WHERE SQRT (EMP_SALARY) > 5000 (SQRT returns the square root of an expression) is valid, but WHERE SUM (EMP_SALARY) > 250000 is not. • HAVING clause—You can use aggregate functions in a HAVING clause to restrict a result set. For instance, HAVING SUM (SALARY) > 250000 is valid, but HAVING SQRT (EMP_SALARY) > 5000 is not. Whether a function is scalar or aggregate also has an impact on handling of null values.

Null Handling
A value of NULL stored in a database creates special problems. Consider the following: 100 + NULL = ? Nonintuitively, the answer to this equation is NULL. Any operation performed on NULL is automatically NULL. Assume that you want to give every employee a $100 a week raise, and you want to see what the new weekly salary for each employee would be. You might code the following query: SELECT EMP_FNAME, EMP_LNAME, EMP_SALARY/52 + 100 FROM EMPLOYEE The SELECT works fine except for those employees whose salary happens to be NULL. The result for those employees is still NULL. Different databases handle this problem with various functions. With Oracle, you can use the NVL function: SELECT EMP_FNAME, EMP_LNAME, NVL(EMP_SALARY, 0)/52 + 100 FROM EMPLOYEE In this case, the NVL function specifies that if EMP_SALARY is NULL, then the value 0 should be substituted. Some other RDBMSs implement the similar function ISNULL:

SELECT EMP_FNAME, EMP_LNAME, ISNULL(EMP_SALARY, 0, EMP_SALARY)/52 + 100 FROM EMPLOYEE

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

In this case, the ISNULL function says that if EMP_SALARY is equal to NULL, the value 0 should be substituted. If it is not equal to NULL, the EMP_SALARY value should be used. (The ISNULL function is similar to the IF function in most spreadsheets.)

Selected SQL Functions
SQL functions are one of those areas with a fairly high amount of variability between RDBMSs. Some functions, such as SUM, are common to all, whereas others may have no equivalent in another RDBMS. For instance, Oracle has a flexible TO_CHAR function to convert a noncharacter data type (such as DATE or NUMBER) to a character type and optionally format the output. Sybase uses either the CAST or CONVERT function to accomplish the same thing. In general, if you are comfortable with using functions in one RDBMS, you will have little problem moving to another RDBMS. In the following sections, I discuss some of the functions you are most likely to use on a regular basis.

DISTINCT
Arguably, DISTINCT is not as much a function as it is a SELECT statement qualifier. However, because it operates on a single value, I include it here. Its purpose is to return only unique values for a row: SELECT DISTINCT (EMP_DEPT_NO) FROM EMPLOYEE The result is: EMP_DEPT_NO ----------100

200 300 400 Most databases do not require that the column name be surrounded by parentheses when using DISTINCT (however, it does not hurt to use them).

COUNT
COUNT returns a count of all rows that meet a condition. For instance, COUNT (EMP_DEPT_NO) returns 32 because there are 32 values stored in that column. However, COUNT (DISTINCT (EMP_DEPT_NO)) returns 4 because there are only 4 unique values. Often, COUNT (*) is used to find the number of rows on a table: SELECT COUNT(*) FROM EMPLOYEE Also, you can use COUNT(*) in conjunction with the GROUP BY clause to determine counts in categories (I discuss GROUP BY later in this chapter): SELECT EMP_GENDER AS 'GENDER', COUNT(*) AS 'COUNT' FROM EMPLOYEE GROUP BY EMP_GENDER The following result set is returned: GENDER -----F M COUNT ----18 14

SUM
SUM adds values in a column. To obtain a total of the salaries from the EMPLOYEE table, run the following query: SELECT SUM(EMP_SALARY) FROM EMPLOYEE The following is the result: SUM(EMP_SALARY) --------------1861241.06

MIN, MAX, And AVG
MIN calculates the minimum value in a column. Similarly, MAX calculates the maximum value, and AVG calculates the average value: SELECT MIN(EMP_SALARY), MAX(EMP_SALARY), AVG(EMP_SALARY)

FROM EMPLOYEE The result is: MIN(EMP_SALARY) --------------18331.50 MAX(EMP_SALARY) --------------127500 AVG(EMP_SALARY) --------------58163.78

LENGTH
As with the Visual Basic LEN function, LENGTH returns the length of a column or expression. LENGTH (“Smith”) returns 5.

SOUNDEX
SOUNDEX searches for strings based upon their similarity (in sound) to the supplied argument. Although this should be a powerful function, its usefulness can be iffy. RDBMSs tend to have different levels of tolerance for what two words sound alike and may need some tuning. The following query and result comes from Sybase SQL Anywhere. Refer to your RDBMS’s documentation regarding the use of SOUNDEX. SELECT EMP_NO, EMP_FNAME, EMP_LNAME FROM EMPLOYEE WHERE SOUNDEX('SMYTHE') = SOUNDEX(EMP_LNAME) The result of the query is: EMP_NO -----110 118 103 EMP_FNAME --------JOHN STEVEN CAROL EMP_LNAME --------SMITH SMITH SMITH

SUBSTR, LEFT, And RIGHT
The functions SUBSTR, LEFT, and RIGHT each return a portion of a string from character data types. You use SUBSTR to return a specific number of characters beginning anywhere within the string: SELECT SUBSTR (EMP_FNAME, 1, 4), SUBSTR (LOC_NAME, 3, 8), SUBSTR (DEPT_NAME, 2)… In this example, the first SUBSTR is returning 4 characters of EMP_FNAME beginning with position 1. The second SUBSTR is returning 8 characters from LOC_NAME beginning with position 3. In the last SUBSTR, the number of characters to return has been omitted. In this case, SQL simply returns all remaining characters (in this case, beginning with position 2 of DEPT_NAME). The LEFT and RIGHT functions are similar in operation. LEFT returns the

leftmost n characters from a column, whereas RIGHT returns the rightmost n characters from a column: SELECT LEFT (EMP_LNAME, 1), RIGHT (EMP_LNAME, 4) Not all databases support the RIGHT and LEFT functions, but if not, the SUBSTR function is adequate.

Concatenation
Some databases provide specific functions to concatenate two strings. For instance, Oracle offers the CONCAT function, which accepts two arguments (two strings to be concatenated). Almost all RDBMSs support the concatenation operator, which is simply two pipe characters (the pipe character is usually above the backslash on your keyboard and looks like one vertical dash on top of another). The advantage of the concatenation operator is that you can concatenate as many strings as needed without resorting to nesting functions. The first example in the next function shows the concatenation operator in use.

TRIM, RTRIM, And LTRIM
The similar functions TRIM, RTRIM, and LTRIM take a string and trim any leading or trailing spaces from it. RTRIM is useful when you want to concatenate two fixed-length columns: SELECT RTRIM(EMP_FNAME) || ' ' || EMP_LNAME AS 'NAME' FROM EMPLOYEE WHERE EMP_NO < 110 ORDER BY EMP_LNAME The result is: NAME ---------------FRANK BENSON EUNICE BROWN ANN CALLAHAN BRIAN JOHNSON CAROL SMITH GENEVIEVE WESLEY Without trimming the rightmost characters from the first name, you get a result that looks like the following: NAME ---------------------FRANK BENSON EUNICE BROWN ANN CALLAHAN BRIAN JOHNSON CAROL SMITH

GENEVIEVE

WESLEY

The LTRIM function removes leading spaces from a string if it has any. Some RDBMSs also provide a TRIM function, which combines the functionality of LTRIM and RTRIM.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

ROUND And TRUNCATE
ROUND and TRUNCATE are similar but not identical. The first rounds a number to the specified position, whereas the latter merely truncates a number at a specified position. Observe the difference when working on EMP_SALARY/52 in the following example: SELECT EMP_NO AS 'EMP NO', EMP_SALARY/52 AS 'WEEKLY', ROUND(EMP_SALARY/52, 3) AS 'ROUNDED', TRUNCATE (EMP_SALARY/52,3) AS 'TRUNCATED' FROM EMPLOYEE WHERE EMP_NO BETWEEN 110 AND 115 ORDER BY EMP_NO The result follows. Note that the third and last rows have differences between the rounded and the truncated numbers. Any result ending in a 5 or above is rounded up. EMP NO WEEKLY ------ --------110 645.10212 111 1876.92308 112 696.18808 113 1395.44885 114 900.75038 115 678.30673 ROUNDED -------645.102 1876.923 696.188 1395.449 900.750 678.307 TRUNCATED --------645.102 1876.923 696.188 1395.448 900.750 678.306

MOD Or REMAINDER
The MOD function returns the remainder after dividing two numbers. MOD

(15, 2) returns 1 because 15 divided by 2 equals 7 with a remainder of 1. This can be a useful function when performing a lot of math at the database server. Some RDBMSs call this function REMAINDER, but the purpose and syntax is otherwise identical.

POWER
Similar to the Visual Basic exponentiation operator, POWER raises a number to the power of another number: POWER (2, 4) returns 16 (2 raised to the 4th power). Not all RDBMSs support this function. You can use fractional exponents to return the root of a number. POWER (8, 3) returns two, which is the third root of eight.

Date Functions
The different RDBMSs have a wide range in what functions they provide to support operations on dates. For instance, Oracle has a DAYS_AFTER function, which returns the date that falls n days after the supplied date: SELECT DAYS_AFTER ('02-FEB-99', 365) This function returns '02-Feb-00'. Sybase uses DAYS: SELECT DAYS ('02-FEB-99', 365) Check your RDBMS documentation for specific date functions.

GROUP BY
The SQL GROUP BY clause, which allows you to group data, is particularly useful when taking breaks on aggregate functions (such as showing subtotals). When a SELECT has a column with an aggregate function, you must GROUP BY all columns where there is no aggregate function. The following query performs a sum on EMP_SALARY and also selects EMP_DEPT_NO and EMP_GENDER. Therefore, you must group by the latter two columns, as shown in this example: SELECT EMP_DEPT_NO, EMP_GENDER, SUM(EMP_SALARY) FROM EMPLOYEE GROUP BY EMP_DEPT_NO, EMP_GENDER ORDER BY EMP_DEPT_NO, EMP_GENDER It sometimes confuses developers that they need to GROUP BY all non-aggregate function columns, but the example shows it only makes sense that if you are summing salary information, you need to take breaks (show subtotals) on all the other columns. The result follows: EMP_DEPT_NO ----------100 100 EMP_GENDER ---------F M SUM(EMP_SALARY) --------------328802.50 147374.18

200 200 300 300 400 400

F M F M F M

147115.66 311425.32 525056.55 77568.70 75759.54 248138.61

You can use multiple aggregate functions as shown in the following example, which compares minimum, maximum, and average salaries for males and females in each department and shows a count for each: SELECT EMP_DEPT_NO AS 'DEPT', EMP_GENDER AS 'SEX', COUNT(*) AS 'COUNT', MIN(EMP_SALARY) AS 'MIN SALARY', MAX(EMP_SALARY) AS 'MAX SALARY', ROUND(AVG(EMP_SALARY),2) AS 'AVG SALARY' FROM EMPLOYEE GROUP BY EMP_DEPT_NO, EMP_GENDER ORDER BY EMP_DEPT_NO, EMP_GENDER The result of the query follows: DEPT ---100 100 200 200 300 300 400 400 SEX --F M F M F M F M COUNT ----5 3 3 6 8 1 2 4 MIN SALARY ---------34591.90 21313.97 27487.44 33545.31 18331.50 77568.70 33543.13 36201.78 MAX SALARY ---------127500.00 72563.34 72789.20 77492.47 104800.00 77568.70 42216.41 73643.82 AVG SALARY ---------65760.50 49124.73 49038.55 51904.22 65632.07 77568.70 37879.77 62034.65

As shown in the result, females in this company tend to make less than their male counterparts in similar jobs except in Department 100. (That was entirely unintentional. All data in the supplied sample tables was generated randomly.) You can also GROUP BY columns that do not appear in the SELECT list. This option mostly has applications in subselects, which I discuss later in this chapter. Sometimes, however, this option is useful even without subselects but in conjunction with the HAVING clause, which I discuss next.

HAVING
The last clause in the SQL SELECT statement is the HAVING clause. The HAVING clause allows you to restrict groups of data based on the results of aggregate functions and thus is usually associated with the GROUP BY clause. You will most likely read in some SQL texts that HAVING must be used in conjunction with the GROUP BY clause, but that is not actually true. The following statement, although not very meaningful, executes just fine:

SELECT SUM(EMP_SALARY) FROM EMPLOYEE HAVING SUM(EMP_SALARY) > 1 The example says to select the sum of all salaries if that sum is greater than one. When used in conjunction with GROUP BY, the HAVING clause is more meaningful. I refine the earlier example of salaries by department and gender to show only those departments and gender combinations where the average salary is less than $50,000: SELECT EMP_DEPT_NO AS 'DEPT', EMP_GENDER AS 'SEX', COUNT(*) AS 'COUNT', MIN(EMP_SALARY) AS 'MIN SALARY', MAX(EMP_SALARY) AS 'MAX SALARY', ROUND(AVG(EMP_SALARY),2) AS 'AVG SALARY' FROM EMPLOYEE GROUP BY EMP_DEPT_NO, EMP_GENDER HAVING AVG(EMP_SALARY) < 50000 ORDER BY EMP_DEPT_NO, EMP_GENDER The new report follows: DEPT ---100 200 400 SEX --M F F COUNT ----3 3 2 MIN SALARY ---------21313.97 27487.44 33543.13 MAX SALARY ---------72563.34 72789.20 42216.41 AVG SALARY ---------49124.73 49038.55 37879.77

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Sometimes it is useful to combine the GROUP BY and HAVING clauses even where the aggregate function does not appear in the SELECT list: SELECT EMP_DEPT_NO FROM EMPLOYEE GROUP BY EMP_DEPT_NO HAVING MIN(EMP_SALARY) < 25000 This query returns two rows (Departments 100 and 300) where the minimum salary is less than $25,000. You can also use HAVING in conjunction with a GROUP BY column that does not appear in the SELECT list, as you will see in the next section.

Subqueries
A subquery can be considered a way to join the result of two queries. Suppose you want to find all employees who work in a department whose average salary is greater than $55,000. You really need to first know what departments have an average salary greater than $55,000: SELECT EMP_DEPT_NO, AVG(EMP_SALARY) FROM EMPLOYEE GROUP BY EMP_DEPT_NO As shown in the following result, you need to list those employees in Departments 100 and 300: EMP_DEPT_NO ----------100 200 EMP_SALARY ---------59522.08 50948.99

08 72563.70 53496. is to ask both questions at once. EMP_DEPT_NO. 300) The trick.95 If I want to know which employee in each department has the highest salary. EMP_FNAME.78 18331.00 35271. EMP_DEPT_NO.97 74586.90 61597.56 21313.02 You can now run a second query: SELECT EMP_NO.000 and produces the following result set: EMP_NO -----101 105 113 117 119 121 123 125 127 129 131 133 135 103 107 111 115 EMP_DEPT_NO ----------100 100 100 100 300 100 300 100 300 100 300 100 300 300 300 300 300 EMP_FNAME --------ANN EUNICE MICHAEL ROSE URSULA WINIFRED ALAN CHARLES EUGENE GEORGE JOAN MAUREEN PATRICIA CAROL GENEVIEVE KATHRYN OLIVERA EMP_LNAME --------CALLAHAN BROWN ANDERSON DANIELS SMITHSONIAN VANCE LAWRENCE GERRFON FITZ DE NORVA WILLIAMS PODANSKI NORTON SMITH WESLEY AMES MAHARAMBA EMP_SALARY ---------127500.50 97600. I need to use what is called a correlated subquery.87 58120.00 37712.34 67572. EMP_SALARY FROM EMPLOYEE WHERE EMP_DEPT_NO IN (100.00 61426. is correlated to the WHERE clause of the outer query.300 400 66958. To do this. you need a subquery: SELECT EMP_NO. EMP_SALARY FROM EMPLOYEE WHERE EMP_DEPT_NO IN (SELECT EMP_DEPT_NO FROM EMPLOYEE GROUP BY EMP_DEPT_NO HAVING AVG(EMP_SALARY) > 55000) The subquery returns a list of those departments where the department’s average salary is greater than 55.10 77568.15 74748. . specified in the WHERE clause. EMP_FNAME. EMP_LNAME.61 34591.42 104800.36 53983. EMP_LNAME. however. A correlated subquery is one where a search condition in the inner query.

) Using the technique I suggest. However. which then executes like any other query. Although I generally recommend moving as much of the processing to the database server as possible. (Database-caching techniques and so on could actually improve this number tremendously. your VB program would dynamically construct another query. Assume you are running this correlated subquery in an organization with 10. correlated subqueries are often better handled partially within your Visual Basic program.Subqueries And Database Performance A subquery does not significantly diminish performance because the inner query (the subquery) is performed only once. but expect to go to lunch. It returns its result set to the outer query. the query would run in less than a minute (much less than a minute if the database is properly tuned). In this case. when you run a correlated subquery. Correlated subqueries can have a devastating impact on performance. so you should use them only when absolutely necessary. you can rephrase the query to yield better performance. EMP_FNAME. MAX(SALARY) FROM EMPLOYEE GROUP BY EMP_DEPT_NO Then.000 employees and 50 departments. EMP_SALARY FROM EMPLOYEE EMP WHERE EMP_SALARY IN (SELECT MAX(EMP_SALARY) FROM EMPLOYEE WHERE EMP_DEPT_NO = EMP. passing the department numbers and salaries as part of the WHERE clause. The correlated subquery might actually run for more than 10 hours before it completes the work. As each row is returned by the database. Imagine that your company has 10.000 times. assume that the inner query takes three seconds to run and that a SELECT of employees matching a specific department and salary condition takes one second to run. For example. For instance. The following query finds the person making the highest salary in each department: SELECT EMP_DEPT_NO.EMP_DEPT_NO GROUP BY EMP_DEPT_NO) . you can run the inner query from your VB application and have the database return just four rows with department number and salary: SELECT EMP_DEPT_NO. the inner query then runs 10. the database checks whether the employee returned in the outer row has a salary matching the row returned by the inner query. the inner query runs once for each occurrence of the outer query. and then to the unemployment office. dinner. the inner query runs. the outer query runs first. EMP_LNAME.000 employees. Further. Often. returning every row in the EMPLOYEE table. in the next example where I search for which employee makes the highest salary in each department. you might be able to rewrite it so that the outer query returns the most exclusive result set (the least number of rows). If you are forced into writing a correlated subquery.

00 77492. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. EMP. Read EarthWeb's privacy statement. allowing the match of EMP_DEPT_NO from the outer query to the same column from the inner query.82 The WHERE clause in the outer query creates a correlated variable.ORDER BY EMP_DEPT_NO The output of the query looks like the following: EMP_DEPT_NO ----------100 200 300 400 EMP_FNAME --------ANN DAVID URSULA PAUL EMP_LNAME --------CALLAHAN MADISON SMITHSONIAN JAMESSON EMP_SALARY ---------127500. All rights reserved. .47 104800.00 73643. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

EMP_NO = EMP_NO AND EMP_SALARY < 30000 ) ORDER BY EMP_DEPT_NO The result is: EMP_DEPT_NO ----------100 200 300 You have a variety of other ways to join the results of an inner query to an outer query. and you can nest the queries as deeply as necessary. You can run a query and test whether the results of the inner query exist in the outer query. Two keywords that you will find in most databases are ANY and ALL. you can code the query as follows: .000 and show the number of those employees.To access the contents. click the chapter and section titles. The ANY keyword allows you to compare a column from the outer query to any of the values returned by the inner query. Suppose you want to find all departments that have one or more employees making less than $25. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- You use the EXISTS keyword in subqueries to test for the existence of occurrences in an outer query. Assuming you want to know all the male employees who have a female manager. The following example selects EMP_DEPT_NO from EMPLOYEE and then restricts the results to those rows where the department number is also returned by the inner query: SELECT EMP_DEPT_NO FROM EMPLOYEE EMP WHERE EXISTS (SELECT EMP_DEPT_NO FROM EMPLOYEE WHERE EMP.

I highly urge you to create a backup of the database so that you can restore it to its original condition. The following statement adds a new row to the DEPARTMENT table. it undoes all the changes made during the current transaction. So that your results remain the same as mine.SELECT EMP_NO. In other words. value2. Every transaction ends with either a COMMIT or a ROLLBACK. ROLLBACK puts the database back to where it was. the column list is omitted: INSERT INTO DEPARTMENT . The syntax of the command is: INSERT INTO tablename [(column-list)] VALUES (value1. INSERT It comes as no surprise that the INSERT statement is used to add new records to a table. The column-list lists those columns into which data is to be inserted. Because all columns are used. Alternatively. or UPDATE to undo all of the changes. I show you examples of commands that alter data. sometimes called logical units of work (LUW). DELETE. COMMIT makes permanent all changes to the database in the current transaction. EMP_LNAME FROM EMPLOYEE WHERE EMP_GENDER = 'M' AND EMP_MGR_ID = ANY (SELECT EMP_NO FROM EMPLOYEE WHERE EMP_GENDER = 'F') ORDER BY EMP_NO The results are: EMP_NO -----112 113 116 120 123 125 129 132 EMP_FNAME --------LARRY MICHAEL PAUL VINCENT ALAN CHARLES GEORGE KEVIN EMP_LNAME --------JOHANSSEN ANDERSON JAMESSON LINCOLN LAWRENCE GERRFON DE NORVA KERRIGAN TIP A Few Words About COMMIT And ROLLBACK Chapter 11 delves into the concepts of transactions. the column list is not necessary. … valuen) The tablename is an existing table on which the developer has insert authority. If all columns are used. EMP_FNAME. In the following sections. you can issue a ROLLBACK command after each INSERT.

The syntax is: DELETE FROM tablename [WHERE condition] The tablename is any valid table. If you are inserting a row where a column will be set to NULL. All rights reserved. SQL assumes you are referencing another column. 'NE'. If you use double quotes. . you must specify the NULL keyword: INSERT INTO DEPARTMENT VALUES (500. The following statement deletes all employees whose department is 100: DELETE FROM EMPLOYEE WHERE EMP_DEPT_NO = 100 Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. all rows are deleted. 'New Department') Notice that all character values must be enclosed in single quotes. Copyright © 1996-2000 EarthWeb Inc. NULL) DELETE The DELETE statement removes one or more rows from a table. If you omit the WHERE clause. 'NE'. Read EarthWeb's privacy statement.VALUES (500.

Although the commands (INSERT. click the chapter and section titles.08 UPDATE EMPLOYEE SET EMP_SALARY = EMP_SALARY * 1. 300. although most RDBMSs won’t allow you to update the primary key columns. which is where the average developer will spend the vast majority of his or her time. 300. and UPDATE) are simple enough. the first example gives all employees an 8 percent raise. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- UPDATE The UPDATE command updates one or more rows in a single table and takes the following syntax: UPDATE tablename SET column_name= value [. I . In the following code snippets. 400) Where To Go From Here In this chapter. I discussed SQL Data Manipulation Language. column_name= value…] [WHERE condition] You can update any one or more columns. all rows are updated. The second command then gives all female employees in departments 200. DELETE.1 WHERE EMP_GENDER = 'F' AND EMP_DEPT_NO IN (200.To access the contents. and 400 an additional 10 percent raise (obviously to make up for the inequities noted in the GROUP BY discussion earlier in this chapter): UPDATE EMPLOYEE SET EMP_SALARY = EMP_SALARY * 1. If you leave out the WHERE clause.

sneak a peek at Chapter 11. If not. Otherwise. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. If you haven’t yet read Chapter 2. you can use the ORDER BY clause to do the sorting at the database level. If you will be developing for more than one RDBMS. Otherwise. For instance. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. If you feel comfortable with SQL. each of the major database vendors has its own Web site. If you are developing and Microsoft Jet will be involved. All rights reserved. don’t forget that the Internet provides a wealth of information. particularly with the SELECT statement. Alternatively. If you are using the ODBC API. A point of confusion for any developer is where to perform processing. it is better to let the database perform the work unless doing so would generate more network traffic. where I discuss some of the vagaries of that dialect of SQL and how it differs from ANSI SQL. then read on. . you probably want to find a book that is specific to your database. For advanced topics. Finally. common sense usually dictates the correct answer. you might want to do so. and a search of the knowledge base at Microsoft’s Web site using the terms “database” and “SQL” yields many tricks and tips. you will also want to refer to Appendix C.really only scratched the surface of what can be done with the SELECT statement. you can do a simple SELECT from the database and then sort the result set at the client using Visual Basic. The most obvious example of that is letting the database format numbers (adding thousand and decimal separators and currency symbols). Specifically. read the next chapter (Chapter 4) where I overview data access with Visual Basic. I discuss the other two portions of SQL (DCL and DDL) there. you might want to consult Appendix B. Read EarthWeb's privacy statement. In general. I discuss these issues in future chapters. Although there is no hard and fast rule. you might want to consider books that are not RDBMS-specific. you might want to consult one of the many books on the subject. That is probably best left to Visual Basic to add when it displays the data. Copyright © 1996-2000 EarthWeb Inc.

which provides a one-stop interface to nearly all data sources. and ADO • Overview of VBSQL • Overview of the ODBC API • Considerations in choosing a data model The nature of nearly all business (and most nonbusiness) programs is to access and manipulate data. and performance metrics at least as robust as RDO. The best general guidance I can offer is that you should base your decision on the current and anticipated skill levels of your staff as well as the current size and complexities of your application. this data is nearly (but not always) stored in a database. The correct one to use is often difficult to ascertain. I discuss each of these access methods in turn and attempt to provide some guidance as to when to use each. . click the chapter and section titles. Visual Basic provides a dizzying array of options to access the database. In this chapter. I wish I could say that there is one right solution. but there isn’t. a high degree of compatibility with what you may have already developed using DAO or RDO. In client/server development. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 4 Visual Basic 6 Data Access Key Topics: • Evolution of Data Access with Visual Basic • Overview of flat (sequential) file processing • Overview of DAO.To access the contents. RDO. The good news in all of this is Microsoft’s migration to Active Data Objects (ADO).

DAO saw some improvements in the underlying Jet engine that made it somewhat more practical to attach to ODBC data sources. Although it looks much the same on the outside.0 was immature and placed a lot of restrictions on developers about what data sources they could connect to. the success of Visual Basic as a development tool left Mr. Version 4 of Visual Basic saw the introduction of Remote Data Objects (RDO).0. allowing direct access to ODBC rather than forcing everything through Microsoft Jet. DAO was a beginning but was hardly a panacea for large-scale development efforts and. on the inside. Gates and company scrambling to meet developers’ demands for industrial-strength enterprise development tools. for whatever reason. RDO 2. in fact. which was essentially a bridge for those developers who. At the same time. Version 5 of Visual Basic was really the first release where robust client/server development became a practical reality. and so on. Microsoft Basic Professional. I believe that I might have been the only developer in the world to actually buy a copy.0. VBSQL was added to allow native access to Microsoft SQL Server via DB-Lib (DB-Library). was really only well suited for small-scale projects aimed at ISAM files such as FoxPro or Paradox. Visual Basic For DOS.0 For Windows all had one thing in common—no real method of doing database programming. There was some resentment at the time that the good folks at Microsoft had forsaken the DOS-based development community. Although laudable. and Visual Basic 1.0 came along. Many projects developed in VB3 needed a fair amount of recoding. The explosion in popularity of the Internet left Microsoft scrambling to catch up with the likes of Netscape. Microsoft responded with the release of Visual Basic For DOS. VB4 (and now VB5 and VB6) are very different on the inside. but the code itself still looked like the top-down Basic code of old. Microsoft talked more openly of using . but careful testing of the Remote Data Control (RDC) revealed some serious flaws in its architecture. were not yet ready to make the jump to Windows.0 was released about the time Windows 3. Although technically the ODBC API was always available. Jet itself was further refined to increase performance and to offload some query processing on remote data sources that supported that processing. RDO 1. Plus. became a practical if not particularly scalable data model.0 was a major enhancement over RDO 1. It is worth noting that the Microsoft development team essentially rewrote Visual Basic from the ground up from versions 3 through 5 to support the concept of add-in components. It was the much-ballyhooed successor to the DOS-based QuickBasic. DAO was refined with a new technology: ODBCDirect. It behaved much like VB for Windows with features such as event-driven programming and Windows-like controls.Visual Basic Data Access Trends Visual Basic 1. Visual Basic 3 was the first real attempt to give Visual Basic real-world database development tools when Microsoft added Data Access Objects (DAO) version 1. objects. which permitted the bypassing of the Jet engine. QuickBasic. which removed much of the overhead involved in DAO.

Wizards that once generated DAO. During VB5’s development. I discuss each of these data models with a brief overview and some examples. The days of ADO have arrived. and scalable data model upon which to develop. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. In the pages that follow. low-overhead OLE DB engine. Copyright © 1996-2000 EarthWeb Inc. he or she will again see something that looks basically familiar. Microsoft discussed the new Active Data Object model. but for others. it will be evolving for some time to come). Read EarthWeb's privacy statement. in fact. it will be worth the effort to convert existing projects to ADO. the unmistakable trend is toward Active Data Objects. . is similar enough that most VB developers will have little problem adjusting. Although this book discusses all of the data models. In the chapters that follow this one. and most VB developers therefore really did not understand that using the ADO model was another option to development. the technology was not ready by the time VB5 was shipping (and. All rights reserved. ADO combines the best of DAO (access to ISAM databases) and RDO (efficient access to ODBC data sources) with a high-performance. When the purchaser of Visual Basic 6 opens the box. However. and ADO 1. However. although not “backwards compatible” with the RDC or the DAO Data control. there will not be enough payback at this point in time to do so. Best of all.the ODBC API as a means of database development. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.or RDO-based forms don’t even offer those data models as an option.5 is a welcome. For some developers. each model is examined more in depth. The ADO Data control. the client/server developer will quickly lose that illusion when poking around under the covers. robust.

and with good reason. if approached methodically. Ease Of Method Power Stability Learning Use Flat File I/O 2 10 10 6 DAO/Jet Data controls 3 9 9 10 . Learning curve refers to my opinion of how difficult the technology is to master. Still. A score of 10 indicates that the method is very powerful. click the chapter and section titles. VB really offered little in the way of database tools until version 3. in all cases. Even the “simple” interface of DAO and its hierarchy of objects is enough to strike fear in the hearts of the object-purists among us. each of the approaches that I discuss offers amazing flexibility and.1 The varieties of data access methods with Visual Basic 6. As to stability. A score of 10 means that the technology is easy to learn.0. Table 4.0 when DAO and Microsoft Jet were added.To access the contents. Table 4.1 lists the 11 flavors of data access with Visual Basic and my own subjective opinion of relative power. Even the most experienced developers are confused by Visual Basic’s approach to database development. a higher score is better. I am referring to how much programming is required to use the method. Each is scored on a scale of 1 to 10. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- What’s Behind Door Number One? I teach client/server development using Visual Basic (as well as other tools) to students with a wide variety of backgrounds. Finally. A score of 1 means that the method listed is not very stable. learning curve. By power. when I use the expression ease of use. and ease of use. I am referring to the likelihood of your program crashing in the event of a program bug. can be conquered. stability. I judge the robustness of the end product in terms of processing a lot of data efficiently and flexibly. once mastered. A score of 10 indicates that the method is very easy to use.

Table 4. in theory at least.DAO/Jet* DAO/ODBCDirect Data controls DAO/ODBCDirect* RDO Data controls RDO* VBSQL ODBC API ADO Data controls ADO* *Writing 4 5 6 6 7 9 10 9 10 7 8 7 9 8 7 4 10 9 5 8 5 8 5 5 1 8 5 6 9 5 9 6 4 1 9 7 all code instead of using the Data control. Table 4. of course. The ODBC API method. Method Sequential ISAM Relational Flat File I/O DAO/Jet Data controls DAO/Jet* DAO/ODBCDirect Data controls DAO/ODBCDirect* RDO Data controls RDO* VBSQL Yes Limited Limited No No No No No Limited Yes Yes Limited Limited Limited Limited No No Yes Yes Yes Yes Yes Yes DB-Lib only . be accessible via VBSQL.1 lists 11 separate methods of data access that all overlap at some point or other. Table 4. DAO/ODBCDirect (with or without the Data control) can access almost any relational database for which an ODBC driver is supplied and can access many ISAM formats as long as an ODBC driver has been defined. including those that may be defined at some point in the future. Flat file I/O (using VB’s Open and Get keywords) is.2 The types of databases and which data access methods can access each. ADO is meant to cover the entire spectrum of data sources. DAO/Jet (with or without the Data control) can process some sequential file formats but only to the extent that they are structured.2 shows which types of databases each method can access. flat file I/O may be appropriate for ISAM files. DAO/Jet can also access most major relational databases. Under some circumstances. the roll-your-own approach and offers little to no realistic likelihood of accessing a true. like RDO. RDO is strictly bound to ODBC data sources. Older versions of Sybase SQL Server also support the DB-Lib interface and should. so it can connect to virtually all relational databases and many ISAM files. VBSQL is used with Microsoft SQL Server using DB-Lib. can access any ODBC data source. relational database.

Read EarthWeb's privacy statement. Copyright © 1996-2000 EarthWeb Inc. In the following sections. I discuss each of the 11 database access methods.ODBC API ADO Data controls ADO* *Writing No Yes Yes Limited Yes Yes Yes Yes Yes all code instead of using the Data control. All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

Perhaps you have received a file of records that you need to add to the database. Instead. and then reload it to the database. update it the old-fashioned way. Although using flat file I/O will not be your primary means of processing data. before that). If the file name is omitted. click the chapter and section titles. Flat file I/O is also well suited when you need to process unstructured data. have been around for many years. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Flat File I/O The Visual Basic commands to process flat (nonrelational) files. I outline the basics in this section. so I have not devoted a separate chapter to flat file I/O. it does have a place even in modern client/server applications. . For additional guidance. refer to the Visual Basic documentation. Most Visual Basic developers who are reading this book are already fairly accomplished in the use of the VB language. Opening And Closing Files Visual Basic uses the Open command to open a file regardless of the mode in which the file is accessed. The syntax of the Open command is as follows: Open filename For open_mode [Access access_mode] [lock_mode] _ As [#]file_number [Len=record_length] The filename includes a fully qualified path to the file. One of the down sides of RDBMSs is that there is a good deal of overhead involved in processing. Consider the possibility that you are updating many thousands of records currently stored in a relational database. more commonly called sequential files. I would never encourage this approach where not absolutely necessary because you lose the advantages of the database’s built-in integrity constraints and so on.To access the contents. It may well be advantageous to read the file sequentially and add the records programmatically. Visual Basic attempts to open the file in the current directory. dating back to the days of QuickBasic (and in some cases. I have worked on some applications where it was more efficient to “drop” a table into a sequential file (using an export utility of the database).

The options are Shared. All subsequent operations against the file reference the assigned file number. For example. In Lock Read mode. in Output mode.The five open_mode options are Append. Lock Read. you can move around the file by specifying an absolute byte offset from the beginning of the file or from the current location in the file. all currently opened files are closed. The access_mode determines whether the file can be read to or written from. With files opened randomly. When a file is opened in Binary mode. Use the FreeFile function to return the next available file number: ' Return a file number from 1 to 255 Dim iFile1 As Integer iFile1 = FreeFile ' Return a file number from 256 to 511 Dim iFile2 As Integer iFile2 = FreeFile 1 The pound sign (#) before the file number is optional. The default is ReadWrite. and Lock Read Write. the operating system can use that to locate record number 4 by moving the “file pointer” to byte 301 in the file (assuming the first record begins at byte 1. The default is Random. because that forces the changes to be written to disk. When a file is closed. and it is retained by Visual Basic for backward compatibility with Basic versions that did require it. . use the Close statement followed by the file number to close it. Write. You must assign an unused file_number when opening a file. The record_length argument is used with files opened in Random mode and is ignored if the file is opened in Binary mode. Once you have finished using a file. The first three options are used where a file is to be accessed sequentially (as opposed to randomly). which prevents any other process from opening the file while your program has it open. and so on). and ReadWrite. If you open a file in Shared mode. the file is locked against others reading it. Random. in Lock Write mode. Failure to properly close the file can result in your changes being lost. the file number is disassociated from that file and can be used again for another file. Likewise. the second record at byte 101. The most restrictive (and default) mode is Lock Read Write. and Binary. Use numbers of 255 and below if the file will not be used by other processes. Lock Write. In Append mode. your program is responsible for maintaining the logic necessary to know where in the file a given record is. Conversely. If you do not supply a file number. a runtime error in that program will be generated. If you have opened a file as Lock Write and another program attempts to open it in Output mode (for example). any data that you write is added to the end of the file. This provides the ability to locate a record quickly by simply supplying a record number. Input. The options are Read. any other process has full access to the file. Output. all records in the file are normally a fixed length. especially those opened in Output or Append modes. The number must be in the range of 1 to 511. Use numbers above 255 if the file can be opened by other processes. I discuss Random and Binary modes in a moment. other processes may not write to the file. Of course. The lock_mode option specifies how the file locking is handled in a multiuser environment. any data overwrites the file from the beginning. You should be sure to close all open files. if all records in a file are 100 bytes long.

Listing 4. Input. "$###. Listing 4.log" For Input Read As iFile2 ' Create a user-defined data type for the next file Type EmpRec Emp_No As Integer Emp_Name As String * 30 Salary As Currency End Type ' Create a variable of type EmpRec Dim strEmp As EmpRec ' Open a file randomly using a record length iFile3 = FreeFile Open "c:\employee. strEmp MsgBox strEmp. Notice that a user type EmpRec is created and used as an argument to the Len clause on the Random file.##0. the file will be used to store employee records. 8. read only iFile2 = FreeFile Open "c:\autoexec.00" ' Close the first file Close iFile1 ' Close all other open files Close Previous Table of Contents Next .Salary. ' Variables to store file numbers Dim iFile1 As Integer Dim iFile2 As Integer Dim iFile3 As Integer ' Open a file in Append mode iFile1 = FreeFile Open "c:\program.dat" For Random As iFile3 Len = Len(strEmp) ' Read the record number 8 and display Get #iFile3.1 opens three files (in Append.1 Demonstration of several flat file access techniques.log" For Append Lock Read Write As iFile1 ' Open a file in Input mode.Emp_Name & "'s salary is " & _ Format$(strEmp. and Random modes).

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Read EarthWeb's privacy statement. All rights reserved. Copyright © 1996-2000 EarthWeb Inc.

use an action code of 1: Mode = FileAttr(1. var2…. The file number you assign (or obtain using FreeFile) is not the same as the file handle. myVar2. which is a Long “address” to the file. myVar1. Visual Basic returns one of the following values: • Input—1 • Output—2 . you could use the FileAttr function to determine in what mode a file has been opened and to return the file handle: Handle = FileAttr (1. 1) where the first “1” is the file number you assigned when you opened the file and the second “1” is the action code. including opening and closing the files. it has a handle. In 16-bit Windows. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Reading Files Use the Input # function to read a file opened in Binary or Input modes using the syntax Input # file_number. In this case.dat" For Input As 1 Input #1. Unfortunately. this option is not supported in 32-bit Windows. var1. however. myVar3 Open "c:\myfile. You use this function to read a comma-separated list of variables from a file: ' Read three variables from a file Dim myVar1. 2) where “1” is the file number that you assigned when you opened the file and “2” is an action code telling Visual Basic you want to return the operating system’s file handle.To access the contents. myVar2. myVar3 Close 1 About File Handles The operating system is actually responsible for all file I/O. When a file is opened. You can. click the chapter and section titles. use FileAttr to obtain information about what mode a file was opened in.

whereas with Binary mode. also used with files opened in Binary or Input modes. carriage returns. sBuffer ' List1 is an existing ListBox control List1. Consistency is not Microsoft’s middle name.1 Example of using Line Input to populate a ListBox control with the contents of a file. If the record number or byte offset is omitted. reading begins at the next record or byte in the file. The following statement reads a file that was previously opened randomly: ' Read the 55th record into the strEmpRec variable Get #iFile3. you supply a byte offset. including commas.• Random—4 • Append—8 • Binary—32 The Input function (without the pound sign). The following code reads a file and displays each line in a ListBox control. up to (but not including) the character-return and line-feed characters.AddItem sBuffer Loop Close 1 Figure 4. 1) Line Input is used to read an entire line of text. as shown in the following example: Dim sBuffer As String Open "c:\autoexec. and line feeds. differs from the Input # function in that it reads in a fixed number of characters from the file. You use the Get function to read a file opened in Random or Binary mode. The result is shown in Figure 4. Notice that Line Input requires the use of the pound sign in front of the file number. 55.bat" For Input As 1 ' Read 100 characters sBuffer = Input (100. you supply a record number.1: Dim sBuffer As String ' Open the file Open "c:\autoexec. With Random mode. strEmpRec The following statement reads the next 512 bytes into a variable from a file previously opened as Binary: .bat" For Input As 1 Do While Not EOF(1) Line Input #1.

. 30 ' Read the next record Get #iFile3. the file pointer is 55. . which writes a record (in Random mode) or the value of a variable (in Binary mode): Put #iFile3. 1998#”). A carriage-return and line-feed sequence is written after each Write # operation. sBuffer Navigating Files The current position in the file is said to be the file pointer. strEmpRec ' Display the current record number (31) MsgBox Seek (#iFile3) The Loc is the counterpart to Seek. Write # places quotes around strings and commas after each variable. strEmpRec Writing To Files Put has additional functionality that varies somewhat depending on whether the file was opened for Binary or Random. Print # is useful for writing formatted reports to a disk file for printing later. if the current record is number 55 in the file.Dim sBuffer As String * 512 Get #iFile3. Print # writes formatted data to a sequential file. The Write # statement writes data to a file in the same format that it is read with the Input # function. See the Visual Basic help file for additional information. a carriage-return and line-feed sequence is written after each Print # operation unless the last character is a semicolon or comma. Dates are surrounded by pound signs (“#December 25. you can write the contents of an array to disk. returning the location of the last read or write. The Seek statement moves the file pointer (that is. Therefore. The counterpart to Get is Put. For instance. However. it sets the location in the file for the next read or write).. whereas the Seek function returns the current file pointer: ' Move to the 30th record Seek #iFile3. Previous Table of Contents Next . Boolean data is written as #TRUE# or #FALSE#. See the Visual Basic help file for more details on some of the ways that you can use Print #. Strings do not have quotes and variables are not separated by commas.

Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . All rights reserved. Read EarthWeb's privacy statement.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

) The example for Line Input earlier in this chapter (see Figure 4. click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Other File Support Functions The EOF and LOF functions are very useful when you perform flat file access. read a 4K chunk sBuffer = Space$(4096) End If .1) used EOF. Dim sBuffer As String Dim lSize As Long Dim lRemaining As Long Dim iBufSize As String ' Open the file in binary mode Open "c:\windows\modem. Listing 4.2 provides an example of using LOF to perform a buffered read of a file. EOF returns a Boolean.To access the contents. LOF returns the length of an open file.log" For Binary As 1 ' Determine the length of the file lSize = LOF(1) ' Initialize the value of lRemaining lRemaining = lSize ' Loop through the file ' Pad the input buffer If lRemaining < 4096 Then ' If less than 4K characters remaining sBuffer = Space$(lRemaining) Else ' Otherwise.2 Using LOF and a method to process very large files with buffered reads. indicating whether the end of the file has been reached. (You can use FileLen to determine the length of an unopened file. Listing 4.

The actual implementation of DAO is shown in Figure 4. it loses in performance. The current version is DAO 4. I go into much more depth on these subjects in Chapter 5.1. Also.1 pulled all of the records from a table in a back-end database such as Oracle and then performed the query locally. It offers the ability to manipulate ISAM databases as well as relational databases. what Jet gains in flexibility (because it can interface to virtually any data source).2 The relationship of DAO to the application and to the database. such as FileDateTime (which returns the date and time when a file was last modified).. which then interacts with the ODBC Driver Manager. Capabilities With the exception of ADO. Jet 1. he or she can use the same code to interact with both FoxPro and Oracle.0. Jet leaves a large footprint in memory. .2. sBuffer lRemaining = lRemaining . I discuss the capabilities of DAO and its object models.Len(sBuffer) If lRemaining < 1 Then Exit Do Loop The Visual Basic help file contains information on other functions that may be useful. it occupies more than a megabyte of RAM. The seasoned (or should I say grizzled?) Visual Basic developer who wrote database applications with Visual Basic 3 used Jet version 1. Jet’s performance enhancements are derived in large part by allowing the back-end database to do what it does best: process queries. In this section. Data Access Objects Data Access Objects (DAO) is the original model of the relational data access models for Visual Basic. DAO is the most flexible of the data access methods available to the VB developer. shielding the developer from many complexities and creating a layer where the developer can use a common code base to interact with multiple back ends. In other words. The original implementation of DAO was with Microsoft Jet.' Read the data Get #1. Unfortunately. This was a primitive implementation. GetAttr (which returns the attributes of a file such as Hidden or System). The ODBC Driver Manager handles all low-level interactions with the database itself. if the developer uses a reasonable amount of planning. and I review the DAO hierarchy. Figure 4. Jet is robust in its capabilities but is a “thick” layer between your applications and the data. slowing down all database access. and SetAttr (which sets file attributes).

ODBCDirect was added to DAO with version 5 of Visual Basic. It is not as flexible as Jet in that it can only communicate with defined ODBC data sources. However, it bypasses Jet and communicates with RDO. It also offers some functionality improvements because it can access ODBC features not available when going through Jet. Because ODBCDirect is a thin layer leaving a minimal footprint in memory, it offers performance nearly as good as RDO itself. ODBCDirect essentially maps DAO functionality to RDO functionality. The RDO layer interacts with the ODBC Manager. In Chapter 5, I discuss the DAO object hierarchy in depth.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Using DAO
DAO has a fairly complex object hierarchy. (See Figures 5.1 and 5.2 in Chapter 5 for a graphical representation of this hierarchy). In this model, all data access objects exist in the context of a single DBEngine object.

Are DAO And Jet Dead?
One might easily jump to the conclusion that Jet, and by extension, DAO, are both in the coffin, if not actually buried. Microsoft SQL Server 7 is making a bold attempt to cover all portions of the enterprise from clustered servers down to a desktop database. (You can purchase a Windows 95 version of SQL Server that supports up to five users, although it is primarily aimed at the desktop user.) If you are predicting the demise of Jet in particular based upon Microsoft’s announcements regarding SQL Server 7, don’t bet a lot of money. Although SQL Server 7 may, and probably will, eventually be a viable desktop platform, it is far from that today. Although Microsoft may have refined the product some by the time you read this, it appears that the memory requirements are about two to three times greater for SQL Server 7 than for Jet. SQL Server 7 for the desktop is about a 200MB install, and although Microsoft specifies a Pentium platform, my recommendation is to not run it with anything less than a 200MHz CPU with at least 64MB of RAM. This is not your typical desktop configuration. Microsoft has continued to refine and improve Jet. Even more, informal testing shows that not only is Jet 4.0 faster than its 3.0 counterpart, but it is also much faster than SQL Server 7 on a typical desktop PC. That is not to say that a future release of SQL Server will not change that discrepancy, but that day has not arrived yet. If anything is going to knock Jet off its desktop throne, it is ADO and OLE DB (which is part and parcel of SQL Server 7, by the way), which I discuss

later in this chapter. For new relational database development efforts, I see no compelling reason to use DAO over ADO because OLE DB seems to be a much more robust technology than Jet and especially because Microsoft is clearly going to concentrate its development bucks there. For the typical desktop development effort, I see no reason not to use Jet against ISAM-type databases, including MS Access. If more robustness is needed (such as logging), then I recommend a product such as Personal Oracle or Sybase SQL Anywhere, both of which offer good performance with modest resource requirements. Otherwise, Jet is a proven data engine technology for file-oriented databases. The DBEngine object contains the Workspaces collection, which consists of individual Workspace objects. Each Workspace object describes a current “session” with the database and includes the Databases collection. Each Database object includes several collections including QueryDefs and RecordSets. A QueryDef object describes an SQL select. Each RecordSet object is an active result set from the database. The actual implementation of the object hierarchy varies a little based on whether ODBCDirect is used. Because the objects themselves vary, there is also some variation in methods and events available to the VB developer. For instance, ODBCDirect offers the Cancel method to cancel a pending asynchronous query. DAO gives the developer the opportunity to use data-aware controls, greatly simplifying the task of DAO-based development. This opportunity comes at the expense of some flexibility in design but can turn 200 lines of code into 20 or fewer. For instance, the Data control automatically connects to the database, builds a RecordSet object, handles the chore of scrolling through the RecordSet, and performs all updates behind the scenes. Without the Data control, the VB developer has to code all of this functionality. Likewise, by having a Data control, the user can bind other data-aware controls such as the TextBox and the ListBox to individual columns in the Data control’s RecordSet object. Without the Data control, the developer has to manually populate each TextBox (or other control) as the user scrolls through a RecordSet. Figure 4.3 shows a form module that uses the Data control and several TextBox controls to display records from the Employee table in the Access version of the sample database provided with this book.

Figure 4.3 The Employee application created using the Data control and very little coding.
TIP Using The Sample Code Because the application in Figure 4.3 uses an Access database without ODBC, the path to the database file is “hard-coded” in the Database name of the Data control. In addition, because the database is on your CD-ROM, the database cannot be updated. To run this code on your own, copy the project file and the form file to your hard drive along with the Access database.

Open the project and change the Database property of the Data control to reflect the new path.

I actually wrote only one line of code (shown below) to display the record number. The rest of the code was all generated as a result of drawing controls on the form and setting their properties as needed. Private Sub Data1_Reposition() Data1.Caption = "Record " & _ Str(Data1.Recordset.AbsolutePosition + 1) & _ " of " & Str(Data1.Recordset.RecordCount) End Sub In Chapter 5, I expand on the use of DAO, adding functionality such as error handling, data validation, and so on using the sample data provided with this book (see Appendix A). I will also walk through the process of coding a DAO-based application without using the Data control, as a means of illustrating the DAO object hierarchy and to provide additional flexibility to the application.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Remote Data Objects
Introduced with Visual Basic version 4.0, Remote Data Objects (RDO) introduced a major performance boost for client/server applications. You can use RDO with any backend database defined as an ODBC data source name (DSN) that supports the SQLNumParams ODBC function (see sidebar). Although some of the names of properties and objects have changed, RDO has a lot in common with DAO. Most VB developers should have little problem converting existing code to use RDO and even less problem grasping its usage. Where RDO will work (when working with any ODBC-defined database), it makes little sense to continue using DAO. However, before converting an application from DAO to RDO, you might want to carefully consider the benefits of converting to ADO instead. I discuss ADO later in this chapter.

RDO Capabilities
RDO puts a smaller layer between your application and the data than does DAO. This is shown in Figure 4.4. RDO basically places a thin wrapper around the ODBC API, allowing the developer most of the benefits of the ODBC API with few drawbacks. The chief advantages of RDO are: • No need for a local query processor (Jet); query processing is done remotely. • Smaller memory footprint. • Event-driven asynchronous queries.

Figure 4.4 The Remote Data Objects model. The Visual Basic 5.0 implementation of RDO (RDO 2.0) and the Remote Data control (RDC) was a significant improvement over the original Visual Basic 4.0 implementation (RDO 1.0). For example, under Visual Basic 4.0, you had to continuously poll for the completion of a database operation. RDO 6.0, introduced with Visual Basic 6 (don’t ask me what happened to versions 3, 4, and 5), is another improvement. Unlike DAO, in which data access is usually performed synchronously (meaning that the program has to wait for the result set to be returned before processing can continue), RDO permits asynchronous queries of the database. For example, if you set the RDC’s Options property to rdAsyncEnable, the ResultSet is populated as a background task. When the query is complete (and the ResultSet completely populated), the QueryCompleted event is fired, providing an event-driven means for your application to know that the query has completed. The RDC’s functionality is similar to the Data control, which most VB developers have used. Likewise, the Remote Data Object hierarchy is similar (though simplified) to the Data Access Object hierarchy.

Using RDO
Figure 4.5 shows an application created using the RDC that is almost identical to the DAO example in Figure 4.3. The snippet places the current row number into the Caption property of the RDC. The properties of the RDC are almost identical to those in the Data control. A few differences mostly reflect the SQL row orientation of the Remote Data control versus the file record orientation of the Data control. For instance, DAO’s RecordSet property is equivalent to RDO’s ResultSet property. DAO’s RecordCount property is equivalent to RDO’s RowCount property as shown in the following code snippet: Private Sub MSRDC1_Reposition() MSRDC1.Caption = "Record " & _ Str(MSRDC1.Resultset.AbsolutePosition) & _ " of " & Str(MSRDC1.Resultset.RowCount)

End Sub

Figure 4.5 The Employee application coded using the Remote Data control.

RDO And ODBC Compliance
The ODBC (Open Database Connectivity) standard is broken into three levels. Base level or Core level defines a minimal set of functionality that an ODBC driver must support. Level 1 defines additional functionality, whereas Level 2 defines yet another layer of more advanced functionality. A Level 2-compliant ODBC driver essentially supports the full set of SQL functionality defined by ANSI SQL. Appendix C lists the different functions required by each level along with the syntax for calling each from Visual Basic. RDO in Visual Basic 4 required a Level 2-compliant implementation, whereas RDO in VB5 and now VB6 has relaxed this requirement considerably to require only the SQLNumParams function.

VBSQL
VBSQL is a library for accessing Microsoft SQL Server via DB-Lib. Because Microsoft is heading away from DB-Lib and more toward an ODBC- and OLE DB-oriented access method to SQL Server, the use of VBSQL is not recommended except for existing projects already utilizing it.

VBSQL Capabilities
VBSQL is written to provide an interface to Microsoft SQL Server only. Specifically, any functionality exposed by SQL Server’s DB-Lib is implemented by VBSQL. Connections tend to be cursor-oriented, and you are pretty much on your own to manually populate controls with information retrieved from the database (as opposed to binding controls to a data source). On the other hand, you have an unusual degree of control (relative to other Visual Basic data models) over the efficiency of your database processing. For instance, you can set the packet size for communicating between the database server and your application using the SQLSetPacket function with the SQLOpen function. (Note that you can determine the current packet size using SQLGetPacket but that once a connection is established, the packet size cannot be changed.) The packet size can be any size up to 64K and, if not specified, is determined by the current SQL Server default. If the default is set to 4,092 bytes but your application is mostly updating and retrieving single records, the large packet size slows down your application. On the other hand, if your application is processing a lot of data, a larger packet size is preferable to reduce the number of disk reads.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Using VBSQL
To use VBSQL, you need to visit the Microsoft Web site and download the VBSQL ActiveX control (look for VBSQL.OCX). The version I used in this book was a prerelease version, but a shipping version should be available by the time you read this. VBSQL requires the use of the VBSQL control, which is really more like a DLL than a Visual Basic control. You need to add to your project the VBSQL.BAS module, which is also available from the Microsoft Web site and included on the CD-ROM (be sure to check the Web site for a more recent release). The VBSQL.BAS module has a number of function calls defined, such as establishing a connection with the database. The declarations all reference the OCX file as shown in this code snippet: Declare Function SqlNextRow Lib "VBSQL.OCX" _ (ByVal SqlConn As Long) As Long Figure 4.6 shows a VBSQL application running in front of the VB6 development environment. A quick look at the two open code windows reveals that this coding, although not terrifically difficult, is tedious. Because Microsoft is in the process of eliminating the DB-Lib interface, and because the Active Data Object model is available, you have little reason to use VBSQL code. Because of the length of the code, and the fact that I don’t recommend VBSQL when clearly better data access models are available, the entire 20 or so pages of code is not printed in the book.

Figure 4.6 The Employee application using VBSQL. To open a connection to the database, a sample code snippet might look like the

following: Dim lSQLConn As Long Dim lRtn As Long Dim sRtn As String ' Share with other procedures Private myLogIn As Long ' Initialize sRtn = SQLInit () ' Establish login record myLogIn = SQLLogIn () ' Set login parameters lRtn = SQLSetLUser (myLogIn, "Coriolis") lRtn = SQLSetLPwd (myLogIn, "Coriolis") ' Workstation lRtn = SQLSetLHost (myLogIn, "W243A") ' Can add other parameters lRtn = SQLSetLApp (myLogIn, "Coriolis VBSQL Sample App") ' Establish connection lSQLConn = SQLOpen (myLogIn, "Home")

The ODBC API
Perhaps the ugliest approach to data access using Visual Basic, at least in terms of complexity of code, is via the ODBC API. It is not for the faint of heart. At one time, particularly before the release of Visual Basic 5 (with its credible RDO version 2), the developer seeking to expose the robustness of the underlying ODBC had little choice but to drop down to the ODBC API. As with VBSQL, I see little reason to do so now, especially with ADO obviating more complex data models. Even still, just as the Visual Basic developer still finds legitimate need to drop to the Windows API for specialized functions, the VB client/server developer may well need to drop to the ODBC API at some point.

ODBC API Capabilities
The capabilities provided by the ODBC API are a function of both the backend database and the driver with which the ODBC manager communicates. For instance, I have used the Microsoft ODBC driver to access Oracle databases. I have also used Oracle’s own driver. As odd as it may sound, Microsoft’s is more functional under many circumstances. For instance, in a DAO environment, if you set the Data control’s Options property to vbSQLPassThru (in order to tell Jet to let the back-end database handle the query), the Oracle ODBC driver can only process the tables as read-only. Appendix C documents some of the technical details of the API.

Using The ODBC API
Listing 4.3 provides a brief look at some of the steps involved in connecting to and manipulating an ODBC data source. In this case, I have coded the steps necessary to list the available ODBC data source names (DSNs). The application is shown in Figure 4.7.

Listing 4.3 Code from frmDSNList. Private Sub cmdClose_Click() End End Sub Private Sub cmdGetSources_Click() Dim iRtn As Integer, iDSNLen As Integer, iDescLen As Integer Dim hEnv As Long Dim sDSN As String * 32, sDesc As String * 128 ' Clear the list box List1.Clear ' Allocate env handle iRtn = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, _ hEnv) ' Set environmental variables iRtn = SQLSetEnvAttr(hEnv, SQL_ATTR_ODBC_VERSION, _ SQL_OV_ODBC3, SQL_IS_INTEGER) ' Get first data source iRtn = SQLDataSources(hEnv, SQL_FETCH_FIRST, sDSN, _ Len(sDSN), iDSNLen, sDesc, Len(sDesc), iDescLen) Do While iRtn = SQL_SUCCESS ' Add DSN to listbox List1.AddItem Left$(sDSN, iDSNLen) ' See if there are any more iRtn = SQLDataSources(hEnv, SQL_FETCH_NEXT, sDSN, _ Len(sDSN), iDSNLen, sDesc, Len(sDesc), iDescLen) Loop ' Free the handle iRtn = SQLFreeHandle(SQL_HANDLE_ENV, hEnv) ' Report the results Text1.Text = Str$(List1.ListCount) End Sub

Figure 4.7 Listing the ODBC data sources using the ODBC API.

The project, included on the CD-ROM, consists of a general code module (ODBC.BAS) containing API declarations and constants and a form module, frmDSNList.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

Active Data Objects—The Future Is Now
One giant leap for Microsoft is an even bigger leap for us mere mortals who don’t happen to own a lot of Microsoft stock. For those of us who have careers based at least in part on the use of Visual Basic to develop client/server applications (indeed, any database applications), Active Data Objects and its concomitant technologies (such as OLE DB) are a huge leap forward. Not only will most applications show anything from a modest to a drastic performance improvement, but also the implementation of the data model is simpler than either DAO or RDO. Perhaps even better, Microsoft has adopted a common data model to be used across all its development products, making objects as applicable in Visual C++ as they are in Visual Basic.

ADO Capabilities
ADO is actually an interface to OLE DB, which provides a common access point for both relational and nonrelational data structures as well as such disparate and nonstructured data sources as text, graphics, and email. In fact, with OLE DB, you can relate two entirely separate data sources to each other as long as there is an OLE DB driver written for each data source. For example, you could read an Employee table in an Oracle, Access, or DB2 database. You could then join the Emp_Email column in that table to the Pop3_Account_Name “column” in a Microsoft Outlook data source (when and if an OLE DB driver is written to access Outlook). Whereas ADO provides a high-level interface to the data, OLE DB is a low-level interface. By and large, VB developers can ignore the dirty business of bits and bytes in which OLE DB deals and concentrate on the streamlined interface provided by ADO. ADO encapsulates OLE DB functionality (and, by extension, data) and exposes it as objects. When dealing with OLE DB data sources, OLE DB is considered the data provider, whereas your application (and the Active Data Objects) is considered

the data consumer.

Using ADO And OLE DB
With ADO and OLE DB come new ways to look at and process data. Data-aware controls such as the TextBox have a new property, DataMember. You can still treat data sources in the “old way”: Assign to the DataSource property the name of an existing Data control (or Remote Data control or Active Data control) and assign to the DataField property a column that corresponds to one of the columns returned by the Data control. This is perfectly acceptable. However, the new data environment allows you to encapsulate the logic in a relational database’s structure. Consider the sample database included with this book. An Orders table is related to the LineItem table. In turn, the Item table is related to the LineItem table. The relationship is shown graphically in Figure 4.8.

Figure 4.8 The relationship between the Orders, LineItem, and Item tables. Now, consider a selection from the Orders table along with all related rows in the LineItem and Item tables. This data hierarchy can be modeled using hierarchical cursors in the new Data Environment Designer. You can build a DataEnvironment object that encapsulates this data hierarchy. Then, you can assign to a data-aware control’s DataSource property a DataEnvironment object instead of assigning a Data control to it. When you assign a DataEnvironment object to a data-aware control, the DataEnvironment object has certain properties that are exposed as data members. In Figure 4.9, I am creating a DataEnvironment object using the Data Environment Designer. After creating a DataEnvironment object, you can insert stored procedures previously created on the database, or you can add new Connection objects or Command objects. A Connection object represents a connection to the database, including various parameters such as user ID, password, and timeout. A Command object can be a table similar to a DAO RecordSource type, an existing SQL view or stored procedure, or an SQL statement. In Figure 4.9, I am creating an SQL statement type Command.

Figure 4.9 Creating the deADO-Example DataEnvironment object using the Data Environment Designer.

When placing a data-aware control on a form, you can set its DataSource property to any valid DataEnvironment object. Because the DataEnvironment object is a project-level object (as opposed to a form-level object, such as a Data control), any control on any form may access it. Once you have selected a DataEnvironment object as a control’s DataSource property, you can use the control’s DataMember to select from any of the Command objects of the DataEnvironment object. In Figure 4.10, I have just selected my deADOExample DataEnvironment object as the DataSource for the DataGrid control. I then selected the Ord_Rpt Command object as the DataMember property.

Figure 4.10 Using a DataEnvironment object as a DataSource of a data-bound control. Of course, none of this is to say that you can’t use the ADO Active Data control (ADC) as you would the DAO Data control or the RDO Remote Data control. In Figure 4.11, I do exactly that. The figure shows two forms open inside an MDIForm. The top form shows the form that was designed in Figure 4.10, displaying rows of data from the three tables represented in Figure 4.8. The bottom form shows the same Employee Maintenance form that I created using DAO and RDO earlier in this chapter.

Figure 4.11 An MDIForm housing two other forms using a DataGrid control bound to a DataEnvironment object and some TextBox controls bound to an ADO Data control.

Previous Table of Contents Next

Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

To access the contents, click the chapter and section titles.

Visual Basic 6 Client/Server Programming Gold Book
Go!
Keyword
Brief Full Advanced Search Search Tips

(Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98

Search this book:
Go!

Previous Table of Contents Next

-----------

The code for this application is included on the CD-ROM. To build it yourself, first create an MDI form named mdiADOExamples. Add two forms named frmADOEmployee and frmADOReport. Set both of their MDIChild properties to True. On the MDI form, add a File menu with three items: Report, Employee, and Exit. For the mnuFile-Report_Click event, code the following: frmADOReport.Show In the mnuFileEmployee_Click event, code the following: frmADOEmployee.Show On frmADOEmployee, add an ActiveData control. To do so, select Microsoft Active Data Objects from the Projects|Components menu to put the control on the toolbox. Set its properties as follows: Align=2 ‘Align Bottom; Connect=“DSN=Coriolis VB Example”; DataSource Name=“Coriolis VB Example”; RecordSource=“employee”. Next, create an array of five textbox controls named txtEmpDat. The DataSource property for each should be Adodoc1. Set their DataField properties to: emp_no; emp_fname; emp_lname; emp_hire_date; and emp_salary. You can set the DataFormat properties for the date and salary fields as you see fit. Add label controls as shown in Figure 4.11 and then add the following code: Private Sub Adodoc1_MoveComplete (ByVal adReason As _ EventReasonEnum, ByVal pError As Error, adStatus _ As EventStatusEnum, ByVal pRecordSet As RecordSet) Adodc1.Caption = "Record " & _ Str$(Adodc1.RecordSet.AbsolutePosition) & " of " & _

11. For instance. (Note that the figure itself is somewhat simplified.adCmdText”.ord_no ORDER BY orders. CursorLocation=“3 .line_price. Errors is actually a collection of Error objects. item.adUseStatic”.adLockReadOnly”. line_item_no. add a DataGrid control named DataGrid1. ord_cust_no. orders WHERE item. item_desc. WrapText=True.Str$(Adodc1. and it must be specified as the “parent” of the Command object. orders.) Figure 4. The ConnectionSource property should be set to “ Provider=MSDASQL. The DataField property for the columns should be set to: ord_no.12 The ADO data model. CursorType=“3 . For the Ord_Rpt Command object. AllowSizing=True.line_no.Orders”.1. and LockType=“1 . such as those shown in Figure 4. DataSource=“deADOExample”. User ID=coriolis. Contrast that to the Data control or the Remote Data control. line_no. as shown in Figure 4. line_item. CommandText=“SELECT orders. For Orders_Only. DataSource=Coriolis VB Example”. Its SourceOfData property should be set to “3 . and LockType=“1 .RecordSet. line_item. line_item. orders. line_item. deADOExample has one Connection named CorVBExample.ord_cust_no.12. The Connection object has two Command objects named Orders_Only and Ord_Rpt. Password=coriolis.deUseOLEDBConnect-String”. line_price.line_total FROM item. CursorLocation=“3 . Set the DataGrid control’s properties as follows: AllowArrows=True.ord_no. in any module). though they are not used in the sample application. The Caption and Format properties should be set appropriately. which must be re-created for each form that will use them. set properties as follows: CommandType=“1 .ord_no.item_no=line_item. DataMember=“Ord_Rpt”. Cursor-Type= “3 adUseStatic”.line_qty. line_total. line_qty. line_item. you will see other Command objects as well.line_no”.line_item_no.adLockReadOnly”. One of the most impressive and useful aspects of ADO and VB6 is that you can create a DataEnvironment object and use it on multiple forms (indeed. The Connection object must first exist. line_item. Caption=“Order Details”.ord_date.line_ord_no=orders.adUseClient”. This change is a leap . set the CommandType property to “2 . Set other properties as follows: CommandText=“Coriolis.RecordCount) End Sub On frmADOReport.AdCmdTable”. This brings us to the simplified (and non-hierarchical) object model of ADO relative to DAO and RDO.item_desc. line_item.adUseClient”. In the CD-ROM code listing. Each Command object exists in the context of a Connection object. ord_date.line_item_no AND line_item.

Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. .forward in the continued evolution of Visual Basic into an object-oriented development tool. All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

When a form includes a Data control. some TextBox controls bound to the Data control. For now. A general procedure is one that you create yourself as either a Sub or a Function. the reader. are an object purist. code. the Data control is essentially an instance of a class—in other words. An object’s behavior describes what the object can do. (An event procedure is a predefined procedure that reacts to an event such as Command1_Click (). For example. the Data control is part of the Form object’s definition. They are the definition of the form. When you design a form in the development environment. set properties. you paste the control onto a form and define properties that enable the control to communicate with the database. and add event procedures and general procedures. state. understand that a class is a definition of an object. but it also includes the simple variables that you use within your procedures.To access the contents. an object. If you. and behavior. It is not an object until instantiated. A form can make itself visible by invoking its Show method. An object’s data may include information from a database. An object’s state is really those things that describe the object. Assume that you have developed a form named frmCustomer. The process of loading it into memory is called instantiation—literally. which consists of a Data control. you attach controls. In Chapter 5. and so on of that form represent the class. All objects have data.) All the properties. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Data Access As An Object—Introducing Data-Aware Classes To use a Data control in your application. creating an instance of. The form does not become an object until it is loaded into memory. I discuss creating data access objects and some of the theory behind it. you might want to . a form has a Caption. click the chapter and section titles. and perhaps a menu and some buttons. When the application is running. It comprises a part of the class.

However. The same is true for any objects that I create to interact with the database or to enforce data validation rules.” the behavior “bears it young live” is overridden to “lays eggs. Under inheritance. Class modules are . I should not have to re-create that Data control on every form object that handles employee data. I should not have to code that in every place that accesses employee records. A real-world example of that might be a motorcycle class. such as a form. if I create a Data control that connects to the database and retrieves employee records. VB does not do that. Under inheritance. You can certainly copy the form. Likewise. In other words. if you alter the attributes of the original frmCustomer class.” “walks on four legs. any changes to an ancestor class are propagated to its descendants. Each Form object is created from scratch.” and “scratches my furniture. You cannot create a Form object and then inherit its properties to create a new Form object. we can create a class (which. the changes are not reflected in the new form. and then take all that work and reuse it on other forms. you can inherit from more than one object to create an entirely new object. it is overridden. If you stop and consider that the Data control and the TextBox control are both classes. I should be able to change the background color of frmCustomer and then see that change reflected in all forms that inherit from frmCustomer. I should be able to create an object that encapsulates that rule and reuse that object wherever I manipulate employee data. We inherit from the “engine” class and the “bicycle” class to create a new class. but cat has additional attributes such as “nocturnal. we might say that cat and person are both inherited from the class called mammal. save it under a new name. we can combine them with the Form class to create an entirely new class. For instance. Unfortunately.” Unfortunately. perhaps frmCustomer. if I have a rule that says an employee’s date of hire must be greater than his or her date of birth.” If an attribute is inappropriate for a new class. for the class “platypus. this falls apart when you seek to reuse the customized behaviors of the Data control or indeed the frmCustomer class. The purpose of inheritance is ultimately something called reuse. motorcycle. I should be able to create a class. becomes an object) by inheriting the attributes of another class and then adding (or customizing) to create an entirely new class. Visual Basic 4 introduced class modules.suspend belief as you read the next statement: In a sense. when instantiated. With multiple inheritance. in the real world.” The classes cat and person both inherit those attributes. For instance. frmCustomer is the result of a loose form of multiple inheritance. and then modify it for specific functionality (perhaps a new Form object that will also display address information). The mammal class has certain attributes such as “has fur” and “bears its young live. which uses attributes of both of the other classes. Visual Basic does not truly support inheritance. Pure object-oriented programming (OOP) languages such as Smalltalk and C++ support an extension to inheritance called multiple inheritance. For instance. The closest that Visual Basic comes to inheritance is a form of reuse known as delegation.

methods. the class module is more like an object in that you can define properties. Copyright © 1996-2000 EarthWeb Inc. and events. the interface of a class is those properties and methods (Subs and Functions) that you define as Public. Whereas the interface of a Data control is those properties and methods that another object can access.similar to general modules in that you can write procedures that can then be accessed from anywhere in a VB project. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement. . All rights reserved. However.

Visual Basic actually does a better job of multiple inheritance than it does with simple inheritance. The inability to reuse objects in Visual Basic is partly solved with class modules. the class is not restricted to using ADO as a data model. It is analogous to having a Data control operating independently of any form. because the new class can combine the attributes of several classes.) A class that is a data source interacts with the database and provides data for other data consumer objects. but this did not (and still does not) provide a total solution. it now has the DataBindingBehavior and DataSourceBehavior properties. but you lose the simplicity of the Data control and you also lose the ability to bind controls to a data source. Further. You can even bind data-aware classes to each other. When you add a class module to your Visual Basic 6 project. Although this is a simplified explanation. it is essentially what is meant by the term delegation. (Note that although the theory of data-aware class behavior is based on the premise of OLE DB. By setting the class module’s DataSourceBehavior property to vbDataSource. The new class can then take advantage of the interface of the other classes. Besides the Name property. Ironically. This is true for data-aware class modules as well. Visual Basic 6 answers that problem with data-aware classes. you can manually code database access from within a class module. the class can act as a data . it now has three “built-in” properties instead of one. click the chapter and section titles. When considering client/server development and its data-centric philosophy. Visual Basic now includes the BindingCollection object.To access the contents. A principal of ADO and OLE DB is that an object can be a data source or a data consumer. This newfound capability of the class module goes hand-in-hand with ADO and OLE DB. Sure. the problem is especially acute with data handling. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- You can also combine existing classes into a new class. which can be used to bind classes as data sources to data-aware controls.

Some of the most welcome changes in VB. reusable data and business components to drive the enterprise-level client/server development effort. The instantiated object can even be deployed at an application server. even though they may not add a lot of additional functionality. In Chapter 10. Figure 4. select References). Figure 4. However. including other classes. I discuss this in Chapter 1. The BindingCollection object consists of bindings between a data source and one or more consumers of that data. A class can also be a data consumer. the term client/server refers to an application involving two or more discrete processes acting in cooperation.13. the class is bound to an entire row or record from the external data source. Other Approaches To Database Development With Visual Basic From a strictly technical point of view.14. as a practical matter. By setting the DataBinding-Behavior to vbSimpleBound. but also can be shared from project to project. Using data-aware classes allows the encapsulation of data manipulation and business logic into a reusable object that can not only be accessed from any Form object. fulfilling the goal of DCOM as I began discussing in Chapter 1. the BindingCollection object has the usual property (Count) and methods (Add.14 You use the Object Browser to explore the various attributes of the new BindingCollection object. Clear.source to other objects. have been the new wizards and templates.13 To use the BindingCollection object. you add a reference to it as you would with other ActiveX libraries (on the Project menu. I expand on these concepts to create practical. To access the Binding-Collection object. first add it as a reference. the class is bound to a single column or field from your external database. as shown in Figure 4. As shown in Figure 4. the term has come to imply a number of other approaches to development to include the graphical user interface (which therefore also implies event-driven development) and rapid application development techniques. . If you set the property to vbBound-Complex. and Remove) of collections as well as several that are specific to data manipulation (such as DataSource and DataMember).

The resulting object or application is not complete—you still need to customize it (such as adding data validation edits). fill-in-the-blank objects (such as the About form) that you can modify to your purpose rather than create from scratch.Templates are prebuilt. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Although the templates and wizards will not fulfill all of your needs. you gain a lot in terms of the reliability of the code and the consistency of the user interface. . I highly urge their use. where they do help. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. because the wizard creates the same “shell” over and over again. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. All rights reserved. but the wizard eliminates a lot of the repetitive drudgery. Further. The wizards walk you through a series of dialogs to create an object or an entire application.

Figure 4. you are prompted with a choice of a number of templates and wizards. (In Chapters 13 and 14. Of most interest are the VB Application Wizard and the Data Project. VB6 offers the option for a Data control approach. whereas the other form is a . VB6 wizards also offer more presentation styles than were offered in VB5. The chart reflects average salaries by department and gender. click the chapter and section titles. an all-code approach. or a data-aware control approach. Whereas VB5 restricted you to the Data or Remote Data controls. as shown in Figure 4.15.16. The Application Wizard generates a remarkably complete application with a simple fill-in-the-blanks approach.16 Configuring the Application Wizard on how to access the database and how to present the resulting data. Unlike the wizard bundled with VB5.17 shows an application generated by the VB Application Wizard. Figure 4.To access the contents.15 Visual Basic will help automate the creation of a variety of different project types. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Visual Basic Application Wizard When you create a new project in Visual Basic. we delve into IIS and DHTML applications.) Figure 4. the wizard in VB6 offers a lot of flexibility in how you complete the data access portion. as shown in Figure 4.

Listing 4. These actions (and others) call the private adoPrimaryRS_WillChange-Record procedure. the data entry forms are not attractive. The chart form is probably even less attractive. a reflection of my being “artistically challenged. Admittedly. the validation code you write here can be used over and over.Recordset) 'This is where you put validation code 'This event gets called when the following actions occur Dim bCancel As Boolean Select Case adReason Case adRsnAddNew Case adRsnClose Case adRsnDelete Case adRsnFirstChange Case adRsnMove Case adRsnRequery Case adRsnResynch Case adRsnUndoAddNew Case adRsnUndoDelete Case adRsnUndoUpdate Case adRsnUpdate End Select . Listing 4. Because any form (or other module) can create an instance of the class. Private Sub adoPrimaryRS_WillChangeRecord _ (ByVal adReason As ADODB.4 Code generated by the Wizard.17 An application created by the VB Application Wizard.4 shows where VB inserted comments prompting me to add validation code. That’s encapsulation and reuse. ByVal pRecordset As ADODB.master/detail presentation of employees by department. Because the class is the data provider. _ ByVal cRecords As Long. it us up to you to move the controls on the forms to suit your needs.” An examination of the code generated will show that VB adds comments where you should add your own customized code. adStatus As _ ADODB. but that problem should be rectified by the time you receive your copy of VB6. Figure 4. it provides public methods to move through displayed records and to edit those records.EventReasonEnum.EventStatusEnum. it did not even place a chart on the form). A look at this reveals something very similar to the validation code placeholder that VB5 added in its Data and Remote Data control wizards. The form with the chart was not built correctly by the Application Wizard (in fact.

see no reason to craft an application from scratch when the VB Application Wizard will do so much of the work for you. you can ask VB to develop a data form. I expanded the four tables that I was interested in: Customer. From the Add-Ins menu. you can see that the Visual Data Manager opens a window with all of the tables in the database. the Application Wizard is not that much help when you are adding functionality to an existing project. Time invested? Ten minutes. run the query to test it. I invoked the Visual Data Manager and then opened the Coriolis VB Example data source. Figure 4. and Item. On the other hand. The Data Form Wizard runs from the Add-Ins menu and offers essentially the same functionality on a form-by-form basis as the Application Wizard. I used the Data Form Wizard to create a customer maintenance form. LineItem. for one. queries. Orders. This is where the Data Form Wizard can be a big help. From there.19.18.18 A customized customer maintenance form originally generated by the Data Form Wizard. In Figure 4. tops. I then spent a few minutes customizing it to make it more usable and then added a line to the MDIForm’s menu to open it.If bCancel Then adStatus = adStatusCancel End Sub The Visual Basic Data Form Wizard I. I then used the Query Builder utility (from the Utility menu) and generated the query shown in the SQL Statement window. and so on. In Figure 4. Previous Table of Contents Next . and so forth. The Visual Data Manager Visual Basic provides the Visual Data Manager utility to help you with many of the more mundane tasks involved in building a database-centric client/server application.19 The Visual Data Manager lets you invoke a suite of tools to generate forms. Figure 4.

Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement. . All rights reserved.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

I tend to lean toward whatever seems to have the most flexibility.To access the contents. Likewise. If you are developing desktop applications. you are already using DAO with Jet. if you are developing beyond the desktop. and if you are happy with it. and especially if you are using ODBCDirect. Again. If RDO is not giving you what you need. the introduction of ADO changes all that. the conversion does not have to occur all . ADO is slick. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- So…What Flavor Tastes Best? I am partial to chocolate fudge. However. which makes me wonder how long VBSQL will be viable. Some might even say it is sexy. if you are using RDO and it suits your needs for the time being. My advice for the time being is to do any new development using ADO but leave your existing code base alone. but when it comes to data access. Again. that meant using three different and mutually exclusive choices. I see no reason to move to ADO either. Microsoft is moving away from DB-Lib. Such is not the case with VBSQL. In a word. things get a little murkier because you have a large code base to change. However. but I try not to get that involved. Although you definitely have a rather large code base to convert. click the chapter and section titles. Chapter 8 should be of assistance in that regard. In the past. In my mind. the most power. Chapter 9 will help you do that. you will probably want to convert to ADO. You can always convert piece-by-piece (or form-by-form) as the need arises. then you probably should consider moving to ADO. Can you say “rewrite”? I am concerned that you might be trapped technologically and urge you to consider migrating to the ADO model. and is easiest to use. that should not preclude you from doing any additional development with ADO. If you are using the ODBC API in your present applications. there is no compelling reason not to continue doing so.

Finally. In particular. Further. For more information on DAO-based development. some additional information on ODBC can be found in Appendix C. if you are proceeding with RDO or you need to enhance current RDO-based applications. either online (www. you will want to move on to Chapter 6. com or to access the Microsoft Developers Network (MSDN). Likewise. I think ADO is the way to go.microsoft. it is Microsoft’s chosen technology of the future and will only get better. and it is a more robust platform than in the past. For simple desktop development. Copyright © 1996-2000 EarthWeb Inc. robust database client/server applications. you face the question of the model to choose for new development. Readers looking for even more information are urged to check out the Microsoft Web site at www.com/msdn/) or on CD-ROM (with a yearly subscription fee). move on to Chapter 5. All readers should look at Chapter 7. which explores ADO and OLE DB in depth. Read EarthWeb's privacy statement. Where To Go From Here I have taken some time in this chapter to explore in a reasonable amount of depth each of the data access options available to the VB developer. you might want to develop a test form using both methodologies to see whether you prefer ADO. . which covers the subject in depth. reasonably high-powered path to the database.at once.microsoft. DAO is still viable. but you should move carefully to ensure that you don’t break what ain’t broke already. However. All rights reserved. How long Microsoft will continue to improve Jet remains to be seen. Because there is little need to do large-scale development with the ODBC API. but it also encompasses a wide array of data sources. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I have not included a separate chapter for that. I spent a little more time with the newer technologies. Not only does it provide a solid. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Chapter 9 uses that technology to build scalable. but it is certainly not disappearing in the short term. Still. For all other development efforts. Jet keeps showing improvements.

To access the contents. click the chapter and section titles. Which one is appropriate is largely a function of what it is you are doing. ODBC workspaces • Using DAO objects • Using the Data control • Transaction and concurrency management • Database replication with Jet As discussed in Chapter 4. Throughout the chapter. DAO is probably the simplest option. I guide you through an in-depth examination of DAO. with which most VB developers are familiar. I also overview Visual Basic’s built-in Data control. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Part II Visual Basic 6 Database Programming Chapter 5 Data Access Objects (DAO) Key Topics: • The DAO hierarchy • Jet vs. Visual Basic provides a dizzying array of options to access the database. beginning with the object hierarchy and then discussing the Data control. In this chapter. At the end of the chapter. . I provide numerous code examples (which you can also find on the enclosed CD-ROM). although even it can get complicated if you get away from using data-aware controls.

Microsoft Jet in particular provided an interface to which the developer could write and access almost any relational database. It is not a full implementation of . create a Database object for Jet data models or create a Connection object to use ODBCDirect. or other comparable access models. ISAM files. Microsoft SQL Server. DAO had two object models (or workspaces): Microsoft Jet and ODBCDirect. Access databases). such as Btrieve or dBASE. allowing the same program to run against data sources ranging from Microsoft SQL Server to FoxPro using Jet SQL. and ODBC data sources (not to be confused with access via ODBCDirect. after creating the Workspace object. let alone 100 or 200 users. Even better. If you further restrict your development efforts to the Data control and data-bound controls. With the Data control. but you probably will not be happy if you scale it to 20 or 30 users. Even more. With Visual Basic 6. we’ll start with simple examples that do just that a little later in this chapter. the interface was for the most part transparent to the developer. Although the Jet engine has improved in performance. to be a one-stop solution. Jet handles much of the dirty work for you. building a database application is almost a no-brainer. Jet offered developers a reliable if not particularly robust method to access and update databases. Jet implements a lowest common denominator approach to SQL. To use ODBCDirect with the Data control. (See Appendix B for a discussion of the elements of Jet SQL. Jet’s footprint (the amount of space it takes) in memory is much larger than that of ODBCDirect. which bypasses Jet). say. the current release of DAO is 4. Even more. Whether Microsoft will continue to develop the Jet engine (given the introduction of Active Data Objects [ADO]) is a point of conjecture.0 of Visual Basic was the first with realistic tools to access and manipulate a database. such as the textbox. Microsoft Jet Version 3. Although the performance of the Jet engine has improved with subsequent releases. The clear advantage to developers is the simplicity of the programs. as well as a wide array of Indexed Sequential Access Method (ISAM) file formats.) Microsoft generally mentions three types of Jet-accessible back-end databases: Microsoft databases (MDB files—in other words. A Microsoft database is a hybrid between an ISAM database (which tends to have its “tables” in separate files whereas MS databases have all of their tables in one file) and a true relational database management system with its own database engine. set the DefaultType property to 1 (useODBC). RDO. Indeed. Writing a client/server application for 4 or 5 users using Jet is fine. When using DAO objects in code.DAO Object Models With Visual Basic 5. DAO defaults to using Jet. see Chapters 2 and 3 for a discussion of the elements of ANSI SQL. it is not nearly as efficient as a native or ODBC interface to. it is still hardly a barn-burner.

Jet relies on DAO to perform transaction management. For instance. Still. the developer. All rights reserved. You can cancel a running operation using the Cancel method and determine the status of an operation via the StillExecuting property. OpenRecordSet. and Snapshot. and MoveLast methods all allow asynchronous operations via the dbRunAsync option. including asynchronous executions. As with a stored procedure. (The RecordSet object needs to provide this service. Execute. Keyset. Dynaset. An ODBC Connection object can have one of four types of RecordSet objects: Dynamic. You cannot use stored queries. which limits you.Structured Query Language. Instead. . Forward-Only. Read EarthWeb's privacy statement. and Static. The OpenConnection. ODBCDirect creates a small layer that actually communicates with RDO (making it questionable whether a project using ODBC should even consider DAO). but you can save precompiled queries as QueryDef objects. Jet is bypassed. common SQL statements such as FETCH NEXT and FETCH PRIOR are not supported. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Forward-Only. These objects are analogous to the ODBC cursor types of Dynamic. Likewise. there is a large DAO code base in existence.) ODBCDirect When you use ODBCDirect. you can input or output (or both) parameters on a stored query by adding Parameter objects to the QueryDef. to a core set of statements. and ODBCDirect offers DAO applications almost the same performance as RDO. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. It also offers most of the same benefits. Jet relies on the application to scroll through a result set already loaded into memory. Jet itself does not directly support COMMIT and ROLLBACK.

Whether you are using the Data control or creating all of the objects directly in code. However. the principles of DAO development remain the same. click the chapter and section titles. you manipulate those objects using their properties and methods to read data from and write data to the database. ODBC takes care of many of the details that Jet normally needs to take care of. Note that ODBCDirect is a “flattened” model that is intuitively simpler to understand. As a developer. That is why. only the level of how dirty your hands get is different. an entirely code-based solution offers some additional flexibility. and so on.1. for the RDO and ADO models in subsequent chapters.To access the contents. a methodical review reveals that the model merely implements into objects the interface to the database. the hierarchies are also similarly simpler: Each relies on the tools provided by the back-end database to manage such things as users accounts. . I discuss in depth each of the Data Access Objects. indexes. Most developers tend to be intimidated by the complexity of the DAO hierarchy. Put in another way. Although using the Data control greatly simplifies development. whereas Figure 5. The hierarchy of the DAO objects in a Jet workspace is shown in Figure 5. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- An Overview Of DAO Programming In the next section.2 shows the DAO object hierarchy for ODBCDirect workspaces. The Jet workspace data model is more involved because the Jet engine itself needs to do so much more work than the equivalent ODBCDirect data model. Use whichever approach makes sense for you.

a corresponding Database object is also created. methods. and the Connection object also has a QueryDefs collection. When you create a Connection object. If you are also manipulating an Oracle database. This seems like a circular reference. and properties needed to manage that file. the DBEngine object is automatically created (almost any reference to a DAO object causes the DBEngine object to be created). you have a Workspace object that contains all of the objects. The highest level object in each hierarchy is the DBEngine object. but it isn’t. the DBEngine object is automatically created. Both have a RecordSets collection.2 DAO objects in the ODBCDirect workspace model. You will use the Errors collection to monitor database errors as they occur. If you are manipulating a FoxPro file. The same is true in reverse. The Workspaces collection contains all of the Workspace objects in your application. Scroll until you find the Microsoft DAO Library 4. that if you take a code-based approach to DAO development. The two entities belonging to the DBEngine object are the Errors collection and the Workspaces collection. Figure 5. The two objects are similar except that the Connection object has more capabilities than does the Database object.0 and select it. however. In the Jet model. An ODBCDirect Workspace object has a Connections collection and a Databases collection. you will notice that a User object contains a Groups collection and that a Group object contains a Users collection. Likewise. Each Workspace object represents a session with the database. There is only one. When you use the Data control. you need to add a reference to the DAO library: From the menu in Visual Basic. The Jet Workspace object has only the Databases collection (in addition to . you have another Workspace object. With the Data control.Figure 5. you can place code in an Error event to handle database-related errors. In Figure 5. Note. even if you open both a Jet and an ODBCDirect workspace. a Workspace object has a Users collection and a Groups collection representing all of the authorized user and group accounts with permissions to the database represented within the Workspace object. It represents the fact that any group (permissions are often administered at the group level in a database) can have multiple users in it and that any user may be a member of multiple groups. select Project|References.1 DAO objects in the Jet workspace model. any time you create a Workspace object in code.1.

In Figures 5. The Tables Container object also contains information about saved queries. The QueryDef object represents a stored or predefined query (on non-ODBC databases. the Properties collections were omitted for clarity. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. A Jet workspace also has a TableDefs collection. The RecordSet object includes methods to update the database. you will spend most of your time with RecordSet objects. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. and so on. whereas the Parameters collection allows for the maintenance of query parameters that are not known until runtime.1 and 5. . most DAO objects (except Connection and Error) have a Properties collection that contains all properties of the containing object. which represents all of the fields in each record of the record set. handle concurrency issues. The Databases container contains Documents that store information about all saved databases (whereas the Databases collection contains information about all open databases). You also use the RecordSet object to add or delete records. which represents the layout of tables stored on the database. Three Container objects are predefined by DAO. The Containers and Documents collections represent information about objects within the workspace. Similarly. The Relations collection stores relationships between tables (foreign key constraints). Each Field object contains information such as the value of the field and its data type. Finally. The RecordSet retrieves from the database one or more records and makes them available to be maintained. The Fields collection represents all of the fields of the QueryDef object. the Tables and Relations containers contain Document objects that describe information about saved tables and saved relationships. All others are called Jet workspaces even if they connect to an ODBC data source via Jet. Copyright © 1996-2000 EarthWeb Inc. Each Container object contains a Documents collection.2. TIP Types Of Workspaces Note that a workspace connecting directly to an ODBC data source is called an ODBCDirect workspace. The RecordSet object includes a Fields collection. the query is actually stored within the database).the Users and Groups collections). All rights reserved. When working with either ODBCDirect or Jet Workspace objects. The query can be executed directly or it can be the source of the RecordSet object.

click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- DAO Objects The following section examines in detail each of the objects in the DAO hierarchy. Whenever any DAO object is instantiated (such as when connecting to the database with the Data control). or pipe characters (“|”). I have included a lot of code examples. plus or equals symbols. If the ID is not specified. However. If the password is not specified. DBEngine The top-level object is DBEngine—that is to say. DBEngine contains all other DAO collections and objects. Likewise. commas. It is used to store a default user ID in case no ID is supplied at connection time. I do not repeat most of the methods and properties that these object have in common. For instance. The DBEngine object contains three collections: Errors is a collection of Error objects. and Properties is a collection of Property objects. user IDs are not case-sensitive. there are restrictions on valid characters—the ID cannot contain control characters (ASCII values 0 to 31). the DefaultUser property defaults to “Admin”. each object except DBEngine has a Name property by which you reference an object in a collection: RecordSet (“Employee”). brackets. slashes. the value defaults to an empty string. DBEngine is automatically created. asterisks. DBEngine has several properties: • DefaultPassword is a string with a maximum length of 14 characters in Jet workspaces and no limit in ODBCDirect workspaces. • DefaultUser is a string with a maximum length of 20 characters in Jet workspaces and no limit in ODBCDirect workspaces. question marks. especially observing the differences between the Jet and the ODBCDirect workspaces. passwords are case-sensitive. you should review each one carefully. so I do not discuss this separately for each object. It is used to store a default password in case no password is supplied at connection time. Typically.To access the contents. In the interest of space. although that is not always true with an ODBCDirect data source (where it is normally a function of the back-end database or the ODBC driver). . Unlike the DefaultPassword property. Workspaces is a collection of Workspace objects. every object except Connection and Error has a Parameters collection. colons or semicolons. Also. Workspaces is the default collection of the DBEngine object. the ID cannot contain any leading spaces.

Listing 5. later in this chapter.3. Compacting the database rearranges the rows in each table contiguously. resulting in less head movement to read records. illustrates the repairing and compacting of a database. • CompactDatabase (Jet workspace only) takes an existing database and compacts it. as shown in the first example. resulting in loss of performance. password. The options property allows the use of one or more of the settings summarized in Table 5. • Version returns the current version of DAO. You can also use this method to create a copy of an existing database. Use old_db to specify the fully qualified path and name of the database file. Decrypts the database while compacting. If omitted.0 file format. Although this could adversely affect performance. it discards all changes made to the database since the last BeginTrans and ends the current transaction or logical unit of work (LUW). • SystemDB (Jet workspace only) is a string that sets or returns the path of the workgroup information file. although you can use it with any Jet data source. dest_locale is where you specify a new collation (sorting) sequence. A value of 0 specifies no limit. the locale will be the same as for old_db. the database quickly becomes fragmented.• DefaultType sets or returns the default workspace type. if used. You may specify a root key of HKEY_LOCAL_MACHINE (the default) or HKEY_LOCAL_USER in the Registry. later in this chapter. src_locale is the current collation sequence and can normally be omitted. SystemDB remains in effect until the application ends. Listing 5. src_locale Table 5. Once DBEngine is created. To use more than one setting. The default is 20 seconds. illustrates the use of these methods. You must create the setting prior to instantiating the DBEngine object.3. must be set prior to the execution of any other DAO code and remains in effect as long as the DBEngine object is instantiated. Value dbEncrypt dbDecrypt dbVersion10 . although it can follow setting the IniPath property. CommitTrans tells the database to end the current transaction and make permanent all of the changes to the database. The syntax is shown in the next code example. new_db will be the Jet version 1.CompactDatabase old_db. optionally creating a new collating sequence. • IniPath (Jet workspace only) is a string that sets or returns the Registry key where settings such as installable ISAM DLLs for the Jet engine are maintained. dest_locale. The DBEngine object also has a number of methods: • BeginTrans is used to begin a transaction on the database. I highly recommend using this setting. It contains settings that permit or deny users and groups access to secured data objects in the database. _ options.MDW with no path. The workgroup information file is most often used with Microsoft databases (Access files). Use new_db to specify the new path and name of the database file. Databases are much like the hard drive on your computer. add the values.1. Specify dbUseJet to create a Jet workspace or dbUseODBC to create an ODBCDirect workspace. new_db. The IniPath. You will normally use this method when an error occurs during one or more of the updates. Rollback is the opposite of CommitTrans . You may optionally specify the dbFlushOSCacheWrites constant to force the operating system to immediately write all changes to disk. DBEngine. As you add and delete records.1 Valid option settings. • LogInTimeOut is an integer that sets or returns the number of seconds that will elapse before an error occurs when attempting to connect to an ODBC data source (Jet or ODBCDirect workspaces). it also prevents the changes from being lost if the user turns off the PC before the changes are written. Purpose Encrypts the database while compacting. The default is System.

user_name is a string identifying the owner of the workspace. new_db will be the Jet version 3.Append wrkJet ' Close the Workspace objects wrkODBC.1. It also refreshes the records .0 file format. To merely copy an existing database. new_db will be the Jet version 2. locale refers to the collation sequence to be used with the database. The Idle method suspends processing. Note that because the first workspace uses ODBCDirect. If type is omitted. At the end of Listing 5.1). it will govern the default type of workspace. Listing 5. which forces any pending writes to a Microsoft database file to be written to disk.dbVersion11 dbVersion20 dbVersion30 new_db will be the Jet version 1.Append wrkODBC ' Create the Jet Workspace Set wrkJet = CreateWorkspace("Jet Workspace". (For more information. workspace is a reference to an existing Workspace object. and type is either dbUseJet or dbUseODBC. _ "Coriolis". password is a string containing the password for the Workspace object. dbUseODBC) ' Append to collection Workspaces. the Jet engine is not loaded until the second workspace object is created. locale. ' Create object variables Dim wrkJet As Workspace Dim wrkODBC As Workspace ' Create the ODBCDirect Workspace Set wrkODBC = CreateWorkspace("ODBC Workspace".1 creates two Workspace objects and appends them to the Workspaces collection.Close • Idle (Jet workspace only) can be considered similar to the Visual Basic DoEvents function.1 file format. "Coriolis". the two Workspace objects are closed. • CreateDatabase (Jet workspace only) creates and opens a new Microsoft database object. In a high volume. The new Workspace object is not automatically appended to the Workspaces collection nor do you need to do so before using it. use the CompactDatabase method.Close wrkJet.) workspace_name is an object variable by which you will reference the Workspace object. dbUseJet) Workspaces. which automatically removes them from the Workspaces collection. Listing 5. DBEngine might not have the chance to release locks. allowing pending tasks to be completed. and options sets various options for the database. _ "Coriolis".0 file format. the default is to create a Jet workspace. "Coriolis". see “The Workspaces Collection And Workspace Object” later in this chapter. thus potentially enhancing performance. If the DBEngine object’s DefaultType property has been set. db_name is a string containing the name of the new database file. You may optionally specify the dbRefreshCache argument. Set dbs = CreateDatabase = workspace. options) • CreateWorkspace is used to create a new Workspace object. The syntax is shown in the following code segment. such as encryption and file format (see Table 5. Using the Idle method allows these locks to be released. multiuser environment.1 Creating Workspace objects and appending them to Workspaces.CreateDatabase _ (db_name.

. You may also omit both the name and the connect arguments depending on how you set the Options argument. The Options argument determines if and how the ODBC driver will prompt the user for DSN information. Read EarthWeb's privacy statement.2 shows an example of using the OpenConnection method for connecting to an ODBC data source. If supplied. The valid values are listed in Table 5. UID=Coriolis. the Name argument then becomes the Name property of the Connection object. the default Workspace object is used. Copyright © 1996-2000 EarthWeb Inc. it must begin with “ODBC. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. connection is a valid Connection variable by which you reference the Connection object. The Name argument must specify either a valid data source name (DSN)— if not specified in the argument property—or it may contain any string. Options. Listing 5. If you allow the ODBC driver to prompt for missing information.”.that are currently buffered in memory.2. • OpenConnection (ODBCDirect workspace only) is similar to the OpenDatabase method. If omitted. . The syntax of the Connect property is fairly flexible. DSN=Coriolis VB Example. Workspace is a valid existing Workspace object. Set connection = Workspace. If omitted. _ Read_Only. Connect) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All parameters must be delimited by semicolons. The syntax for the method appears in the following code example. If omitted. Either way. the default is False (the Connection object is read-write). The Connect argument is an optional string specifying how to connect to the database.OpenConnection (Name. PWD=Coriolis. A typical connect string is ODBC. and its exact requirements will vary according to the back-end database. the password and user ID are taken from the Password and UserName properties of the Connection object. the DSN chosen by the user will become the Name property. Read_Only specifies whether the Connection object will be read-only. All rights reserved.

dbDriverCompleteRequired + dbRunAsycn. The syntax is shown in the next code segment. existing Workspace object. Use settings from the Connect string. db_name is a qualified path and file name of a Jet database file. False. Prompt only for required missing information. _ "ODBC. May be combined with any of the preceding options. When OpenDatabase is used in an ODBCDirect workspace.To access the contents. but it can also be used in Jet workspaces. If not supplied. dbDriverComplete dbDriverCompleteRequired dbDriverNoPrompt dbDriverPrompt dbRunAsync Listing 5.PWD=Coriolis. it can be a connect string as shown in the OpenConnection method. For a Jet workspace. database is a valid object variable of type Database that is used to reference the Database object. click the chapter and section titles. Connect asynchronously. db_name is a string containing the name of the database. dbUseODBC) ' Open Connection ' object ' Connect asynchronously and prompt only ' for missing information Set conCoriolis = wrkODBC. "Coriolis". Meaning (Default) Prompt only for missing connect information.") • OpenDatabase is similar to OpenConnection.OpenConnection _ ("Coriolis". Dim wrkODBC as Workspace Dim conCoriolis As Connection ' Create ODBCDirect Workspace object Set wrkODBC = CreateWorkspace("Coriolis". If it is .2 The OpenConnection method.DSN=Coriolis VB Example.2 Valid options when connecting to an ODBC data source.UID=Coriolis. Display the ODBC Data Sources dialog box. _ "Coriolis". Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Value Table 5. the current Workspace object is used. a Connection object is automatically created. For ODBCDirect workspaces. workspace is a valid.

options. The method will validate all data and indexes and will delete any data that can’t be repaired. The syntax is shown in the next code example. then db_name can be any string. dbUserCommitSync. an error results. if you select from a table that does not exist. For ODBCDirect workspaces. the ODBC driver will return the first error. (Modify the application as needed to add additional database types. I strongly urge that you instead use the ODBC Administrator applet in the Control Panel. DAO will return an error indicating that the data wasn’t found. If the database is already opened and you attempt to open it in exclusive mode. If another process attempts to open it. parameter is the Registry key to override. • SetOption (Jet workspace only) is a method that allows you to temporarily override Jet engine values stored in the Windows Registry. and dbImplicitCommitSync.OpenDatabase (db_name. begin the string with “ODBC. and finally. Separate each of these parameters with semicolons. the value may be any of those specified in Table 5. A runtime error occurs if the repair fails. For instance. no application may be using it when you attempt to repair it. dbMaxBufferSize. the first object in the collection represents the lowest-level error. • RepairDatabase (Jet workspace only) is used to attempt to repair a corrupt database.left blank and the connect property begins with “ODBC. The connect argument specifies what database type (such as Access or Paradox) to open and may also specify a password and other information. dbLockDelay. dbSharedAsyncDelay. This means that all Error objects in the collection relate to one error condition. _ read_only.3 The Database Repair application included on the CD-ROM. an error results. The CD-ROM contains an application that lets you select a database for repair (see Figure 5.) Figure 5. Typically. dbLockRetry. For a Jet workspace. Set database = workspace. and new_value is the temporary new setting.”. The collection is cleared when a new DAO operation generates an error. connect) • RegisterDatabase enters connection information about the particular database into the Windows Registry. When errors occur during a DAO operation. the database is opened in exclusive mode (no other process may use it). dbMaxLocksPerFile. The requirements vary by database type. the ODBC driver manager will prompt the user for other information. dbExclusiveAsyncDelay. The ODBC driver manager will likely then return an error. The valid parameters are dbPageTimeout. If the connect argument is complete. they are added to the Errors collection. You should check the Count property of the Errors . dbRecycleLVs.2. dbFlushTransactionTimeout. The database must be closed. To access an ODBC data source (regardless of whether you use Jet or ODBCDirect).3) and optionally compact it. See your database documentation for valid values and meanings of these parameters: SetOption parameter. and you should consult the help file for the database to determine exact requirements.”. and you can then reference the Database object using that name. new_value The Errors Collection And Error Object The Errors collection consists of Error objects. If True. Be sure to add a reference to Microsoft DAO objects. the options argument may be either True or False (default).

However. Alternatively. Read EarthWeb's privacy statement. by using the For Each construct. The application code is on the CD-ROM. including records found or errors generated. If using the Data control. VB’s Err object will contain the pertinent error information instead. The Source property is a string containing the programmatic class ID of the object where the error occurred. you can enter an employee number or employee last name and press the retrieve button. Figure 5. Copyright © 1996-2000 EarthWeb Inc. The HelpFile property is a string containing the path and name of the help file to present to the user for more information about the error.4 shows an application that you can copy from the CD-ROM. If you use the New keyword to create a new instance of a DAO object and the operation results in an error. The Error object has properties similar to those of VB’s Err object. The Description property is a string that contains a textual description of the error. Because the collection is zero based. you do not need to take this into account as you would with a For Next loop. there are no Append or Delete methods. All rights reserved. . and the application will dynamically create a SELECT statement and run it. The HelpContext property is a string containing the appropriate help context ID. and the Number property is a Long containing the error number. the error will not be appended to the Errors collection because the object does not get created and thus is not yet part of DAO. Figure 5. The statement generated is displayed in a listbox along with the results. displaying each error description: Dim vError As Variant For Each vError in Errors MsgBox vError. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. you can also place code in the Error event to intercept any errors. The following code iterates through the Errors collection. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the Count property is always one greater than the highest index. For a list of these errors. You can iterate through the Errors collection to examine all Error objects. Because Error objects are automatically appended. consult “Trappable DAO Errors” in the VB help file.4 The sample DAO Errors application allows you to dynamically generate SQL statements and see the results. The application allows you to type an SQL SELECT statement and then run it.collection after database operations to ensure that no errors have taken place.Description Next The Errors collection has only a Refresh method.

To access the contents. Field. Index. Description Big integer (whole number with precision of 20 [unsigned] or 19 [signed]) Binary (fixed-length binary up to 255 characters) Boolean Byte Char (fixed-length string) Currency Date/Time . prop_DDL) Prop_name is a string containing the name by which you will reference the Property object.CreateProperty (prop_name. The following syntax creates a new Property object: Set prop_var = object. _ prop_val. indicates that this is a DDL object.3 Valid Property types. TableDef. Prop_type specifies the data type of the object. QueryDef. There is an example later in this chapter where we discuss the Replicable property of the Database object. prop_type. or Document properties on Jet workspaces only using the Properties collection’s Append method. (The most common use occurs in maintaining partial replicas.3. click the chapter and section titles. if True. Prop_val is the initial value and prop_DDL is a boolean which. as listed in Table 5. as I discuss at various points in this chapter. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Properties Collection And Property Object Every DAO object except Error and Connection has a Properties collection. Type dbBigInt dbBinary dbBoolean dbByte dbChar dbCurrency dbDate Table 5. You can add your own properties to Database.) You must first define its characteristics with the CreateProperty method of the object to which you want to add the Property object.

The application has a Jet workspace and an ODBCDirect workspace.5 This application iterates through all DAO objects and lists the Property objects in each. All operations performed during a session form one transaction scope…. and Value. and it is the collection with which you will interact the most. and True indicates that the property is inherited. The VB documentation defines a session as “…a sequence of operations performed by the Microsoft Jet database engine. The Property objects are displayed in a listbox. Type. A session begins when a user logs on and ends when a user logs off. You will create a Workspace object for each database session that you require. I have included an application on the CD-ROM called DAOHierarchy that iterates through all DAO objects and their Properties collections. but ODBCDirect . The property is a Boolean.2MB) Numeric Single Text (fixed-length string up to 255 characters) Time Time stamp VarBinary (variable-length binary data up to 255 characters) User-defined properties can be inherited in Jet workspaces. Other properties of the Property object include Name. the RecordSource will inherit the new user-defined property. as shown in Figure 5. If you add a user-defined property to a QueryDef object and then create a new RecordSet object using the QueryDef object as a record source. Figure 5.” The definition is fine for Jet workspaces. and prop_val arguments in the CreateProperty method discussed previously.5. You can determine whether a property is inherited by examining the Property object’s Inherited property. prop_type. The Workspaces Collection And Workspace Object Workspaces is the default collection of the DBEngine object.dbDecimal dbDouble dbFloat dbGUID dbInteger dbLong dbLongBinary dbMemo dbNumeric dbSingle dbText dbTime dbTimeStamp dbVarBinary Decimal Double Float GUID (Global Unique Identifier used with RPCs [remote procedure calls]) Integer Long Long binary (OLE object) Memo (variable length up to 1. which correspond to the prop_name.

All rights reserved.workspaces often have multiple transactions within a current session. Groups. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I discussed the creation of a workspace and appending it to the collection under DBEngine earlier in this chapter. You can reference any of the Workspace objects within Workspaces by using its ordinal index or by its name: Workspaces (1) or Workspaces (“Coriolis”). Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Thus. and Refresh methods as well as the Count property. Delete. ODBCDirect workspaces have Connections. . Users. Databases is the default collection. You must append the object to the Workspaces collection using the collection’s Append method.1 and 5. The Workspace object is comprised of different collections itself (refer to Figures 5. the default Workspace object is created as DBEngine. Read EarthWeb's privacy statement. Copyright © 1996-2000 EarthWeb Inc. Jet workspaces have these collections: Databases. You can create a “hidden” workspace by not appending it to the collection. and Properties. depending on whether it is a Jet workspace or an ODBCDirect workspace. The first time you create or refer to a Workspace object. You create a new Workspace object with the CreateWorkspace method of DBEngine.2). and Properties. Databases. I will use the term a little more loosely than does the VB documentation. In both cases. The Workspaces collection has the usual Append.Workspaces (0).

and so on. use clientside cursors. perhaps one is scrolling through the Employee table while another is executing a report on the Customer table.4. forward-only with a rowset size of 1. then both of the RecordSet objects represent distinct transactions. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Workspace object has the following properties: • DefaultCursorDriver (ODBCDirect workspace only) is a long equal to one of the values shown in Table 5. For example. which would be more . cursor libraries. Record set is open read-only. at some length in Chapter 11. cursor stability. then the two RecordSet objects comprise a single transaction and a Rollback or CommitTrans on either RecordSet affects both objects. so you have to open a separate Workspace object in order to have multiple transactions on the same ODBC data source (which is why this is a property of the Workspace object and not the RecordSet object. If set to False.4 Valid cursor driver types.) Type Table 5. assume you have two record sets open on the same ODBC database.To access the contents. Having multiple transactions is not supported by the Workspace object. Description (Default) If the server supports cursors. Otherwise. • IsolateODBCTrans (Jet workspace only) is a Boolean that indicates whether transactions on the same Jet ODBC data source are isolated. Use server-side cursors. dbUseNoCursor Do not use cursors. If IsolateODBCTrans is set to True. (I discuss the concept of cursors. use them. Use client-side cursors. click the chapter and section titles. dbUseDefaultCursor dbUseODBCCursor dbUseServerCursor dbUseClientBatchCursor Use the client batch cursor library. It sets or returns the type of cursor driver used when a new Database or Connection object is created.

Even better would be to consider RDO or ADO. CommitTrans. CommitTrans commits the current transaction. For true back-end RDBMSs. When you use BeginTrans with the Workspace object. Depending on how the record set is opened. Listing 5. Issuing a CommitTrans outside of a nested transaction also flushes the log. We discuss this option in more detail when discussing the Container object later in this chapter. we recommend using the ODBCDirect workspace because it is more efficient than Jet. or Rollback is ignored and no error is generated. you are probably better off using the Jet model. I discussed these three methods under the DBEngine topic earlier in this chapter. for three Workspace objects connected to a given ODBC data source. This value overrides the LogInTimeOut value set at the DBEngine level. the change is automatically committed. • LogInTimeOut (ODBCDirect workspace only) is an integer representing how many seconds will elapse while trying to connect to a database before an error occurs. If the disk runs out of space. there are three separate. a runtime error occurs. Not all ISAM databases (or ODBC drivers) support transactions. In either case. issuing BeginTrans. This can be expensive in terms of server resources. You can nest transactions as shown in the next code example. Rollback rolls back the current transaction. The Workspace object supports several methods: • BeginTrans creates a new transaction. simultaneous connections to the server. all changes are rolled back. an error occurs and data may be lost. the RecordSet object may not support transactions. the Database object’s Transaction property will be False.3 illustrates the use of .intuitive). Even if an inner transaction commits changes to the database. If you change a record outside of a transaction (without first issuing a BeginTrans). you face additional considerations. • Type is an integer that sets or returns the workspace type. A further consequence of setting IsolateODBCTrans to True is that each workspace involving the same ODBC data source creates a distinct connection. the inner transactions are rolled back as well. The valid values are dbUseJet and dbUseODBC. Therefore. You can set the type only when creating the Workspace object. If you use a Jet workspace. a “log file” of transactions applied is maintained in the Temp directory. • UserName is a string representing the owner of the Workspace object. If the database does not support transactions. Issuing a Rollback empties the log. The most common use of the property is in verifying or altering security privileges. A value of 0 indicates there is no limit. you must set it before appending the object to the Workspaces collection. if an outer transaction issues a Rollback. If you issue a CommitTrans or Rollback without first issuing a BeginTrans. If you close a Workspace object after issuing a BeginTrans. If you are going to use this property. With an ISAM database such as Access or Paradox. and I recommend that you consider carefully the wisdom of having more than one operation against the same database occur simultaneously.

allows the user to alter data. . The six textbox controls are an array named txtFields. Connection. The running application is shown in Figure 5. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. The two CommandButton controls are an array named Command1.6. Note that the inner transaction may commit the work but that the outer will roll back all changes anyway.nested transactions in an ODBCDirect workspace. Read EarthWeb's privacy statement. It creates Workspace. displays the results in the textboxes. Copyright © 1996-2000 EarthWeb Inc. and RecordSet objects in code. and then rolls back the changes. All rights reserved.

OpenRecordSet _ ("Select * from Employee".UID=Coriolis.Database=Coriolis.3 The DAO transaction demonstration program.Workspaces.DSN=Coriolis VB Example. Option Explicit Private Sub Command1_Click(Index As Integer) Dim Dim Dim Dim Dim Dim Dim Dim Dim iRtn As Integer sRaise As String sMsg As String sConn As String cSalary As Currency cSaveSal() As Currency wrkEmp As Workspace conCoriolis As Connection rsEmp As RecordSet Select Case Index Case 0 ' Create Workspace Set wrkEmp = CreateWorkspace _ ("emp". dbUseODBC) ' Append to collection DBEngine. .Append wrkEmp ' Create connection object sConn = "ODBC. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Listing 5. "admin". "". dbOpenDynamic) ' Start of outer transaction.OpenConnection _ (""." Set conCoriolis = wrkEmp.To access the contents. ." & _ "PWD=Coriolis. sConn) ' Create RecordSet object Set rsEmp = conCoriolis. . click the chapter and section titles.

00") cSaveSal(rsEmp.MoveFirst ' Set up array to save old salaries ReDim cSaveSal(rsEmp.BeginTrans With rsEmp ' Make sure row count is accurate .##0. vbOKCancel + _ vbQuestion."Commit or Rollback") = vbYes Then wrkEmp. "Display Salary Changes") _ . "###.MoveFirst Do While Not . "0") cSalary = !emp_Salary * (1 + Val(sRaise) / 100) If cSalary <> !emp_Salary Then ' If changed.Rollback End If ' Display changes (if any) . edit the record .MoveNext Loop ' Commit the changes? ' This is the inner transaction!!! If MsgBox("Save all changes?". "Raise".Edit !emp_Salary = cSalary ' Save the change . vbYesNo + _ vbQuestion.AbsolutePosition) = !emp_Salary sMsg = "What percent raise for " & !emp_fname & _ " " & !emp_lname & " making $" & _ Format$(!emp_Salary.AbsolutePosition) txtFields(4) = !emp_Salary If MsgBox("Show next record?".Update End If ' Move to next record . "###.CommitTrans Else wrkEmp.EOF txtFields(0) = !emp_no txtFields(1) = !emp_fname txtFields(2) = !emp_lname txtFields(3) = cSaveSal(rsEmp.BeginTrans ' Start of inner transaction.##0.00") & "?" sRaise = InputBox$(sMsg.wrkEmp.MoveLast . wrkEmp.RecordCount) ' Prompt for changes to salary Do Until .EOF txtFields(0) = !emp_no txtFields(1) = !emp_fname txtFields(2) = !emp_lname txtFields(3) = Format$(!emp_Salary.

the Connection object is richer in functionality.CreateGroup (name. • The CreateGroup method (Jet workspace only) creates a new Group object. a transaction affects all objects within the Workspace object. The ODBCDirect Database object is retained for backward compatibility with Jet workspaces and is created automatically when you use the OpenConnection method. You cannot close the default workspace.MoveNext Loop ' Roll back all updates ' This is the outer transaction wrkEmp. although you can use the Database object much as you would use it in a Jet workspace. pid (personal identifier) is a string of 4 to 20 characters.6 The DAO transaction application.3 where wrkEmp is closed. However. TIP About Workspaces And Transactions Transactions always have workspace scope. That is.Close Case 1 End End Select End Sub Figure 5. Set Group = object. The syntax is shown in the next code segment. numbers. If you issue a CommitTrans for one of multiple Database objects. object is either a Workspace or User that will own the Group object. The syntax is shown in the following code example. Its use is illustrated near the end of Listing 5. even if the object contains multiple Database objects. create additional Workspace objects. and underscores but must begin with a letter. object is either a Workspace or Group. Note that you can nest transactions within a Workspace object. Use of the method was discussed under the DBEngine topic earlier in this chapter. all the Database objects are affected. See the BeginTrans method later in the list for more information. If you need to manage transactions separately for different Database objects. pid is the personal identifier and password is a string of up to 14 characters containing the User object’s password. no error is generated. • The Close method closes the Workspace object. . The name may have any combination of letters.= vbCancel Then Exit Do End If .Close End With conCoriolis.) • The CreateDatabase method (Jet workspace only) creates a new Database object. which Jet uses in conjunction with an account name to identify a user or group in a Workspace object. (Attempting to close it is ignored.Rollback . pid) • The CreateUser method (Jet workspace only) creates a new User object.

CreateUser (name. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. password) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. pid.Set User = object. . Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. All rights reserved.

Refresh. (Note that permissions are actually administered at the document level by the Permissions property of the Document object. You can append a User object to a Group object’s User collections. you can append a Group object to the Groups collection of a User object. I discussed this method earlier in the chapter in the discussion on Workspaces. click the chapter and section titles. The object has . See “The Groups Collection And Group Object” later in this chapter for more information about these groups.To access the contents. Conversely. one named Admin and the other Guest. having the effect of making that User object a member of that group. whereas Guest is made a member of the Group object named Guests. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Users Collection And User Object The Users collection is a Jet-workspace-only construct belonging to the Workspace and Group objects (see Figure 5. Specifically. and queries. tables. User objects enforce access permissions and restrictions on Document objects within the Workspace that in turn represent the databases. use the Workspace or Group object’s CreateUser method. The User object is an account with a certain set of permissions to the underlying data within a Workspace object. it is a good idea to invoke the Refresh method before referencing a collection: wrkEmp. you can create a Workspace object with the same set of permissions as the User object. Admin is added to the Group objects known as Admin and Users. having the effect of giving that User object the same permissions as the Group object. see “The Documents Collection And Document Object” later in this chapter. DAO automatically creates two User objects.1). The User object has two collections: Groups and Properties. Note that because of the way the Group and User objects tend to reference each other.Users. To create a new User object.) Given a User object.

use the CreateGroup method. You can append a Group object to a User object’s Groups collection. The User object has two methods.1). . which we discussed earlier in the chapter. Because of the way users and groups tend to reference each other. Read EarthWeb's privacy statement. To clear the password. use a zero-length string for new_password. All of these were discussed earlier in the chapter. object. new_password The Groups Collection And Group Object The Groups collection is a Jet-workspace-only construct belonging to either a Workspace object or a User object (see Figure 5. The syntax is shown in the next code segment. Password. All rights reserved.1). and PID. and one method. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. To create a new Group.three properties: Name. The Group object has two collections (see Figure 5. I discussed the CreateGroup method earlier in the chapter. CreateUser. old_password is the object’s current password. I also discussed this method earlier in the chapter under the DBEngine topic.NewPassword old_password. The Group object represents a group of users who have common access permissions and restrictions to Document objects within a Workgroup object. Name and PID. You use the NewPassword method to change the password of an existing User object. Passwords are case-sensitive. two properties. which grants that user membership in the group (also see the discussion of the User object earlier in this chapter). Note that you must have the proper permissions to alter the Password property of a User object. Users and Properties. I discussed each of these under the CreateUser method. it is good practice to use the Refresh method before referencing the collection. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Note that the actual security is maintained at the Document object level via the Permissions property. new_password is the object’s revised password.

For more information. note that although you can use it for ODBCDirect workspaces. the db_type argument must be a valid ODBC connection string.1 and 5. the property is read-only. If you do specify this as a db_type and supply no parameters. as listed in Table 5. Properties and RecordSets are collections common to both Jet and ODBCDirect workspaces. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Databases Collection And Database Object The Databases collection contains all Database objects created within a Workspace object.. QueryDef. and TableDefs are Jet-workspace-only collections. Relations. However. whereas RecordSets is the default for ODBCDirect workspaces (see Figures 5. object. The Database object is used to manipulate an open database. the db_type must end in a semicolon and all parameters must be semicolon delimited. The Database objects are automatically appended to the collection and are created by the Workspace object’s CreateDatabase method. a logon dialog is displayed. If supplied. If using ODBCDirect. If a password is required but not supplied in the parameters argument. db_type must be ODBC. QueryDefs.) db_type is a valid database type. see the OpenDatabase method of the Workspace object discussed earlier in this chapter. or Connection object. Table 5. then the ODBC driver displays a dialog box of all available data sources. The syntax for the Connect property is shown in the next code example. • The Connect property sets or returns a string describing connection parameters to a database. The Database object consists of a number of collections: Containers.Connect db_type. TableDef. The Database object is automatically removed from the collection when you close it with the Close method. click the chapter and section titles. You should be sure to close all RecordSet objects within a Database before closing the Database object.2).5 Connect string settings. The Database object has a number of properties: • CollatingOrder (Jet workspace only) affects the sort sequence by setting which alphabet to use for string comparisons.5. (For QueryDef objects. .To access the contents. If under a Jet workspace. which I discussed earlier in this chapter. the Connection object has more functionality. object is a valid Database. TableDefs is the default for Jet workspaces. parameters is an optional argument with requirements that vary by database (see the database documentation for more information). parameters. you are performing a connection to a table linked via a Microsoft database (called a linked table). The Databases collection has only the Refresh method and the Count property.

x Paradox 4. if you were to run the following . UID=user.0.6. Excel 3.x. Excel 5. and replication properties have been added.Database Type Microsoft Jet Database dBASE III dBASE IV dBASE 5 HTML Import HTML Export Lotus 1-2-3 WKS Lotus 1-2-3 WK1 Lotus 1-2-3 WK3 Lotus 1-2-3 WK4 Microsoft Excel 3.xls drive:\path\filename. DATABASE=database.x. MAPILEVEL=folderpath. FoxPro 2.0 Microsoft Excel 4. I discuss replicas throughout the chapter. Excel 8.5 Microsoft FoxPro 2.] Text.x ODBC drive:\path drive:\path drive:\path drive:\path drive:\path drive:\path drive:\path None Text drive:\path • The Connection property (ODBCDirect workspace only) returns the Connection object that corresponds to the Database object.0. Example drive:\path\filename. Lotus WK1. • The RecordsAffected property returns the number of records that were affected by the most recent invocation of the Execute method. dBASE III. dBASE IV. ODBC. • The QueryTimeOut property is an integer that sets how long a query will run before timing out. HTML Export.0.xls drive:\path\filename. PWD=password. Excel 4.xls drive:\path\filename.] FoxPro 2.wk4 drive:\path\filename.] [DATABASE=database.0 Paradox 3. [TABLETYPE={ 0 | 1 }].xls drive:\path\filename.5.0. For example.0. A value of 0 specifies no limit.0.x Paradox 5.mdb drive:\path drive:\path drive:\path drive:\path\filename drive:\path drive:\path\filename.x.wk1 drive:\path\filename. Paradox 5.mdb Microsoft FoxPro 2. Paradox 4. FoxPro 2. DSN=datasourcename.xls drive:\path\filename. A Design Master is a database to which system tables. • The DesignMasterID property (Jet workspace only) returns a 16-byte value that corresponds to a Design Master in a replica set. Lotus WK1.0 Microsoft FoxPro 2. Note that the Connection object and Database object are two different variables that correspond to the same open database. [PROFILE=profile.] [PWD=password. Paradox 3.wks drive:\path\filename.0. dBASE 5.0. and it represents the first replica in a replica set.wk3 drive:\path\filename.0 Microsoft Excel 95 Microsoft Excel 97 Microsoft Exchange Specifier [database]. Lotus WK4.0.0 Microsoft Excel 5. FoxPro 3. Lotus WK3. Excel 5. system fields.6 Microsoft Visual FoxPro 3. [LOGINTIMEOUT=seconds. Exchange 4. HTML Import.

The following code illustrates this process: Dim prpReplica Set prpReplica = . All rights reserved. Once the property is set. If the value is “T”.Properties ("Replicable") = "T" Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the database becomes replicable. the RecordsAffected property would return 35 because there are 35 rows on the Employee table: Update Employee Set Emp_Sal = Emp_Sal * 1. it cannot be changed. Copyright © 1996-2000 EarthWeb Inc.query on the sample Employee table. . Read EarthWeb's privacy statement.Append prpReplica dbEmp.Properties. dbText. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.CreateProperty ("Replicable". "T") dbEmp.08 • The Replicable property (Jet workspace only) must first be created by using the CreateProperty method (discussed under the Properties topic earlier in this chapter). It must be a Text data type.

but there can only be one Design Master at a time. tables. add three new columns that help Jet determine what rows have changed so they can then be merged back into other copies of the database. Different replicas can serve as the Design Master. queries. For instance. When you set this property on a Database object.To access the contents. This is not accurate. a traveling salesperson might have a copy of the database on his or her laptop computer and then be able to add and maintain customers and take new orders. the GUID on both the server and the client must match for the two to bind. is a unique identifier of the replica itself. All tables. . The ReplicaID. click the chapter and section titles. Jet adds fields. • ReplicaID (Jet workspace only) returns a 128-bit Globally Unique Identifier (GUID). When you set the Replicable property of a Jet database. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Microsoft Jet And Replication One of the neater features of Microsoft databases in general and Microsoft Jet in particular is the ability to perform database replication. you might assume that the inherited object will have the same Replicable value. Replication refers to the process of being able to distribute portions or all of a database to distributed locations and then merge back all the changes to the master database. A replica is a copy of a database. Changes in one replica are synchronized and applied to all other replicas in the replica set. This value is stored in the MSysReplicas system table in the database. It returns a reference to the Design Master. and properties to all database objects. and so on) and is a member of a replica set. In terms of a replicable database. The replica set is all of the replicated copies of the database. you should first make a backup of the database because a lot of changes will be done immediately. which is the first replica in a replica set. I discussed the concept of inheriting properties earlier in the chapter in the discussion of Properties collections and the Property object. as an example. You still need to explicitly set the value. including all of its objects (tables. If you inherit an object and that object has a Replicable property. The changes to the replicated database can be merged back into the main database at a later time. then.

We discuss the QueryDef object later in this chapter. Two variations on the statement appear in the following code example.CreateRelation (name. source is a string that contains either an SQL statement or the name of a QueryDef object. Set relation = db. The syntax of the statement is shown in the next code segment. In an ODBCDirect workspace. db is a valid Database object. attributes) • CreateTableDef (Jet workspace only) creates a TableDef. it can also contain the name of a stored procedure on a Microsoft SQL Server database. attributes is an optional argument that specifies how two tables are related. The Database object has the following methods: • Close closes the object. object is a valid Database or Connection object. sql) • CreateRelation (Jet workspace only) creates a Relation object that specifies the relationship between two objects in TableDef or QueryDef objects. db is a valid Database object. See the discussion of the Relationship object for more information. sql is a string containing an SQL statement. attributes is one or more constants that describe attributes of the object. • V1XNullBehavior (Jet workspace only) is applicable to Jet version 1 databases converted to later versions.• Updatable is a Boolean that returns True if the underlying object is updatable. connect is a string that describes the connection. table. connect) • Execute runs an SQL statement such as SQL SELECT or UPDATE. In the first example.6) that specify the data integrity characteristics of the query. I discuss the Relation object later in this chapter. which I discuss later in this chapter. if set to True.CreateTableDef (name. table and foreign_table are Variants of type String that identify the two tables involved in the relationship. • CreateQueryDef creates a QueryDef object and appends it to the QueryDefs collection. indicates zero-length text fields will be converted to Null. Set QueryDef = object. source is the name of the table in the underlying database that the object refers to. You should be sure to first close all RecordSet objects. object is a valid Database or Connection object. • Version returns the ODBC driver version on ODBCDirect work-spaces. from the mode in which it was opened (such as read-only) to the nature of the query itself (not having a primary key or a join on several tables) to the nature of the record set type (such as snapshot). It is a Boolean that. • CreateProperty (Jet workspace only) adds a property to the Properties collection. There are a number of reasons an object might not be updatable. See the discussion of the Connect property of the Database object for more information. options is one or more constants (as listed in Table 5.CreateQueryDef (name. I discussed this method earlier. The second form of the statement specifies the . _ foreign_table. The syntax is shown in the next code example. Set tabledef = db. _ source. but it returns the version of Jet on Jet workspaces. You can leave sql blank and set the SQL property of the object after you create it. attributes. The syntax of the statement is shown in the following code segment.

Perform consistent updates. Perform rollback if an error occurs. this can only be a table name. replica is a string containing the full path and name of the new replica. all properties are set to False.QueryDef object and thus omits the name argument.7. This user-defined argument might be something such as “Replica of California Customers”. description is a string describing the replica. options • NewPassword (Jet workspace only) creates a new password for the object. options querydef. Value dbDenyWrite dbInconsistent dbConsistent dbSQLPassThrough dbFailOnError dbSeeChanges dbRunAsync dbExecDirect • MakeReplica (Jet workspace only) makes a new replica from another database replica. or RecordSet object in the second example. • OpenRecordSet opens a new RecordSet object and appends it to the RecordSets collection. ODBCDirect only (Connection and QueryDef). Immediately following. Initially. this can be a table name. meaning no data will be replicated. a query name. dbRepMakeReadOnly prevents users from changing the data in the replica. For ODBCDirect workspaces. the default is .Execute options Table 5. database. You need to set the ReplicateFilter properties of the TableDef object to determine what data will actually be replicated. which specifies the replica is a partial replica (not all records are included). Do not first call ODBC SQLPrepare function. the changes in those replicas will be applied to the new replica.MakeReplica replica. However. Generate runtime error if another user changes data. Jet only. Jet only. object. or an SQL statement. Perform asynchronous query. as outlined in Table 5. description. Perform an SQL pass-through query. For Jet workspace table-type record sets.) The syntax for the method is shown in the next code segment. This is a useful option when replicating data that is normally static (such as a ZIP code table). Execute does not return a record set. TableDef. ODBCDirect only (Connection and QueryDef). database is a valid Database object. source is a string that specifies the source of the data. Jet only. object is a valid Database or Connection object in the first example or a valid QueryDef. recordset is the name of a valid object variable of type RecordSet.6 Valid options constants for the Execute method. type is the record set type. Jet only.Execute source. Under ODBCDirect. For best performance. Jet only. I discuss the RecordSet object later in this chapter. It cannot already exist. I recommend issuing a BeginTrans before the Execute method. Two variations on this method are shown in the next code example. when synchronized with other replicas. (Default) Perform inconsistent updates. Jet only. (See the discussion of Replicable and ReplicaID properties earlier in this section. options is one or both of the constants dbRepMakePartial. perform a Rollback or CommitTrans method to end the transaction. Description Other users cannot write to the object. See the discussion of this method earlier in the chapter under the User object.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. All rights reserved.” ' Database and Connection objects Set recordset = object. Under Jet.9. If Jet cannot open this type or if you are opening an ODBC data source. I discuss these settings in more detail later in this chapter under “The RecordSets Collection And RecordSet Object. type. lockedits) ' QueryDef.8 and 5. TableDef and RecordSet objects Set recordset = object. _ options. the default is dbOpenDynaset. . the default is dbOpenTable. _ lockedits) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. options. Valid options and lockedits are listed in Tables 5. Copyright © 1996-2000 EarthWeb Inc.dbOpenForwardOnly.OpenRecordSet (source.OpenRecordSet (type.

Opens a forward-only-type record set object. Passes an SQL statement to ODBC for processing. Dynaset only. Opens a dynamic-type record set.To access the contents. Generates an error if another user changes data. Opens a dynaset-type record set. Snapshot only. click the chapter and section titles.7 Valid RecordSet type constants. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Constant dbOpenTable Table 5. Opens a snapshot-type record set. dbSQLPassThrough Yes dbSeeChanges Yes No dbDenyWrite Yes No . Dynaset only. dbOpenDynamic dbOpenDynaset dbOpenSnapshot dbOpenForwardOnly Yes Constant dbAppendOnly Table 5.8 Valid RecordSet option constants. Jet ODBCDirect Description Yes No Yes Yes No Yes Yes Yes Yes Opens a table-type record set. Prevents other users from modifying or adding records. Jet ODBCDirect Description Yes No No User can only append new records.

dbRepImpExpChanges. dbRepImpChanges sends changes from the replica to the Database object. The database argument is a valid Database object. Enables batch optimistic updating. Allows only consistent updates.9 Valid RecordSet lockedit constants. the replica is populated with data based on the current DataBase object.dbDenyRead dbForwardOnly dbReadOnly dbRunAsync dbExecDirect dbInconsistent Yes Yes Yes Yes No Yes No No No No Yes No dbConsistent Yes No Prevents other users from reading data in a table. pathname is a String containing the path and name of the replica. Prevents changes to the record set. Dynaset. Creates a forward-only record set. Based on the values of the Filter properties of the TableDef objects. Runs query asynchronously. Allows inconsistent updates. Uses pessimistic locking. which is the default. snapshot only. The syntax is shown in the next code example. Uses optimistic concurrency based on row values. Constant dbReadOnly dbPessimistic dbOptimistic Jet Yes Default Yes ODBCDirect Default Yes Yes Yes Description Prevents users from making changes. snapshot only. It takes only the argument of the replica to synchronize as a string containing a path and name of the replica (see MakeReplica). Uses optimistic locking. Table 5. To use . dbRepExportChanges sends changes from the Database object to the replica. Dynaset. dbRepSyncInternet replicates changes between two files connected by an Internet pathway. synchronizing it with the Design Master. exchange is a constant indicating which way to replicate. Snapshot only. Does not first call ODBC SQLPrepare function. dbOptimisticValue No dbOptimisticBatch No Yes • PopulatePartial (Jet workspace only) populates a partial replica. • Synchronize (Jet workspace only) synchronizes two replicas. sends changes both ways.

Copyright © 1996-2000 EarthWeb Inc. All rights reserved. changes to the design of the database are always replicated first. you must use the PopulatePartial method instead. Note that when you replicate changes. . This occurs even if replication is going only one way. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. The two replicas cannot have the same ReplicaID. exchange Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. database. If synchronizing partial replicas with other partial replicas.this. Read EarthWeb's privacy statement. specify a URL instead of a file name and path in the pathname argument.Synchronize pathname.

RecordsAffected. If you create a Database object in an ODBCDirect workspace. The Connection object also has a number of methods in common with the Database object: Close. a corresponding Database object is also created and added to the Databases collection. Because you can open the same Connection object more than once. several of which are in common with the Database object and were discussed earlier in this chapter: Connect. and Updatable. if you create a new Connection object. • StillExecuting is a Boolean that indicates whether a query run asynchronously is still executing. its Name may appear more than once in the collection. QueryTimeOut. The Connection object has a number of properties. I discussed these methods earlier in this chapter under the Database object . • Transactions is a Boolean that returns True if the underlying data source supports transactions.2): QueryDefs (the default) and RecordSets. Conversely.To access the contents. and OpenRecordSet. Execute. CreateQueryDef. a corresponding Connection object is also created and added to the Connections collection. It is available when invoking the Execute or CreateConnection methods. The Connection object itself represents a connection to an ODBC data source. see the CreateConnection method of the Workspace object discussed earlier in this chapter. Other properties of the Connection object include the following: • Database returns an object variable that is a reference to the corresponding Database object. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Connections Collection And Connection Object The Connections collection is an ODBCDirect workspace construct that encompasses the functionality of the Databases collection and adds additional functionality. Connection objects are automatically appended to the collection. It contains two collections (see Figure 5. click the chapter and section titles. To create a new Connection object.

although the possible permissions are slightly different. The purpose of the Container object is to group similar types of Document objects. Some of these permissions may be specific to the user. The Document object also has this property.topic. User has exclusive access to the database. See also the Permissions property.10. others may be inherited from the group to which he or she belongs. User can open the database.10 Container and Document permission constants. Constant Container Document Description dbSecDBAdmin No Yes User can replicate the database and change the password. Some of these Container objects are defined by the Jet engine. the Container maintains information about tables and queries. For the Table object. For the Relationship object. The Containers Collection And Container Object The Containers collection is a Jet-workspace-only construct representing all of the Container objects in a Database object. It has the following properties: • AllPermissions returns all of the permissions of the current UserName property. as listed in Table 5. whereas others are defined by other applications. Because Container objects are automatically appended to the Containers collection. the collection has only a Refresh method and a Count property. including column and index information. Table 5.MDW). the Container contains information about saved databases. Connection also has a Cancel method that you can use to cancel a currently executing asynchronous query: myConnection. User can create new databases. The Container object has two collections: Properties and Documents (which is the default). This setting is valid only on the Databases container in the workgroup information file (System. dbSecDBCreate No Yes dbSecDBExclusive No dbSecDBOpen dbSecDeleteData dbSecInsertData dbSecReadDef No Yes Yes Yes Yes Yes Yes Yes Yes . User can delete records.Cancel. For the Database object. User can add records. Container maintains information about saved relationships. User can read the table definition.

dbSecReplaceData Yes dbSecRetrieveData Yes Yes Yes User can modify records. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. including column and index information. As such. he or she has the privilege of changing the Owner property. This does not include permissions inherited by membership in a group (see AllPermissions). . All rights reserved. dbSecWriteDef Yes Yes • The Inherit property indicates whether new Document objects will inherit the Permissions property from this object. Copyright © 1996-2000 EarthWeb Inc. Set it to True to cause new objects to inherit the Permissions property. • The Owner property is a string that is the name of an object in either the Groups or Users collection and represents the owner of this object. These permissions are summarized in Table 5.11. User can modify or delete the table definition. • The Permissions property is a long containing constants indicating which permissions have been assigned to the UserName property. assuming other permissions permit this. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. User can retrieve data from the Document object.

To access the contents. User can change the Owner property setting. User can delete records. User can modify records. User has full access to the object. User can read the table definition.* User has exclusive access to the database. User doesn’t have access to the object. User can retrieve data from the Document object.* User can read the object’s security-related information. User can open the database. dbSecDBExclusive No dbSecDBOpen dbSecDeleteData dbSecDelete dbSecFullAccess dbSecInsertData dbSecNoAccess dbSecReadSec dbSecReadDef No Yes No No Yes No No Yes dbSecReplaceData Yes dbSecRetrieveData Yes dbSecWriteOwner No . Table Database Other Description Yes No No No Yes Yes Yes Yes No No No No No No No No No No No No No No No No Yes Yes No Yes Yes No No No Yes User can create new documents.* User can create new databases. click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Constant dbSecCreate dbSecDBAdmin dbSecDBCreate Table 5. User can delete the object. User can add records.11 Valid Permissions constants.* User can replicate database and change password.

You should create this property before making an object replicable. The following code segment is adapted from the Microsoft VB help file and shows KeepLocal being used on the Northwind database: Dim Dim Dim Set Set dbNorthwind As Database docTemp As Document prpTemp As Property dbNorthwind = OpenDatabase("Northwind. • DateCreated returns the date and time that a table was created for table-type record sets (Jet workspace only) or that the object was created in all other cases.mdb") docTemp = dbNorthwind. tables (in a table Container).dbSecWriteSec dbSecWriteDef No Yes No No Yes No User can alter access permissions.CreateProperty("KeepLocal". Permissions. Document. Document objects describe instances of objects specified by the owner Container object.Containers("Modules"). _ dbText. and relationships (in a relationship Container). The Documents Collection And Document Object The Documents collection is a Jet-workspace-only construct belonging to the Container object. The Document object has a number of properties in common with its Container object: AllPermissions. Then. Owner. this Document object will not be replicated with the other objects. and UserName. Document objects are automatically appended to the Documents collection. LastUpdated returns the date and time the table or object was last updated. Both values are of type Variant with an underlying data type of Date. and QueryDef objects. With the properties discussed in this section. The Document object has one collection: Properties. The Container object has no methods. See the discussion of the Container object earlier in this chapter for explanations of these properties. User can modify or delete the table definition. TableDef. Other properties include the following: • Container returns an object variable that is a reference to the parent Container object. _ Documents("Utility Functions") Set prpTemp = docTemp. "T") ' Set an existing document docEmp. you can obtain information about saved databases (in a database Container). *Not valid for Document objects. It is a user-defined property and must therefore be created using the CreateProperty method discussed earlier in this chapter for the Property object. • KeepLocal is similar to the Replicable property of the Database.Properties("KeepLocal") = "T" . • UserName is a string representing the user of the object. Name.

Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement.Close • Replicable is a user-defined property that determines whether the object can be replicated. The Document object has no methods. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I discussed this method under the Database topic earlier in this chapter. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.Append prpTemp dbNorthwind. All rights reserved. .docTemp.Properties.

there was no conflict. you invoke the Database object’s CreateTableDef method. Read-only. Read-only. and Replicable. discussed earlier in the chapter: DateCreated. you must append it to the TableDefs collection.1 Table is a system table provided by Jet. With the individual TableDef objects. Name. You can write to this property even if the object has not been appended to the collection. It also has the following properties: • Attributes is a long consisting of one or more constants describing various attributes of the object.12.2 Table is a hidden table provided by Jet. Table is a linked table from an ODBC data source. Constant Table 5. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The TableDefs Collection And TableDef Object The TableDefs collection is a Jet workspace construct belonging to the Database object. Note that attributes of the individual columns are stored in the Attributes property of the individual Field objects. can set this constant on an appended TableDef object. Fields. Attributes of the relationships are stored in the Attributes property of the individual Relationship objects. Description The table is a linked table opened for exclusive use. click the chapter and section titles. This . If this is a zero-length string. you can manipulate a table definition. as listed in Table 5. and Indexes (see Figure 5.2 Table is a linked table from a non-ODBC data source. LastUpdated. • ConflictTable is a string containing the name of the table that caused an error during a replica synchronization process.1 Save the user ID and password with the connection information.12 Valid Attributes constants of the TableDef object. which I discussed earlier in this chapter. To create a TableDef object. KeepLocal.1). The TableDef object has three collections: Properties.To access the contents. including validation rules. When you create a TableDef object. dbAttachExclusive dbAttachSavePWD dbSystemObject dbHiddenObject dbAttachedTable dbAttachedODBC 1Not 2You valid for local tables. The TableDef object has some properties in common with the Document object.

invoke the ReplicatePartial method.Synchronize "California. Dim tdfEmp As TableDef Dim sFilter As String Dim dbCoriolis As Database ' Open the database Set dbCoriolis = OpenDatabase("Coriolis. The table name will be suffixed with “_conflict”. The update of one record will be replicated to the other.4 replicates only the employees from the state of California to a partial replica contained in the “California. this value will be Employee_conflict. • The ValidationRule for a TableDef object differs from that for a Field object in that it can apply to multiple fields in the table. If the table is a linked table. The three settings are True (replicate all records).mdb" ' Set the replica filter sFilter = "Emp_St = 'CA'" ' Now do the partial replication tdfEmp. the following code enforces the rule for the Item table that price must be greater than cost and that the cost must be greater than zero: ' tdfItem is an existing TableDef tdfItem. • The ReplicaFilter is used with partial replicas (I discussed this earlier in the chapter when I discussed the Database object). or a string specifying a filter to use to determine which records to replicate.PopulatePartial "California. Listing 5. For instance. then the RecordCount is always -1. You cannot use any aggregate functions or user-defined functions.mdb") ' Define the TableDef as the employees table Set tdfEmp = dbCoriolis. Listing 5.property is useful when two users make changes to the same record. This property tells you the name of the table that contains the conflict information so that the problem can be resolved. • Connect is a string containing connect information. In other words.ValidationRule = Str$(Item_Price) & " > " & _ . Before changing the filter. but the second user’s changes will not be replicated. The ValidationRule property allows you to validate values entered or maintained by the user on the underlying object (the table. it is the name of the underlying table of the TableDef object. It is specified similar to the RecordSet object’s Find criteria argument.MDB” file.TableDefs("Employees") ' Synchronize first! This is a full replica dbCoriolis. in this case) by creating a rule similar to an SQL WHERE clause without the WHERE keyword. • RecordCount is a long containing the total number of records in the object.mdb" • The SourceNameTable property is a string that specifies the name of a linked table or a base table in a Jet workspace. if a conflict occurs on the Employee table. be sure to execute the Synchronize method. False (don’t replicate any records). After changing the filter. For example.4 Using ReplicaFilter and performing a partial replication. The data entered by the user must conform to the rule set in the ValidationRule or the change is rejected and the message entered into the ValidationText property is displayed. I discussed this property earlier in the chapter in the Database topic.ReplicaFilter = _ sFilter dbCoriolis.

All rights reserved. Read EarthWeb's privacy statement.Str$(Item_Cost) & " AND " & Str$(Item_Cost) & " > 0" • The ValidationText property sets the text of a message that will be displayed if an edit does not pass the ValidationRule. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Copyright © 1996-2000 EarthWeb Inc.ValidationText = "Price must be greater than" & "cost and cost must be greater than 0!" _ Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. The following code sets the property: tdfItem.

which you must append to the Fields collection manually. I discuss the Field object later in this chapter.CreateIndex (name) • OpenRecordSet opens a new RecordSet object. Set field = object. For instance. Whereas a TableDef object represents a table within a database (represented by the Database object). you should issue the RefreshLink method to physically attach to the new data source. size) • The CreateIndex method creates a new Index object. object is an existing Field.2). you need to use the Refresh method on all collections (Fields and Indexes) belonging to the TableDef object so that they will also be in sync. TableDef. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The TableDef object has a number of methods: • The CreateField method creates a new Field object. You must manually append the Index object to the Indexes collection. The syntax is shown in the next code example.To access the contents. you could change the Connect property to attach to a different data source. Relation. Set Index = TableDef. The syntax for the CreateField method is shown in the next code example.3 earlier in the chapter listed the valid data types.1 and 5. The Fields Collection And Field Object The Fields collection is a construct belonging to a TableDef. You cannot delete a Field object from the collection if an Index object is referencing it. RecordSet. or Index object (see Figures 5. size is a Variant (subtype Integer) that is used to set the maximum size of a text field. When you do. the Fields collection of . I discuss Index later in this chapter.CreateField (name. or Relation object. • The RefreshLink method allows you to refresh connection information. click the chapter and section titles. type is the data type of the new Field object. It represents all of the fields associated with that object. Note that once you change a data source. Table 5. QueryDef. type.

If used. • DefaultValue is a string of up to 255 characters specifying a default value for the field. For other objects. if you were to append to the Fields collection objects representing Emp_Salary. The string can contain the special value GenUniqueID(). The string can also contain any expression except a user-defined function. Within a RecordSet object. such as a customer number. For example. ForeignName contains the name of a Relation object. • CollatingOrder is a Long containing a constant that specifies a collation sequence (sort order). • FieldSize returns a Long indicating the size of the Field object. such as TableDef. the Field objects are the specifications of the field (such as data type). the ordinal number represents the actual order in which the fields appear within the owning object. Emp_LName. you can reference it by its Name property or by its ordinal number (as in any other collection). Emp_LName would be ordinal number 1 (the collection is zero-based) and would appear to be the second column on the Employee table. • ForeignName is used in referential integrity relationships. For an Index object. dbSystemField specifies that the field contains replica information. dbVariableField specifies that the field is variable length. However. dbFixedField specifies that the field is fixed length. and then Emp_FName. • AllowZeroLength is a Boolean that sets whether a text or memo field can contain a zero-length string. dbAutoIncrField causes the value of the field in new records to increment to a new Long value. the Fields collection is the database fields represented in that index. The Field object has a number of properties that you use depending on its context. For example. Note that the number of characters and number of bytes may not be the same.13. the Relation object’s TableName property contains the name of the table on whose primary key this Field object is dependent. it is the number of bytes. depending on whether ANSI or multibyte characters are used. For a numeric field. whereas Value is a frequently used property when dealing with Field objects belonging to the RecordSet object. if the Field object is part of the Orders table containing the definition of the Cust_No field. For a memo field. As such. This is the default for numeric values. • Attributes is a Long containing one or more constants with which you can specify various attributes of the Field object. True indicates the field is updatable. then the . which causes a unique random number to be assigned as a value of the Field object. this is the number of characters. such as whether it can be updated (dbUpdatableField). dbDescending specifies that a Field object in an Index will sort in descending order. this is useful for primary keys. FieldSize is an important property in terms of the TableDef object. different properties are available depending on the owner of the Field object.Field objects represents all of the fields or columns on that table. dbHyperLinkField is used with a memo field to specify that it contains a hyperlink. These are summarized in Table 5. When referring to a Field object in the collection. • DataUpdatable is a Boolean indicating whether the field can be updated. you use the Fields collection to read and set values from the current record. For instance.

the Value property of the Field object is constrained to already existing Cust_No values on the Customer table. If False. it is validated only when being updated to the table. • ValidationRule was discussed earlier in this chapter under the TableDef object. Thus. See also the FieldSize property. the Type value determines the maximum size and this property is set automatically. then SourceField would be Cust_LName and the SourceTable would be Customer.8 illustrates some techniques to handle collisions. the “Cust_LName” Field object might have a Value of “Smith”. • OrdinalPosition is an integer that sets or returns the relative position of the Field object within the Fields collection. I talk at more length of transaction and concurrency issues in Chapter 12. This is useful during batch updates so that you can determine whether another process has altered a record in between the time that you retrieve it and the time you update it. Table 5. • ValidationText sets or returns the text that will be displayed if data does not pass validation. For most data types. unlike the ValidationRule property of the TableDef object. For instance.ForeignName property is set to the name of that Relation object whose TableName property is set to Customer. the data is validated as soon as it is set. Property Index QueryDef RecordSet Relation TableDef AllowZeroLength Attributes No Yes No Yes Jet only Yes Jet only No Jet only Yes . It is a constant as listed in Table 5. Setting this property to True is the equivalent of specifying Not Null in a table Create statement. the ValidationRule can only reference the Field object to which it applies. a collision is said to have occurred. • VisibleValue is used in conjunction with the OriginalValue property discussed in concurrency management in batch updates.3 earlier in this chapter. If True. the ValidationRule property of the “Cust_LName” Field object cannot reference the “Cust_FName” Field object. See the ValidationRule example earlier in this chapter under the TableDef topic. When the VisibleValue is different from the OriginalValue. • SourceField and SourceTable set or return the name of the field (or column) and file (or table) to which this Field object corresponds. • Type sets or returns the data type of the Field object. • Value contains the value of the Field object. If a change occurred. In other words. then the new value of the field is shown in the VisibleValue property. If the object is used for a customer’s last name. • OriginalValue contains the original value of the Field object when first retrieved. However. • Size is used with the text data type to set a maximum number of characters (up to 255 characters). • ValidateOnSet is a Boolean that dictates when the data will be validated. Listing 5. • Required is a Boolean indicating whether the field must contain a non-null value.13 Properties of the Field object and when they are available.

All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.CollatingOrder DataUpdatable DefaultValue FieldSize ForeignName Name OrdinalPosition OriginalValue Required Size SourceField SourceTable Type ValidateOnSet ValidationRule ValidationText Value VisibleValue *Only No Yes No No No Yes No No Yes No No No Yes No No No Yes No Jet only Yes Jet only No No Yes Yes No Yes Yes Yes Yes Yes No Jet only Jet only No No Jet only Yes Jet only Yes No Yes Yes No Yes No No Yes Yes No No Yes Jet only No No Yes Jet only No Yes Yes Yes Yes Yes No Yes Yes No No ODBCDirect* No Yes No Yes Yes Yes Yes Jet only Jet only Jet only Yes No No No No No No No No ODBCDirect* No if DefaultCursorDriver is dbUseClientBatchCursor. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . Read EarthWeb's privacy statement.

For instance.GetChunk (offset. length) Recordset!Field. You should then use the Append method to append it to the collection. GetChunk retrieves all or a portion of such a field. Note that the first time you use AppendChunk on a field. The other two methods help in dealing with large memo or long binary fields. the database would allow . source The Indexes Collection And Index Object The Indexes collection contains all of the Index objects of a TableDef object in a Jet workspace (see Figure 5. click the chapter and section titles. Subsequent calls to AppendChunk then add to the end of the field. The syntax for AppendChunk is also shown. such as Cust_LName and Cust_FName. and length is how many bytes to copy.To access the contents. variable is a Variant of type String. You create an Index object using the TableDef object’s CreateIndex method. RecordSet is a valid RecordSet object. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Field object has three methods. in which case it also acts as an integrity constraint by preventing any duplicate values in the column or columns on which the index is defined. I discussed the CreateProperty method earlier in this chapter in the Properties collection section. An index can be unique. source is a Variant of type String from which data is to be copied to the Field object. When ordering by Cust_LName or by both Cust_LName and Cust_FName. offset is a Long specifying from which byte to start copying. You can place an index on one or more columns in a table. AppendChunk adds data to the end of a memo or long binary field.1). you can only do that if the TableDef is updatable (as denoted by the Updatable property of the TableDef).AppendChunk. Set variable = RecordSet ! Field. I discussed indexes in Chapter 2. Field is a valid Field object. if a unique index were created on the last and first name fields of the Customer table. the value of the field is replaced. the database will use the indexes to tremendously improve performance. However. GetChunk uses the syntax shown in the following code segment. An index is used on a database either to speed up access or to act as an integrity constraint.

if this property is True. you should also consult with your DBA. If the index is unique and there is a duplicate value in the column or columns covered. • The IgnoreNulls property is a Boolean that determines how null values are handled. In other words. the index represents a foreign key to a parent table. • DistinctCount is a Long that returns the number of unique values in the index. If IgnoreNulls is True and Required is False. An index becomes “active” only when it is appended to the Indexes collection. then the property is equivalent to the number of unique values in that column. Some databases have an Update Statistics command that should be run periodically to update this type of information (which is helpful to the query optimizer). which is a Boolean that determines if null values are allowed. Microsoft databases (MDB files) do not support clustering. most (but not all) databases require that the clustered index be specified when the table is created or before any data is added to the table. then the IgnoreNulls property is irrelevant because there can be no null values. then null values are allowed but are not reflected in the index. . The Fields collection is used. If the index covers more than one column (called a compound index or composite index). Note that this property may not always reflect the actual number of distinct properties. The Index object has the following properties. Some ISAM files and most relational databases support clustering of data.5 demonstrates the use of most of the properties. • Foreign is a Boolean indicating whether this index references a column in another table in a referential integrity relationship. Because the index becomes active when appended to the collection. you should use the CreateIndex method if you need this property to be exact. True is the equivalent of the Not Null clause in the CREATE TABLE statement. For example. If Required is True. you must set all of its properties before appending it. Listing 5. of course. You use this property in association with the Required property. If the index is on one column. you can set this property to False to ignore those null values and thus speed searches. but it would allow only one combination of “Smith” in Cust_LName and “John” in Cust_FName. The clustering specifies in what order the data is physically stored on the table. then null values are allowed and are also reflected in the index. then a trappable error occurs. ODBC data sources always return False for this property. Because of performance considerations. • Clustered is a Boolean indicating whether the index is clustered. which you use to maintain and manipulate the index. You should consult your database documentation for whether your database does support clustering and what restrictions are enforced. you are better off maintaining the clustering information at the database level and not within your Visual Basic program. the clustered index is not detected. If a field allows null values. then the property is the number of unique combinations of those columns. An Index object has two collections: I discussed Properties earlier in this chapter and Fields right before this topic.duplicate values of “Smith” in Cust_LName. A table may have only one clustered index on it. This information is typically maintained in the database’s system tables. From Visual Basic. to specify what columns comprise the index. By and large. If IgnoreNulls and Required are both False.

All rights reserved. Copyright © 1996-2000 EarthWeb Inc. .• The Primary property is a Boolean indicating whether the index is the primary key of the table. it is unique. and by definition. A table can have only one primary key. • The Unique property is a Boolean indicating whether the index is unique. NOTE An Index object does not specify in what order the data is stored. only in what order the data will be returned when the index is used in an Order By clause. Read EarthWeb's privacy statement. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

' Declare variables Dim dbCoriolis As Database Dim tdfEmployee As TableDef Dim idxName As Index ' Open the database object Set dbCoriolis = OpenDatabase("Coriolis.Fields.Append .CreateField("Emp_FName") ' Not unique .Append . click the chapter and section titles.5 demonstrates the use of the Index object using the sample Access database supplied on the CD-ROM.Indexes.CreateIndex("Name") ' Set properties as needed With idxName ' Create a non-unique index on the employee ' last name and first name fields .IgnoreNulls = False End With ' Make the index active (builds the index) tdfEmployee. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Listing 5.CreateField("Emp_LName") .Append idxName .mdb") ' Open the Employee table Set tdfEmployee = dbCoriolis!Employee ' Create a new index object Set idxName = tdfEmployee.Fields. Listing 5.Unique = False ' Do not ignore null values .To access the contents.5 Using the Index object.

it would not be listed because the join condition would not be satisfied. The default is a natural or inner join. EMP_FNAME. Both were discussed earlier in the chapter. dbRelationDontEnforce means there is no referential integrity enforced.Index ("Name"). It indicates that even if no employees are in a particular department. Consider the following selection: SELECT DEPT_NO. which simply specifies that data is returned from both tables if the join condition is satisfied. dbRelationUnique specifies the relationship is one-to-one.Indexes. However. EMPLOYEE WHERE DEPT_NO = EMP_DEPT_NO If a department did not happen to have any employees in it. After creating a Relation object. you can also specify the use of an outer join. EMP_LNAME FROM DEPARTMENT. in the Properties collection and TableDefs collection sections. A left outer join is how we indicate that it is okay if the information on the left-hand side of the comparison is missing. EMP_NO. the department information should be returned. You can determine if the relationship is one-to-one or one-to-many. respectively. The Relations Collection And The Relation Object The Relations collection contains all of the Relation objects of a Database object and is created using the CreateRelation method. The Relation object has these properties: • The Attributes property is one or more constants and describes the relationship between the Field objects in the Fields collection associated with this Relation object. dbRelation-UpdateCascade specifies that any updates to a value will cascade down to dependent values. An outer join states that even if the join condition is not satisfied. We can perform outer joins using the Attributes property of the Relation object.DistinctCount & _ " unique values.1)—Fields and Properties—which were discussed earlier in this chapter. list the other information anyway. you should append it to the Relations collection. if a customer number is changed on the Customer table. A Relation object sets or returns how columns in a database relate to one another. some data is to be returned. list all employees. The Relation object has two collections (see Figure 5.' Display how many unique values there are MsgBox "There are " & _ tdfEmployee. In this example. For instance. A right outer join is just the opposite. then all of the customer . which I discussed earlier in this chapter in the Database object section. DEPT_NAME. dbRelationInherited means that the relationship is enforced in some other database than the current database (this is a Microsoft Access concept only)." The Index object also has two methods: CreateProperty and CreateField. a left outer join states that even if a department number is missing on the department table. You can also specify how columns are to be used when joining two tables. We can solve that by creating an outer join.

dbRelationLeft and dbRelationRight are used with Microsoft Access to specify a left outer join or a right outer join as the default join type. This has implications if a row in a partial replica has its parent or child link broken because the partial replica does not include the parent or child information.numbers on the referenced Orders table will also be updated to reflect the change. which I discussed earlier in the chapter in the TableDefs topic. all child rows will also be deleted. The Field object has one method. All rights reserved. dbRelationCascade is similar. specifying that if a parent row is deleted. The Attributes property describes how to relate them. • The PartialReplica is a Boolean that. if a customer is deleted. Read EarthWeb's privacy statement. specifies that the Relation should be considered when populating a partial replica from a full replica. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. if True. For example. even if it’s not defined to be a part of it in the TableDef object’s PartialReplica property. CreateField. all of the customer’s orders will also be deleted. Use the Fields collection to set or determine what fields are involved in the relationship. associated information will be included in the partial replica. Copyright © 1996-2000 EarthWeb Inc. • The Table and ForeignTable properties specify the parent and child tables in a relationship. If set to True. .

The QueryDef object consists of the Fields collection (which I discussed earlier in the chapter) and the Parameters collection (which I discuss later in the chapter). see the CacheStart property of the RecordSet object. You can fill the cache by invoking the FillCache method or simply by moving through the record set. which you can use to specify how the query will run and behave: • The CacheSize property (ODBCDirect workspace only) is a Long that sets or returns how many rows will be cached locally. under the Parameters section. it is saved in the database). Also. you also don’t want to set this too high because the user may not be able to interact with the data until the cache fills.1) or a Connection object (see Figure 5. all records are cached locally. To create a QueryDef object. use the CreateQueryDef method. The QueryDef object represents a saved query. you can improve performance by eliminating how many times rows have to be retrieved from the server. QueryDef objects are manually appended to the collection.2). By caching records locally.6. For ODBCDirect workspaces. I illustrate the use of the QueryDef object in Listing 5. . it is a temporary object and is destroyed when the application ends or the object is unloaded from memory. The QueryDef object has a number of properties. which I discussed earlier this chapter when I discussed the Databases collection. later in this chapter. In a Jet workspace. the value must be between 5 and 1. Note that the CacheSize property is a tuning parameter. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The QueryDefs Collection And QueryDef Object The QueryDefs collection maintains all QueryDef objects of a Database object (see Figure 5. the QueryDef object is permanent (that is.200 but cannot exceed the memory available. A good compromise setting is 100 rows. click the chapter and section titles. However.To access the contents. In a Jet workspace. Otherwise. A setting of 0 turns off caching.

this setting is useful in limiting potentially “runaway” selects. It is then stored temporarily on the database until run. A value of -1 indicates that the default Database or Connection QueryTimeOut value should be used. • MaxRecords is used to limit the number of records that will be returned from an ODBC data source. it may make sense to prepare it first. a query that is going to run in less than three seconds does not need to be prepared. In ODBCDirect workspaces. Also. or deleted. You can ask the database to prepare a statement. • The KeepLocal property (Jet workspace only) applies to partial replicas. The value dbQPrepare causes the query to be prepared. you may get somewhat better performance by preparing it before execution. The messages are contained in a table within the database. • The RecordsAffected property is a Long that returns the number of records affected by the most recent Execute. A value of 0 specifies no limit. whereas dbQUnPrepare causes the query to run dynamically (without being prepared). However. no more will be returned. • The DateCreated and LastUpdated properties (Jet workspace only) return when the object was created and when it was last updated. which is roughly equivalent to compiling it. Where a query is more complex or will take more time to execute. modified. Setting this property causes the object not to be distributed to other replicas. this is useful in reining in a potential runaway query. Before using this property. the value is meaningless when performing a Drop Table statement (the value will not reflect the number of records deleted). In general. • LogMessages (Jet workspace only) causes messages returned from an ODBC database to be written to a log file. It is a Long where 0 specifies no limit. Like the MaxRecords property. You can override dbQPrepare by setting the Execute method’s Options argument to dbExecDirect.• The Connect property specifies connection parameters to the database and was discussed earlier in this chapter in the Database section. Once the maximum number of records is reached. The property is a Boolean where True causes messages to be logged. • The ODBCTimeOut property indicates the number of seconds that will occur before an executing query will time out. even if more fit the selection criteria. The database analyzes the query and determines the optimum access path to the data. it must first be created. • The Prepare property (ODBCDirect workspace only) is a Long that indicates whether a query should be prepared before being executed. such as when testing. The name of the table is the user name appended with a sequential number such as “Admin-01” or “Admin-02”. you will want to limit the number of records returned by making your SQL SELECT statements as restrictive as possible. As a practical matter. • The Replicable property sets or returns a value that determines if the . which I illustrated under KeepLocal earlier in the chapter in our discussion of the Document object. if you are going to run the same query repeatedly. This is the number of records added.

In general. Jet ODBCDirect Description Yes Yes Yes Yes Yes Yes Yes Yes Yes No Yes Yes Yes Yes A query that changes data such as Update. you should use Jet SQL (see Appendix B) unless you are performing a passthrough query. in which case you should use your database’s SQL dialect (such as Oracle or MS SQL Server). You cannot manipulate data retrieved until this property is False.current object should be replicated. meaning that DAO reports back to you the type of query stored in the QueryDef object. A Select statement. • The Type property sets or returns the query type.14.) The SQL statement can contain parameters. The parameters (see the discussion of the Parameters collection later in this chapter) must be set prior to execution of the query. In Jet workspaces. A Union query (combines two or more Select queries). A stored procedure. • The ReturnsRecords property (Jet workspace only) sets or returns a Boolean that indicates whether an SQL passthrough query returns records. Adds records to the end of a table. (Note that the ODBC driver for your database may not necessarily implement 100 percent of your database’s functionality. you use the database’s dialect. you should set this property to True. A compound query. this is a read-only property. If the query does return records. You can also call a stored procedure with or without parameters in ODBCDirect workspaces. A cross-tab query. An SQL UPDATE command.14 Valid QueryDef object Type values. Create and Drop). Constant dbQAction dbQAppend dbQCompound dbQCrosstab dbQDDL dbQDelete dbQMakeTable Table 5. • SQL is a string containing the query to be executed by the QueryDef object. does not return any records. A query that creates a new table from an existing record set. dbQProcedure dbQSelect dbQSetOperation No Yes Yes Yes Yes Yes . set it to False. as listed in Table 5. Refer to your ODBC driver’s documentation. A query that deletes rows. • The StillExecuting property (ODBCDirect workspace only) returns a Boolean indicating whether a query being run asynchronously is still executing. otherwise. In ODBCDirect workspaces. for instance. Data definition language (that is. I discussed this property’s usage earlier in the chapter when I discussed the Database object.

Copyright © 1996-2000 EarthWeb Inc. • The Updatable property returns True if the query definition itself can be updated.dbQSPTBulk Yes No dbQSQLPassThrough Yes dbQUpdate Yes No Yes With dbQSQLPassThrough. An action query that changes a range of records. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. even if the resulting record set is read-only. a query that doesn’t return records. A passthrough query. All rights reserved. . Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement.

creates a new RecordSet object based on the QueryDef object and appends it to the RecordSets collection. as listed in Table 5. The options argument is one or more constants.9 earlier in the chapter. type is the type of record set to open. lock) The Parameters Collection And Parameter Object The Parameters collection contains all of the Parameter objects of a QueryDef object. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The QueryDef object has a number of useful methods: • The Cancel method (ODBCDirect workspace only) cancels a currently running asynchronous query. you will get better performance if you place the Execute statement after an explicit BeginTrans statement. • The CreateProperty method creates a new Property object. demonstrated in Listing 5. click the chapter and section titles. Set recordset = object.Execute options • The OpenRecordSet method. querydef. After the query has been run. Listing 5. you can use the RecordsAffected property to determine how many records were modified. The query must be an action query (see the Type property). In Jet workspaces. and lock is a constant specifying what locking strategy to use. as listed in Table 5. The syntax is somewhat different from when used within a Database or Connection object and is shown in the next code segment. • The Execute method runs the query and takes the syntax shown in the next code example. or TableDef. A parameter is a value that is supplied to a query at runtime and can be thought of much like a .To access the contents. I expand on locking and options strategies later in this chapter when I discuss the RecordSet object. • The Close method closes the QueryDef object and removes it from the collection and from memory. We discussed this method earlier in the chapter in the Properties section. options. options is one or more constants.OpenRecordset (type. as listed in Table 5.8.3 and discussed earlier in the chapter under the Databases topic.7 earlier in the chapter. The object is a valid object variable of type QueryDef. as shown in Table 5.8 earlier in the chapter.3 demonstrated the BeginTrans method. RecordSet.

EMP_NO. EMP_LNAME. Type “? dbCoriolis.Parameters. " & _ "SELECT EMP_DEPT_NO.CreateQueryDef("". If you type “? dbCoriolis.Count”. You first create a QueryDef object to store the query definition and then two Parameter objects to supply the missing information. EMP_SALARY FROM EMPLOYEE WHERE EMP_DEPT = ? AND EMP_GENDER = ? ORDER BY EMP_DEPT. EMP_GENDER. The query itself creates the two parameter objects. Additionally. EMP_LNAME. Private Sub Command1_Click() Dim dbCoriolis As Database Dim qdfDeptGenEmpSal As QueryDef Dim rsReport As RecordSet Dim sCoriolis As String Dim sGender As String Dim iCtr As Integer Dim iDept As Integer ' Change this to reflect your path sCoriolis = "c:\coriolis. the question mark represents a value that will be supplied before the query is actually run. " & _ . You supply the value via a Parameter object. Here. and then displays the results on the screen shown in Figure 5.7. EMP_FNAME You want to be able to run this query. you can use the Direction property to determine whether the parameter is input. Listing 5. EMP_FNAME. as shown on the first highlighted line. or both. output. _ "PARAMETERS Dept Integer. The application (which is also on the CD-ROM) prompts the user to supply a department number and a gender and then displays all the records that fit that criteria. Parameter.CreateQueryDef. the answer will be 2. much as you would with a stored procedure on a database. and the answer is Dept. After executing the statement. The code in Listing 5.6 Demonstration of the QueryDef. You supply the value via the Value property of the Parameter object. you can examine the Parameters collection in the Immediate window. Imagine you have this query stored about your employees: SELECT EMP_DEPT_NO.Parameters (0). EMP_NO. supplying the department number and gender at runtime.CreateQueryDef. EMP_FNAME. Notice in the statement that you use SQL data types when “declaring” the parameter type instead of Visual Basic data types.variable in your program where a value is supplied during execution.Name”. and RecordSet objects.6 creates a QueryDef object with two parameters for department number and gender. You might create a query with a placeholder similar to “Where Cust_No = ?”. Gender Char .mdb" Set dbCoriolis = OpenDatabase(sCoriolis) ' Create a temp QueryDef object ' Use 2 parameters Set qdfDeptGenEmpSal = _ dbCoriolis. This allows you to create a stored query where you do not know in advance what some of the values will be. EMP_GENDER. creates a RecordSet based on the QueryDef.

MoveNext End If End If txtFields(0).Text = rsReport!Emp_No txtFields(3). "Gender".Text = rsReport!Emp_LName txtFields(5).Text = rsReport!Emp_Gender txtFields(2). EMP_SALARY FROM EMPLOYEE WHERE " & _ "EMP_DEPT_NO = [Dept] AND EMP_GENDER = [Gender] " & _ "ORDER BY EMP_DEPT_NO.Parameters("Gender") = sGender ' Open the RecordSet Set rsReport = _ qdfDeptGenEmpSal. vbYesNo + vbQuestion) _ = vbNo Then Exit For Else rsReport.MoveLast rsReport. EMP_LNAME. EMP_FNAME") ' Prompt the user for the values to search for iDept = Val(InputBox("Enter Department to Search For". "Gender Crisis" GoTo GenderBad End If ' Set the parameters qdfDeptGenEmpSal.Text = rsReport!EMP_DEPT_NO txtFields(1).Close dbCoriolis.Text = rsReport!Emp_Salary Next ' Close everything rsReport. vbOKOnly + _ vbExclamation.MoveFirst ' Display the results For iCtr = 0 To rsReport.RecordCount .Close End Sub .1 If iCtr > 0 Then ' Display More? If MsgBox("Display More?"."EMP_LNAME. _ "Department".Close qdfDeptGenEmpSal. "100")) GenderBad: sGender = UCase$(InputBox("Enter Gender to Search For".OpenRecordSet(dbOpenSnapshot) ' Scroll to last record to ensure accurate record count rsReport.Text = rsReport!Emp_FName txtFields(4).Parameters("Dept") = iDept qdfDeptGenEmpSal. "F")) If sGender <> "F" And sGender <> "M" Then MsgBox "Gender must be M or F!".

Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc.Figure 5.7 This application returns all records that match the department and gender entered by the user.

3 earlier in this chapter. Some RDBMSs. can determine the direction of parameters. it . a Connection object. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Parameter object has no methods. which is used to receive the return value from the procedure.6. When you open a RecordSet object. in an ODBCDirect workspace. output. then you must use one of the Visual Basic constants listed in Table 5. such as a column in a query result).Parameters("Gender"). dbParamInputOutput. • The Value property is the actual value stored in the parameter. This is most useful with stored procedures (see Chapter 11). The possible values are dbParamInput. Because it is the default property of the object. you see that you use SQL data types and not the equivalent Visual Basic data types. If you make the assignment directly. which passes information to the procedure and receives information from the server. and dbParamReturnValue. I could have coded the assignments as shown here: qdfDeptGenEmpSal. click the chapter and section titles.6.Value = sGender The RecordSets Collection And RecordSet Object The DAO object with which you will most often interact is the RecordSet object. It does have these properties: • Direction (ODBCDirect workspace only) determines whether the parameter is input. Alternatively. as I did in Listing 5. • The Type property specifies the data type of the Parameter. dbParamOutput. such as in the example in Listing 5. Therefore. which indicates an output parameter (a parameter that the database will supply.Parameters("Dept"). which is the default and indicates an input parameter.6. you can omit it in assignments and references. or both. it is safest to set the direction property prior to executing the procedure. If you examine Listing 5. and not as part of the CreateQueryDef method. The RecordSets collection contains all of the RecordSet objects in a Database object or.To access the contents. such as Microsoft SQL Server. Others (depending especially on the ODBC driver being used) cannot determine the direction.Value = iDept qdfDeptGenEmpSal.

The types of record sets that you can generate follow: • A table-type record set (Jet workspace only) represents one entire base table. • A dynamic-type record set (ODBCDirect workspace only) is the result of a query against one or more tables. It represents either all of the records in a base table (in a table-type record set) or the rows generated from a query. and modify records and move through the records in any direction. Depending on the nature of the data returned. To refer to them. You can add. you generally cannot update a record if the record set does not contain the primary key of that record. as shown in this code: ' Create two object variables Dim rsSet1 As RecordSet Dim rsSet2 As RecordSet ' qdfSample is an existing QueryDef object ' First instance of the RecordSet Set rsSet1 = qdfSample. You can open the same RecordSet object more than once. Depending on whether you use a Data control to access the records. • A forward-only-type record set is identical to a snapshot except that you can only move forward through the records.OpenRecordSet(dbOpenSnapshot) ' Second instance of the RecordSet Set rsSet2 = qdfSample. they are not included in the snapshot until it is closed and reopened. you must create an object variable to reference them uniquely. Use the Updatable property to determine if the record set can be updated. • A snapshot-type record set is not updatable. The record . you can generate up to five types of record sets. This is most useful for data that you need to reference but not change. you may be restricted in whether you can update. When you close it. but this is not a restriction of the record set. You can add. You should use the type that provides the functionality you need but uses the least resources. the rows can consist of one or more fields from multiple tables. it is automatically removed. Use the Updatable property to determine whether the record set can be updated. This is a function of the database and not of the record set. • A dynaset-type record set is also fully updatable and you also can move freely through the records. However.is automatically appended to the collection. meaning that you can have duplicate named RecordSet objects within the same collection. update. if you need to look up records for a report but you don’t need to scroll forward and backward through the records. For instance. The latter provides more flexible access to the records (you can move forward and backward through the records) but also takes more resources. Depending on what fields are actually represented. In other words. such as a postal code lookup table. or delete records. the database may not allow you to update. You can move freely through the records. you should use a forward-only-type record set instead of the snapshot-type.OpenRecordSet(dbOpenSnapshot) The RecordSet object itself is the program’s near-exclusive interface to the database. If other users add or change records on the database. you generally cannot update a record if the record set does not contain the primary key of that record. delete. For instance.

The Properties collection contains all of the Property objects of the RecordSet object. All rights reserved.3 makes extensive use of a RecordSet object in an ODBCDirect workspace. which I discussed earlier in this chapter with the Database topic.8 earlier in this chapter. If there are no records. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. closing them. additions. and referencing them. and deletions made by other users to the database that affect your records. When you open a record set. each of which I discussed earlier in the chapter. The RecordSet object has two collections. Listing 5.6 illustrates the use of a RecordSet object in a Jet workspace.set automatically reflects the changes. the BOF and EOF properties are both true and the RecordCount property is equal to 0. You can examine each Field object to determine the data type of each field in the record set using the Field object’s Type property. The Fields collection denotes all of the fields within the RecordSet object. Most of the listings in this chapter show examples of opening record sets. . Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. This is specified in the type argument of the OpenRecordSet method. the current record is always the first record (denoted by the property AbsolutePosition =0). To specify the type of record set. Use the Value property to examine the value of each field. As shown. the use is nearly identical. use one of the constants listed in Table 5. whereas Listing 5. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

a runtime error results if you then attempt to perform a MovePrevious. If you are positioned on the last record and you delete it. This can only happen in a multiuser environment or when your application opens multiple record sets on the same data. you can invoke the Update method again. but the current record position is before the first record. which is an array of bookmarks of those records on which collisions occurred. BOF and EOF behave differently between Jet workspaces and ODBCDirect . then these two properties (BatchCollisionCount and BatchCollisions) are repopulated. the LOF property may not accurately reflect the fact that you are now beyond the last record. Note that if you have an empty record set and add a record. The AbsolutePosition is zero-based so the highest record number will always be one less than the number of records. In either case. Likewise. • The BOF and LOF properties both return Boolean values that determine whether the current record position is before the first record (BOF) or after the last record (LOF). Visual Basic knows not to re-update those records for which no collision occurred because their RecordStatus is changed to dbRecordUn-Modified once successfully updated. A collision in a batch update occurs when you attempt to update a record that has been altered because you retrieved it. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The properties that are available when using the RecordSet property depend both on the type of workspace (Jet or ODBCDirect) and on the type of record set. click the chapter and section titles. The properties are discussed in turn in the following list: • AbsolutePosition is a Long that returns the current record number. if you do delete the last record in a record set. Use this property along with the BatchCollisions property. there are valid records. This allows your application to then move to each record and correct the problem. Specifying an AbsolutePosition of less than zero or greater than the number of records causes a runtime error. If there are valid records and BOF is True.To access the contents. this property is equal to -1. If no record is current. you should perform a MoveLast to reposition to the new last record in the record set. If BOF is True but LOF is False. • BatchCollisionCount (ODBCDirect workspace only) returns the number of records that did not complete the last batch update. Once the problem is rectified. a runtime error also occurs. Alternatively. you can set the property to move to a specific record number within the RecordSet (except on a forward-only-type record set). The default value is 15. If there are any more collisions. if EOF is True and you then attempt to perform a MoveNext. • The BatchSize (ODBCDirect workspace only) property sets and returns how many statements are sent to the server at a time during a batch update. then there are no valid records. If both values are True. Note that not all ODBC drivers support more than one statement being sent at a time.

Several of the sample applications on the CD-ROM scroll through records until EOF is True. In a Jet workspace. If you create a copy of the record set using the Clone method. both BOF and EOF become False.Edit ' Give them a raise! !Emp_Salary = !Emp_Salary + cRaise ' This is a local update. the database ' is not getting updated yet! . moves to the end of the record set. • The CacheStart property (Jet workspace only) is used with dynaset-type record sets. You should perform a MoveFirst or MoveLast to make the current record valid. If you then rebuild the cache (see CacheSize). in an ODBCDirect workspace. On the other hand.MoveLast ' Scroll through records in descending order Do While Not .workspaces. You can move to that record and then set the CacheStart property equal to the Bookmark property of that record.MoveLast ' And back again rsEmp. indicating that there are no more records.BookMark ' Scroll to the end rsEmp. This allows you to quickly move back to it at any time. The following scrolls backward through the records until BOF is True. You can save your current position in a current record by saving the bookmark to a variable of type Variant. Bookmarkable is a Boolean that determines whether the current record can be bookmarked.BookMarkable = False Then MsgBox "Cannot Save Position!" Else ' Save the position Dim vBookMark As Variant vBookMark = rsEmp. With rsEmp ' Move to last record . BOF becomes False but EOF remains True. and then moves back to the saved bookmark: ' rsEmp is a currently open RecordSet If rsEmp. It allows you to specify which record will be the first record in a cache. . • The Connection property (ODBCDirect workspace only) is a string containing connection parameters and was discussed earlier in this chapter with the Databases topic. It uniquely identifies each record in a record set.Update ' Scroll to prior record .BookMark = vBookMark End If • CacheSize is a Long that sets or returns the number of records from an ODBC data source that will be cached locally.BOF ' Put the record in edit mode . the 40th record will then be the first record in the new cache. the bookmarks are identical. indicating that the current record is still invalid. The following code segment stores the current bookmark. I discussed its usage earlier in the chapter when we discussed the QueryDef object.MovePrevious Loop • Bookmark is a property whose data type is a Variant array of Byte data. Suppose you have 50 records cached locally and you want the new cache to begin with record 40.

In general. this property may not be accurate until you have scrolled through all of the records. • The Name property is a Variant of subtype String that you use to reference the object within the RecordSets collection. • The EditMode property is a Long that contains a constant indicating the current edit state for the first record. • Index (Jet workspace only) is used to alter the order of records. For instance.6.5).AbsolutePosition + 1 & _ " of " & str$(rsEmp. you may want to omit this step because moving to the last record has an adverse impact on performance. but it is not a precise method for moving around. If you search for a record and it is not found. It is essentially the WHERE clause in an SQL query except that the word WHERE is omitted. My recommendation is that you will usually achieve better performance by opening a new record set where the SQL statement includes the WHERE clause. When you first open the RecordSet. Because you can open the same RecordSet object more than once. whereas AbsolutePosition is 0 based. (RecordCount does not reflect any records that have been deleted. RecordCount reflects the actual number of records. assign the RecordSet to an object variable. You can set this property to move within a record set (rsEmp.Per-centPosition=12. If you set this property to the Name property of a valid Index object. as I discuss in Chapter 12 and at various points throughout this chapter. Set the Filter property on an existing RecordSet object to refine which records will be included in the record set. dbEditNone indicates that the record is not being edited. You are better off moving using the Bookmark property.5. • RecordCount is a Long that returns the number of records in the current RecordSet object. the 2K page on which the record is stored is locked as soon as the record is edited. Data1. Jet will use that index on the database to order the records. • NoMatch (Jet workspace only) is a Boolean indicating the success or failure of the most recent Find or Seek operation. In Listing 5. To uniquely identify a given RecordSet object. PercentPosition will be equal to 12. which occurs when the AddNew method has been invoked. If it is not necessary to know how many records there are. dbEditAdd indicates that the current record is a new record that hasn’t been updated to the database. Under pessimistic locking. dbEditInProgress indicates that the current record is currently being edited. Under optimistic locking. See the Find method later in this section. • Filter (Jet workspace only) contains a string restricting what records appear in the record set. but you need to take extra care for concurrency issues. this property is set to True.) The following code updates a Data control’s Caption property to display the current record number and the number of records. If no record has been updated or added. You should evaluate this property each time you perform a Find or Seek. the page is not locked until the record is saved.• The DateCreated and LastUpdated properties (Jet workspace only) return the date and time the base table (not the record set itself) was created and last updated. this value is not valid. which ensures that the RecordCount property is accurate. • PercentPosition returns a single between 0 and 100 that gives an approximate percentage of the relative position within the record set.Caption = "Record " & rsEmp. you can have duplicate Name properties. • The LastModified property is useful to determine which record was the last to be modified in a record set. I illustrate using the MoveLast method to scroll to the last record.RecordCount) & " records" • RecordStatus (ODBCDirect workspace only) is a Long that reflects the current status of . LastModified contains the bookmark of the last record to be altered or added. I recommend optimistic locking. • LockEdits is a Boolean indicating whether pessimistic locking (True) or optimistic locking (False) is in effect. if there are 1.000 records and you are currently displaying record 125.

In an optimistic batch update. the record set type itself may preclude updates (snapshot types. dbOpenDynaset. You also cannot reference any other property of the RecordSet object until this property returns False. I enumerated the five different types of record sets at the beginning of this section. dbOpenDynaSet.MousePointer = vbHourGlass Set rsEmp = conEmp.MousePointer = vbDefault • Transactions (Jet workspace only) is a Boolean that returns True if the RecordSet object supports transaction processing. and dbOpenForewardOnly. This is meaningful only in optimistic batch updating. You cannot access the records in a RecordSet object until the query has finished processing. In general. I recommend using the ORDER BY clause in the SELECT statement itself. • Type sets or returns the RecordSet type. you can determine from each record’s RecordStatus what type of change will be made to the database. The syntax is the same as the SQL ORDER BY clause except that it omits the ORDER BY phrase. Your query may combine updatable and non-updatable tables or perhaps it does not include the primary key of a record. Altering the Sort property of an already opened RecordSet object does not alter its sequence. For instance. The DoEvents statement allows the screen to redraw while the loop is executing: ' Open the RecordSet Screen. • Sort (Jet workspace only) is a string that sets or returns the sort order for a record set. • StillExecuting (ODBCDirect workspace only) is a Boolean that returns True if an asynchronous query is still executing. and Rollback has no effect if the RecordSet does not support transaction processing. you should check the Transactions property before issuing a BeginTrans to ensure that you don’t receive unexpected results. The constants associated with these types are dbOpenTable. You should check this property to ensure that your RecordSet object can be updated.each record in the RecordSet. you must set the property before opening it. dbRecordNew. The constants can be dbRecordUnModified. dbRecordModified. 0. Listing 5.StillExecuting = False Then Exit Do DoEvents Loop Screen. If the property returns False. because other types of record sets cause the record change to be updated to the database immediately.MoveLast dbRunAsync ' Don't do anything until the move is finished Do If rsEmp. CommitTrans. a MoveLast is performed asynchronously. There are any number of reasons why a RecordSet object might not be updatable. • Updatable is a Boolean that returns True if the RecordSet object is updatable. • Restartable is a Boolean that returns True if the RecordSet can be requeried (see the ReQuery method later in this section). Using BeginTrans. Then. dbOpenDynamic. However. or dbRecordDBDeleted. _ dbOptimisticBatch + dbRunAsync) ' Move to the last record rsEmp.OpenRecordSet _ ("SELECT * FROM EMPLOYEE". • UpdateOptions (ODBCDirect workspace only) determines the WHERE clause in an . you will have to close the record set and reopen it to refresh the records. dbRecordDeleted. for example). The following code opens a RecordSet object. The code then loops until the move is complete. dbOpenSnapShot.3 earlier in this chapter contains a program demonstrating transaction processing.

you know that the record has been altered. you might want to include more columns to ensure that no other user has altered the record between the time you retrieved the row and the time you update it. Note. . Use this option if you are concerned about concurrency issues (see Chapter 11 for more details) but only care about those columns that you altered. you only need to specify the primary key in the WHERE clause to uniquely identify the row to be updated. Normally. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.update statement sent to the database. include all columns from the record. Normally. Use dbCriteriaKey if you only want to use the primary columns in the WHERE clause. For instance. if for some reason you are altering the primary key. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. you will want to use dbCriteriaUpdate (which is the default) because it is inherently more efficient. however. whereas the ValidationRule for a RecordSet can reference any field in the record. Read EarthWeb's privacy statement. and it is more efficient (because the WHERE clause is simpler). I discussed these properties earlier in the chapter in the TableDef and Field topics. All rights reserved. However. dbCriteriaTimeStamp will use the primary columns and the timestamp column if there is one. if you specify your WHERE clause. Use this option in a multiuser environment where you absolutely do not want to alter a record if another user has altered it. Copyright © 1996-2000 EarthWeb Inc. Along with any of the five prior constants. dbCriteriaModValues causes the WHERE clause to include the primary columns and any columns that were changed. However. that the ValidationRule for a Field object cannot reference other Field objects. • The ValidationRule and ValidationText properties (Jet workspace only) control the validation criteria and what message to display if the record fails validation. then if the WHERE clause fails. dbCriteraAllCols uses all columns in the WHERE clause. in a multiuser environment. I generally recommend validating each field in the RecordSet independently. This is often just as good as dbCriteriaAllCols because any change to the record will cause the timestamp to be changed. you can also specify either dbCriteriaUpdate to specify that the update be done with an UPDATE statement or dbCriteriaDeleteInsert to specify that the update be done by first deleting the record and then inserting a new one. you normally need to delete the first record and then insert a new record.

It does not add it to the database. the changes are discarded. • CancelUpdate cancels any changes that are pending since the last Update call. If you create a new record and then move to another record. as noted in the discussion of each: • The AddNew method adds a new record to the RecordSet. the changes are lost unless you first invoke the Update method (unless you are performing batch updates). dbUpdateRegular cancels any pending changes that aren’t cached. dbUpdateBatch cancels any changes pending in the cache. (Use the Update method to make the change to the database. new records are always added to the end of the RecordSet. If dbRunAsync was not specified. and it is more efficient than creating a second RecordSet using the CreateRecordSet method. using Cancel causes a runtime error. If there is no unique key.To access the contents. you can also specify an argument. If the user adds a record or modifies a record. this is the OpenRecordSet method) or MoveLast operation. they are set to those values.” • The Cancel method (ODBCDirect workspace only) cancels execution of a currently running asynchronous query (for the RecordSet object. as shown in the following example. rsEmp.) If the fields have default values. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The RecordSet object has a rich set of methods that you use to manipulate fields or data as well as properties. but each RecordSet can have different current records. This is the default. If performing batch updating. Cloning a RecordSet is useful if you need to access the records in different ways at the same time. click the chapter and section titles. Not all methods are available for all record set types. whereas ODBCDirect workspaces generate the message “Invalid Argument. The bookmarks in each copy of the RecordSet are shared. records are added in their proper sort order if one has been specified with the Index property. The new record must have a unique key. In a table-type RecordSet. Jet workspaces generate a “Permission Denied” error. otherwise.CancelUpdate dbUpdateBatch • Clone (Jet workspace only) creates a copy of the current record set. they are set to Null. In a dynaset-type RecordSet. The following example creates a cloned RecordSet and searches it to see if the primary key . You can issue the Clone method on the cloned RecordSet without affecting the original RecordSet and you can issue another Clone on the original RecordSet without affecting the cloned RecordSet.

Text) & _ "'" If rsClone. The current record remains current but is inaccessible. You should close all open RecordSet objects prior to closing the Database or Connection object to which the RecordSet objects belong. The syntax is shown in the following code segment. the CacheSize value is used instead. Changes to the record are placed into the copy buffer and are made permanent after the Update method is issued. startbookmark • The FindFirst.Clone ' Now. It is no longer possible to reference the deleted record. rows is the number of records to retrieve. The following example searches the rsEmp RecordSet object for all occurrences of the last name “Smith”. FindNext.Close • The Close method closes the RecordSet object. • Edit causes the current record to be placed into edit mode. Note that in a non-batch-based RecordSet. You should move to a new record after executing the Delete method.Bookmark = rsEmp.FillCache rows. search through it for the primary key ' txtEmpID is a textbox containing Emp ID rsClone. Instead.NoMatch = False Then ' Duplicate key found MsgBox "Invalid Primary Key!" ' Move to the offending record rsEmp. the value stored in the CacheStart property is used. and the change cannot be undone unless you perform a Rollback after a BeginTrans statement. If omitted. • The Delete method is used to delete the current record in the RecordSet. These methods are not available in ODBCDirect workspaces. The startbookmark argument specifies the Bookmark of the record that should be the first record in the cache. and FindPrevious methods (Jet workspace only) allow you to search the record set for a specific record. If omitted. then you use FindNext to find all subsequent .FindFirst "Emp_ID = '" & Trim(txtEmpID. If the first one is found (using FindFirst). recordset is a valid object variable of type RecordSet (the RecordSet must already be opened). • The CopyQueryDef is used to create a new QueryDef object that is the same as the QueryDef on which the RecordSet object is based. recordset. you should use your SQL SELECT statement to return those rows that you require. FindLast. The search criteria is similar to the SQL WHERE clause except that the word WHERE is omitted. moving to another record without using the Update method causes the changes to be discarded. • FillCache (Jet workspace only) fills all or part of a local cache.LastModified End If ' Close the cloned RecordSet rsClone.of a record that has just been added already exists: ' Assumes rsEmp already exists and that the ' user has just entered a new record Dim rsClone As RecordSet ' Clone the RecordSet Set rsClone = rsEmp. See the discussion of CacheSize and CacheStart earlier in this section.

MoveLast. which causes the move to occur relative to whichever record is referenced by the Bookmark. the current record will be past the last record (in other words. Note that the current record is the one immediately after the last one loaded. BOF or EOF is set to True as appropriate. EOF will be True). An error results if BOF is True and you MovePrevious or if EOF is True and you MoveNext.AbsolutePosition + 1) & "!" Loop End If • GetRows copies one or more rows from a RecordSet into a two-dimensional array of type Variant.occurrences. If the RecordSet contains fewer than 300 rows. The following example moves 300 rows in a RecordSet called rsCusts into an array. no error results. whereas a value less than zero moves backward.NoMatch Then Exit Do MsgBox "Another Smith Found at Record " & _ str$(rsEmp. Dim vBookMark As Variant ' Bookmark the current record vBookMark = rsEmp. Use UBound to determine how many rows were moved. MoveFirst. If there are no current records. MoveNext. The first is the number of records to move relative to the current record. rsEmp. The Move method accepts two arguments. The following example records the current position and then moves to the last record. If you load all of the rows. ' Do not need to declare as array Dim vArray As Variant ' Copy the first 300 rows Set vArray = rsCusts. startbookmark. whereas FindPrevious finds the occurrence of a criteria prior to the current record.GetRows (300) ' Display how many there actually are MsgBox UBound (vArray. and MovePrevious methods move to an absolute record within the RecordSet. It then uses the Move method to move 10 rows ahead of the record that was bookmarked.FindFirst "EMP_LNAME = 'SMITH'" If rsEmp.BookMark ' Move to the last record .FindFirst "EMP_LNAME = 'SMITH'" MsgBox "Smith Found at Record " & _ str$(rsEmp. FindLast finds the last occurrence of a criteria. 2) & " records loaded" ' Display a field MsgBox varray(2. 17) ' Reposition to the first record MoveFirst • The Move. A value greater than zero moves forward. If you otherwise move forward or backward more records than are in the RecordSet.NoMatch = False Then Do rsEmp.AbsolutePosition + 1) If rsEmp. moving causes an error. You may specify an optional argument. where the first subscript refers to the column number (zero-based) and the second subscript refers to the row number (also zero-based). The code also displays the value of the 3rd field in the 18th record.

False is used. I do not recommend this practice (placing more than one query in the Source property) and prefer to use entirely different RecordSet objects for different result sets. If the search uses < or <=. For example. If you do specify more than one query. No error occurs. If you specify pessimistic locking when you place a record in edit mode. batched changes. Otherwise. True forces the changes to be saved. I discussed these two properties earlier in this section. but the BatchCollisions and BatchCollisionCount properties will be set. • The Seek (Jet workspace only) method is roughly equivalent to the Find methods. or >=. any pending batched updates are written to disk. only in Jet workspaces). the changes to the record are written to disk without being cached. then the record (and the entire page the record is on) remains locked until you issue the Update method. force) Previous Table of Contents Next .update (type. The syntax is shown in the following code example. this method returns False. including an example of using the Update method in a multiuser environment. the search starts at the last record in the record set. >. it returns True. • Update causes the contents of the copy buffer to be saved to the RecordSet object. or >=. If there are no more records to be fetched. If you specify dbUpdateBatch. Seek is available only in table-type record sets (and thus. you can only use these comparison operators: =. >. <=. each must be separated by semicolons.Seek=350.MoveLast ' Move to the 10th record beyond the bookmark Move 10. If not specified. dbUpdateCurrentRecord causes any changes to the current record to be updated to disk regardless of whether there are other pending. • OpenRecordSet (Jet workspace only) creates a new RecordSet object. the search starts from the beginning of the record set and returns the first match. The value you are searching for must be part of the current index (see the Index method earlier in this section). I discussed how to use it in the Databases topic earlier in this chapter. which search for a value in a RecordSet. • ReQuery re-creates or refreshes the records in a RecordSet object by re-executing the query. <. you can only search for employee IDs.rsEmp. The following locates employee ID 350: rsEmp. recorset. Further. or Edit method. The force argument optionally specifies whether to force the database to be updated even if another user has changed the record. recordset is a valid object variable of type RecordSet. Delete. If you specify =. if the current index is on the Emp_ID field. If you specify dbUpdateRegular (which is the default). It works only on the current record. indicating that the changes should not be made if another process has made changes to the records since you invoked the AddNew. The optional type argument specifies how to update the data. vBookMark • NextRecordSet (ODBCDirect workspace only) gets the next set of records when more than one SQL statement is specified in the RecordSet object’s Source property (or in the SQL property of the QueryDef object on which the RecordSet is based).

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. . All rights reserved.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

In addition to the brief examples shown in this section. any time the Data control scrolls a record. image. all controls that are bound to it also update their contents. ComboBox. The Data control also offers the convenience of being a target—a data provider. MaskedEdit. Additionally. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Data Control The Data control is the granddaddy of all Visual Basic data access controls and is the only data access control intrinsic to VB.To access the contents. Further. listbox. picturebox. MoveNext. and MSFlexGrid controls can display multiple values at the same time. When a form is opened. To use the Remote Data control or the Active Data control. you first must add them to the toolbox using the Components selection from the Project menu. Listing 5. set the DefaultType property to 2 (dbUseODBC). Data-aware controls include the textbox. which occurs any time there is an action that would cause the current record to no longer be the current record. DataGrid. label. MovePrevious. DataCombo. To force the Data control to create an ODBCDirect workspace. The Data control works only with DAO workspaces. the control provides buttons for the user to navigate a record set. checkbox OLE. click the chapter and section titles. and RichTextBox controls. although it does support both Jet and ODBCDirect. The Data control is flexible in that it provides access to most of the DAO hierarchy that I discussed in first part of this chapter with little coding. if you will—for data-aware controls to bind to. and MoveFirst methods. the Data control automatically creates a RecordSet object and fetches the records from the database. Thus. The Data control provides the interface necessary to automatically add and update records. the DataList. The buttons equate to the MoveFirst.4 earlier in this . It includes events that make it convenient to process records such as the Validation event. The latter two controls come with the Professional and Enterprise editions of VB only.

Any time the user scrolls a record. the RecordSet is automatically populated and. you can create a RecordSet in your code and assign it to the Data control. The Life Of The Data Control When you open a form containing a Data control. The Microsoft documentation states that with a Data control. it is initialized before the form’s Load event. Controls that can be bound to a data source are data aware. Using The Data Control You draw the Data control on a form as you would any other VB control. and then populates the RecordSet and positions itself onto the first record. If you do not like its interface. This has not always been my experience. implying that the RecordCount property of the RecordSet will be accurate. Although you can dock the control to the left or right edges of the form. an untrappable error occurs. I discuss here the key properties of the Data control that I did not discuss earlier in the chapter when reviewing the Data Access Objects: • The Align property allows you to dock the Data control to one edge of the form. giving you the opportunity to edit any changes made by the user as well as the opportunity to prevent the update and even stop the action the user took. bound controls have a DataChanged property. the Validate event fires and you can stop the form from closing. the Data control makes the first record the current record. In Chapter 9. you will have to then supply your own navigation capabilities. which is not meaningful in DAO applications. the control’s Validate event occurs. the ability to bind a control to a field or column in the database. When the form is resized. bound controls have a DataFormat property to customize the display of data (this is new to Visual Basic 6). allowing you to quickly determine which fields of a record have been modified. I also show the DataChanged property being used in the Validate event example later in this section. if the user attempts to close the form. the control is also automatically resized. you do not need to perform a MoveLast. If an error occurs during initialization. I recommend docking on the bottom where the control is out of the way of any toolbars.chapter provides an example of using the Data control. it is rather ugly. However. Also. you will have to experiment with your own database implementation. Where appropriate. Thus. Alternatively. I discuss more advanced uses of these properties as well as the new DataMember property. The Data control creates a Database object and a RecordSet object. Possible values are 0 (no . again. you can make it invisible (by setting its Visible property to False). of course. You bind a control to a data source by setting the control’s DataSource property to the name of the object (such as a Data control) and setting the DataField property to whichever field is to be displayed. When this happens. Bound Controls One of the great conveniences of the Data controls is.

vbEOFActionMoveLast and vbEOFActionEOF ignore the move and move to the EOF invalid record. Copyright © 1996-2000 EarthWeb Inc. 3 (align left).AbsolutePosition + 1) & _ " of " & str$(rsEmp. you must Refresh the Data control. the attempt to move backward is ignored. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Using the Data control. In other words. This is the default action. 1 (align top). The following code snippet placed in the Reposition event will cause the caption to display a “Record x of y records” message every time the user moves to another record: Data1. you can only specify table. All rights reserved. DAO will attempt to create a dynaset. If the user is on the first record (BOF is True) and attempts to move to a prior record. dynaset. To use other types of RecordSet objects. or snapshot. • The Caption property is a string you can use to display information about the database connection (or whatever purpose suits your needs).alignment). you need to create and manipulate the RecordSet object in code. • BOFAction and EOFAction determine what to do if the user attempts to scroll before the first record or after the last record.Caption = "Record " & _ str$(rsEmp. I recommend using vbBOFActionMoveFirst and vbEOFActionMoveLast for the two properties. 2 (align bottom). . If you change the RecordSetType property in code. as shown in the previous example. Similarly. the Validate event is triggered for the current record and the Reposition event is triggered on the now invalid record. or 4 (align right).RecordCount) & " records" • The RecordSetType property determines what type of RecordSet object will be displayed. All the properties and methods of the RecordSet object are available to you by referencing the Data control. vbBOFActionBOF causes the Data control to scroll before the end of the file. When this happens. If not specified. vbBOFActionMoveFirst causes the first record to remain the current record. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.

click the chapter and section titles.To access the contents.RecordSource = "Select * From Employee " & _ "Where Emp_Dept_No = " & datPrimaryRS!Dept_No • The UpdateControls method is used to get the current record in the Data control’s RecordSet object and display the values in all bound controls. if you have a Data control displaying department numbers and names. This is useful. For instance. You place code similar to the following in the master Data control’s Reposition event: datSecondaryRS. This is normally not necessary except when you want to cancel all changes made by a user on the current record and restore the values in the bound controls. from the Validate event itself when you don’t want to create a second call to the event. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Data control has these key methods beyond those that I discussed earlier in the chapter: • The Refresh method rebuilds the results of the RecordSet associated with the Data control. such as passing an invalid QueryDef object or an invalid SQL statement. for instance. If you don’t code for these errors. you will have two Data controls on a form in a master/detail relationship where the contents being retrieved from the detail Data control depend on a value in the current record of the master Data control. When you then use the Refresh method (Data1. When a new record is displayed in the master Data control. The first record in the new RecordSet will be the current record. as when using the RecordSet object’s Update method. whereas response is one of two values that you set: vbDataErrContinue causes the program to continue execution and vbDataErrDisplay causes VB to display the error and act as though . creating a new SQL statement or associating a QueryDef object with it. DAO will rebuild the RecordSet. • The UpdateRecord method saves all changes to the current record to the database. an untrappable error occurs. the secondary Data control fetches the employees in the currently displayed department. you will modify the RecordSet object’s Source property. The Data control also has a number of events that are useful in the client/server environment: • The Error event occurs as a result of any error that occurs while no VB code is being executed—in other words. Most commonly. Often. The syntax for the event is shown in the next code example. you might have a second Data control that fetches all of the employees in that department. If there is an error. when the error occurs at the database.Refresh). VB displays a message and the error is typically fatal. data_error is the error number generated. but the Validate event is not triggered. and bound controls will be updated with the new fields.

An example is if the Data control attempts to open an invalid RecordSet.the error was unhandled. For instance. I included a line of code to change the caption each time a new record is displayed. The save argument is a Boolean that you can evaluate to determine whether any bound data was changed. or Close operation. including when the Data control is loaded and the first record is displayed. the Error event is roughly the same as an active error handler in your code. For instance. The action argument is a constant that you can evaluate to determine what action caused the Validate event to occur.SelStart = 0 txtSalary. This is where you will place code to handle situations unique to each record. there is usually no need to update the database and there is probably no need to validate the data. Beyond that. if the user changes a record and then clicks a move button. you might change an AddNew method to MoveNext.SetFocus txtSalary. If the value is False. You have the opportunity to save the changes or to cancel the operation that triggered the Validate event. the Edit and UpdateRecord methods are invoked. Note that an error that occurs prior to the form’s Load event does not trigger the event. and before a Delete. you can change one action to another. Finally. You can code a Select Case Action statement to determine which action occurred. Table 5.Text) < 0 Then MessageBox "Invalid Salary!" ' Prevent the action Action -= vbDataActionCancel ' Put focus on the error txtSalary. Unload. You cannot invoke any methods of the RecordSet during the Validate event.Text) End If ' See if ID has changed If txtID. The event occurs before a new record becomes the current record (such as when the user clicks one of the move buttons). • The Validate event is where you will place code to ensure that data is valid before being saved to the database. you may want to add code to the Reposition event to calculate the age of an employee based on his or her date of birth each time a new employee is displayed.SelLength = Len(txtSalary.15 lists the possible constants. If the value of Save is True when the event is exited. You can set the value of Action to vbDataActionCancel to cancel whatever action the user took. _ Save As Integer) Select Case Action Case vbDataActionUnload ' Prevent the form from being unloaded Action = vbDataActionCancel Case Else ' Check the Salary If Val(txtSalary. response) • The Reposition event occurs after any record becomes the current record. you can cancel the move to force the user to correct any input errors. before the Update method. The syntax of the event is shown in the next code example. Under the Caption method. causing the change to be saved to the database. Data1_Error (data_error.DataChanged Then MessageBox "Can't Change ID!" Save = False End If End Select . Private Sub Data1_Validate (Action As Integer. For example.

MoveFirst method. MovePrevious method. Read EarthWeb's privacy statement.End Sub Table 5. Find method. Close method. we have covered in depth the Data Access Objects. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. AddNew method. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. and numerous examples. MoveLast method. Copyright © 1996-2000 EarthWeb Inc. Bookmark property set. Delete method. Constant vbDataActionCancel vbDataActionMoveFirst vbDataActionMovePrevious vbDataActionMoveNext vbDataActionMoveLast vbDataActionAddNew vbDataActionUpdate vbDataActionDelete vbDataActionFind vbDataActionBookmark vbDataActionClose vbDataActionUnload Meaning Cancel the operation when the Sub exits. All rights reserved. their use both in code and with the Data control. Read Chapter 4 to see DAO contrasted with other Visual Basic data models. I recommend reading Chapter 11 where I discuss advanced database techniques such as transaction and concurrency management. MoveNext method. If you have determined that DAO is the correct model for you.15 Constants for the action argument of the Validate event. Where To Go From Here In this chapter. Update operation (but not UpdateRecord). Form is being unloaded. .

it may make more sense to avoid DAO altogether and use RDO instead. Figure 6. I discussed the usage of Data Access Objects (DAO). You can also use RDO to access Jet databases. DAO actually communicates with Remote Data Objects (RDO) through a thin layer. However.DAO • Event-driven data access with RDO • Managing asynchronous communications • Transaction and concurrency management In Chapter 5. as I discussed at the end of Chapter 4. click the chapter and section titles.1 How an application communicates with ODBC via the RDO layer. the Jet engine gets . Of course. If you are using ODBC data sources. When you create a DAO ODBCDirect workspace. it makes even more sense for many to move directly to ADO. DAO is most appropriate for desktop database applications. as shown in Figure 6.1. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 6 Remote Data Objects (RDO) Key Topics: • The RDO hierarchy • RDO vs. with or without the Jet engine. for true client/server applications.To access the contents. although you can use it.

released with Visual Basic 5. I review the use of Remote Data Objects. and RDO passes its ODBC function requests to the Jet engine. whereas DAO’s primary emphasis is on the retrieval itself. What Is RDO? RDO version 1 was introduced with Visual Basic 4 and was tremendously improved with RDO version 2. Table 6.loaded as it does in DAO. In this chapter. resulting in potential erratic program behavior. RDO leaves the details of data retrieval to the ODBC driver. . although considerably simpler than DAO. RDO Object DAO Object rdoEngine DBEngine rdoError rdoEnvironment rdoConnection rdoQuery rdoColumn rdoParameter rdoResultset rdoTable rdoPreparedStatement Error Workspace Database or Connection QueryDef Field Parameter Recordset TableDef N/A You will notice two key differences between RDO and DAO: RDO is table and row oriented. You can declare most RDO objects with the WithEvents clause and then use an event-driven model to handle messages and manage asynchronous communications. concentrating on in-code techniques with a review of the Remote Data control (RDC). RDO places more emphasis on procedures and result sets. a given Jet ODBC driver might not support some RDO functions. This environment not only provides more flexibility than you have with DAO. DAO developers will recognize familiar features in RDO: Many of the methods and properties are similar and the object hierarchy. for example. so it is much more efficient than DAO.1 provides a basic cross-reference of RDO objects to their DAO counterparts. Table 6. Additionally. which attempts to map them to Jet functions. This setup is actually more expensive in terms of computing power than simply using DAO. RDO offers a compelling alternative to DAO for those who do not need to use the Jet engine. RDO essentially acts as a thin wrapper around the ODBC API. is still familiar. whereas DAO is file and record oriented.1 Cross-reference of RDO objects to DAO objects. but it also tends to simplify the program logic. Worse. RDO provides an event-driven environment in which to manage the database.

The first instance of the rdoEnvironment object is created whenever the . each rdoQuery object contains an rdoColumns and an rdoParameters collection. and its use is discouraged because its functionality has been incorporated into other objects. RDO objects are arranged in a hierarchy (see Figure 6. you can create the rdoResultset object by using the rdoConnection object’s OpenResultset method. there is only one rdoEngine object. select Project|References. As such. For example. and each rdoParameter object represents a query parameter. The rdoQuery object is similar to DAO’s QueryDef object and represents a query against the database. It allows you to manipulate a row from a query and consists of an rdoColumns collection.0. you can create RDO objects by using the Remote Data control or by using methods of the parent object to create them. The rdoResultset object is similar to the Recordset object in DAO. and rdoPreparedStatements collections. Its functionality—as a database-prepared query or stored procedure—is encompassed by the rdoQuery object. The rdoEngine object also has a collection of rdoEnvironment objects. As with DAO.2). Scroll down the list until you locate Microsoft Remote Data Objects and select it.Overview Of Remote Data Objects Whereas DAO has up to 17 objects (and 16 collections). rdoResultsets. The rdoEnvironment object contains the rdoConnection collection. The rdoEngine is the highest object in the hierarchy. Each rdoColumn object represents a column in the query. you must add it as a reference in your VB project. Otherwise. rdoTable is included mostly for backward compatibility. Thus. Figure 6. which are equivalent to DAO’s Fields and Parameters collections. RDO has just 10 objects (and 9 collections). If you use the RDC. the Remote Data Objects library is automatically loaded.) Like DAO. rdoTables. The rdoEngine object is created automatically.2 The Remote Data Object hierarchy. (From the menu. Each rdoCollection object consists of the rdoQueries. The rdoTable object stores information about an SQL table or view and thus also includes an rdoColumns collection. and it is created as soon as you reference any RDO object. The rdoPreparedStatement is also provided for backward compatibility with RDO 1. RDO maintains information about ODBC errors in the rdoErrors collection. Like DAO. which are the equivalent of the DAO Workspace objects.

The rdoTable object is created automatically whenever a table or view is referenced. TIP The rdoParameter object and rdoParameters collection are only created and populated if the ODBC driver supports the SQLNumParams function. If the ODBC driver does not support parameters or is otherwise unable to parse the query. The rdoParameter object is created automatically for parameter queries. All rights reserved. The rdoError object is created automatically any time an ODBC error occurs. Copyright © 1996-2000 EarthWeb Inc.rdoEngine object is created. . The Remote Data control can create rdoConnection and rdoResultset objects. Additional instances of it are created with the rdoEngine object’s rdoCreateEnvironment method. the rdoParameter objects and rdoParameters collection are not created and a trappable runtime error occurs. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. Refer to your ODBC driver documentation if you encounter any problems. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

you must use the Append method to add these objects to the collections and the Delete method to remove them. Exploring Remote Data Objects In the following sections. Note that you might need to alter the path to the database in the code or configure the ODBC data source name prior to running the examples. so I concentrate on the key aspects of the different properties and methods of each object. If you need more information. All other objects are automatically appended to their collections. The rdoEngine is responsible for creating the rdoEnvironment and rdoError objects. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- RDO Collections As noted. ODBC is exposed via its API. It also provides default values for other objects in the RDO hierarchy. of which there can only be one. The rdoEngine Object The rdoEngine object is the owner of all other RDO objects. I discuss each of the Remote Data Objects and provide examples for their usage. you might want to refer to the Visual Basic documentation. As in Chapter 5. these objects are not automatically appended to collections when created. all RDO objects are maintained in collections except the rdoEngine object.To access the contents. it is not my intention to chop down the rain forest. RDO places user-friendly wrappers around the API in the form of RDO properties and methods. Therefore. It is essentially the RDO library and provides the interface between your VB application and ODBC. click the chapter and section titles. rdoEngine has one event—InfoMessage—which occurs when informational . Visual Basic 6 allows you to create rdoConnection and rdoQuery objects that are not part of a collection. Where I have included a complete program to illustrate a technique. you can find the source code on the CD-ROM. so the collections have only the Refresh method and Count property. However.

No cursor.2 RDO cursor driver constants. • The rdoDefaultUser is a string containing the user name that will be used when an rdoEnvironment object is created. You can individually override these behaviors when you create the other objects: • The DefaultCursorDriver property specifies which kind of cursor driver to be used by default. which are retained for backward compatibility with RDO version 1.2 lists the possible values. If .1. Listing 6. you will get better performance for small result sets using the ODBC driver cursor library. the default is a zero-length string. do not use a cursor. In general. illustrates the use of this technique. unless another one is specified. Use server cursor.Number) & ": " & vErr. For optimistic batch processing. Table 6. This event replaces the need for the ErrorThreshold and rdoDefaultErrorThreshold properties. later in this chapter. you should use the server cursor. unless another one is specified. use rdUseClientBatch. If your result set will have only one row. • The rdoDefaultPassword is a string containing the password that will be used when an rdoEnvironment object is created. Once you declare a reference to the rdoEngine object using the WithEvents clause. To take advantage of the InfoMessage event. Private Sub rdoEng_InfoMessage () Dim sMsg As String Dim vErr As Variant ' Iterate through all errors For each vErr in rdoErrors sMsg = str$(vErr." & sMsg Next The rdoEngine object has a number of properties that you use to set default behaviors of other objects.Description ' Display text of message MsgBox "Info . Description Use server side if available. If not specified. if not. use client side. Constant rdUseIfNeeded rdUseODBC rdUseServer rdUseClientBatch rdUseNone Table 6. If client side is also not available. you can intercept any messages from the database. Use the ODBC driver cursor library. Appropriate only with one row at a time.messages (ODBC SQL_SUCCESS_WITH_INFO return codes) are received from the ODBC driver. The default value is rdUseIfNeeded. Use optimistic batch cursor library. use none. This event is triggered once for each set of messages received. For result sets of more than 100 rows or so. you declare the object using the WithEvents clause: Private WithEvents rdoEng As rdoEngine.

rdLocaleEnglish is used because it does not require a DLL. A value of 0 indicates there is no limit. including the default user and password properties. it is added. It is recommended that you use the ODBC Administrator because the requirements for different ODBC drivers vary. The default is 15. the default is a zero-length string.1. otherwise. provides an example of this method. the Windows locale will be used. password) • The rdoRegisterDataSource essentially duplicates the functionality of the ODBC Administrator in the Windows Control Panel by adding or updating ODBC data source information to the Windows Registry. • The rdoDefaultLogInTimeOut property is a Long that specifies how many seconds to wait when logging on to the server before an error is generated.3 shows the valid values. The name argument must be unique within the collection. Constant rdLocaleChinese rdLocaleEnglish rdLocaleFrench rdLocaleGerman rdLocaleItalian rdLocaleJapanese rdLocaleKorean rdLocaleSimplifiedChinese rdLocaleSpanish rdLocaleSystem Table 6. see the VB help file. a default rdoEnvironment object is automatically created. Messages are generated from a locale-specific DLL. If you specify a locale but the user does not have the correct DLL. Private WithEvents rdoEng As rdoEngine rdoEng. For more information. When you create the rdoEngine object. the object will not be appended to the collection. although you can reference the defaults from the rdoEngine object.rdoCreateEnvironment (name.3 Valid RDO locale constants. it is updated. • The rdoLocaleID property is a Long in which you specify the language in which messages should be displayed.not specified. If it is not supplied. If the name is not specified. Description Chinese English French German Italian Japanese Korean Simplified Chinese Spanish The Windows locale • The rdoVersion property returns a string containing the RDO version number. Table 6. This value will be used if you do not specify a LogInTimeout property for the rdoEnvironment object. . The rdoEngine object also supports these two methods: • rdoCreateEnvironment creates a new rdoEnvironment object and appends it to the rdoEnvironments collection. You must specify the user and password arguments. The syntax is shown in the following code segment. Listing 6. later in this chapter. If the data source name does not exist. user.

All rights reserved. . Read EarthWeb's privacy statement.Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc.

You can use the Remove method to remove any rdoEnvironment object except the default.To access the contents. A default rdoEnvironment object is created when the rdoEngine object is instantiated. The Name property is then determined by the remote data source and is read-only. you can alter its User and LoginTimeout properties but not the Password property. you use the rdoCreateEnvironment method of the rdoEngine object. CommitTrans. If you need more objects. Once the object is created. Because of this. which is the ODBC environment handle. click the chapter and section titles. The user name and password are both empty strings. Conversely. Once the properties of the standalone object are set. you can manage a single transaction across multiple rdoConnection objects using the BeginTrans. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoEnvironments Collection And rdoEnvironment Object The rdoEnvironment object represents a single transaction against a database within the context of a single user/password combination. you can append it to the collection using the Add method. If you issue a CommitTrans or a RollbackTrans . If you create another rdoEnvironment object and do not specify its Name property. All rdoEnvironment objects share a single hEnv property. you can create multiple rdoEnvironment objects if you need to maintain multiple simultaneous transactions. and RollbackTrans methods. which cannot be destroyed. The Name property of the default rdoEnvironment object is “Default_Environment”. there is a single environment handle—a memory pointer to the ODBC session. it is created as a standalone object (it is not appended to the collection). You can close any rdoEnvironment object using the Close method except the default object. In ODBC. All activity against that database will occur within the context of the rdoEnvironment object. This behavior may be an advantage because the object is not exposed to other in-process DLLs.

If not specified. CommitTrans.1. If CursorDriver is not specified. As with the rdoEngine object. It supports three events: BeginTrans.2 earlier in the chapter lists possible values. and many ODBC API functions cannot be performed until other functions are executed. You must allocate the handles in a specific order. and connection) unless you fully understand the ODBC API. if specified. the rdoEngine object’s default cursor driver is used. Each of these events is fired after the corresponding transaction method has completed. determines how many seconds can pass when attempting to log on to the database before an error occurs. To take advantage of these events. fires after the CommitTrans method completes: Private Sub rdoEnv_CommitTrans() MsgBox "Transaction Committed" End Sub Listing 6. TIP Warning! Do not attempt to use ODBC handles (environment. If not specified. later in this section. these values default to the values from rdoEngine. the default value from rdoEngine is used. • The hEnv property is a Long containing the ODBC environment handle. Arbitrary use of the handles and API functions can result in program crashes and computer lockups. and RollbackTrans. illustrates many of the methods and properties of rdoEnvironment. you can program the rdoEnvironment object in an event-driven manner. it cannot be read in your code. for example. you must declare the rdoEnvironment object using the WithEvents clause as shown: Dim rdoEnv WithEvents As rdoEnvironment ' Set a reference to the default object Set rdoEnv As rdoEnvironments(0) The CommitTrans event.in an rdoEnvironment object. • The Password and UserName properties are both strings and specify the user ID and password for the rdoEnvironment object. The rdoEnvironment object supports a number of properties: • The CursorDriver property is a Long specifying what type of cursor to use within the rdoEnvironment. statement. the Password property is write-only. Table 6. Once set. all rdoConnection objects are affected. • The LoginTimeout property. Previous Table of Contents Next .

Copyright © 1996-2000 EarthWeb Inc. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. All rights reserved. Read EarthWeb's privacy statement.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

If you need multiple transactions. click the chapter and section titles.1 The modification of employee salaries. Option Explicit Private WithEvents rEng As rdoEngine Private WithEvents renvCoriolis As rdoEnvironment Private WithEvents rconEmp As rdoConnection Private WithEvents rrsEmp As rdoResultset Private rqEmpSal As rdoQuery Private Sub Command1_Click(Index As Integer) Dim Dim Dim Dim Dim Dim iRtn As Integer sRaise As String sMsg As String sConn As String cSalary As Currency cSaveSal() As Currency Select Case Index Case 0 .To access the contents. Listing 6. Transaction management is discussed in more detail in Chapter 11. Listing 6. you must create multiple rdoEnvironment objects.2 later in this chapter provides a completely event-driven model. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoEnvironment object supports several methods: • The BeginTrans method begins a new transaction. The user is allowed to save or discard changes after all of the salaries are displayed and modified. Listing 6. The scope of the transaction is across all rdoConnection objects within the rdoEnvironment object. The application. Although the application takes advantage of some event-driven concepts.3. a modification of the transaction example in Chapter 5. is shown in Figure 6. as discussed earlier in this section.1 provides an example of a program that manipulates the salary data of employees in the context of a transaction. it uses While Wend loops to determine when an asynchronously called method has completed.

"0") cSalary = !emp_Salary * (1 + Val(sRaise) / 100) .rdoCreateEnvironment _ ("Emp".BeginTrans ' Scroll through rows With rrsEmp ' Set up array to save old salaries ReDim cSaveSal(rrsEmp. _ "Select * from employee") ' Create resultset object Set rrsEmp = . _ rdConcurValues. "coriolis") ' Set properties With renvCoriolis . Options:=rdAsyncEnable) End With ' Wait for connection to complete While rconEmp. rdOpenDynamic. "###.OpenResultset("EmpSelect". "###. _ Connect:="DSN=Coriolis VB Example.".00") & "?" sRaise = InputBox$(sMsg.##0.LoginTimeout = 10 ' Create connection Set rconEmp = .CursorDriver = rdUseOdbc .OpenConnection(dsName:=""." & _ "PWD=Coriolis. rdAsyncEnable + rdExecDirect) ' Idle until the query is complete While rrsEmp. "Raise".CreateQuery("EmpSelect".StillConnecting DoEvents Wend ' Set properties of the connection With rconEmp . "coriolis". _ Prompt:=rdDriverNoPrompt.StillExecuting DoEvents Wend End With ' Begin transaction renvCoriolis.EOF txtFields(0) = !emp_no txtFields(1) = !emp_fname txtFields(2) = !emp_lname txtFields(3) = Format$(!emp_Salary.AbsolutePosition) = !emp_Salary ' Prompt for changes to salary sMsg = "What percent raise for " & !emp_fname & _ " " & !emp_lname & " making $" & _ Format$(!emp_Salary.QueryTimeout = 10 ' Create query object Set rqEmpSal = .UID=Coriolis.##0.' Create environment Set renvCoriolis = rdoEngine.00") cSaveSal(rrsEmp.RowCount) Do Until .

vbYesNo + vbQuestion.RollbackTrans End If ' Display changes (if any) . vbOKOnly + vbCritical Case False MsgBox "Connection Succeeded!" End Select .Close rconEmp.EOF txtFields(0) = !emp_no txtFields(1) = !emp_fname txtFields(2) = !emp_lname txtFields(3) = cSaveSal(rrsEmp.Update End If ' Move to next record .Close End With ' Close the objects rqEmpSal. edit the record .MoveNext Loop . _ "Commit or Rollback") = vbYes Then renvCoriolis.CommitTrans Else renvCoriolis.Close renvCoriolis. _ "Display Salary Changes") = vbCancel Then Exit Do End If . _ vbOKCancel + vbQuestion.Edit !emp_Salary = cSalary ' Save the change .MoveFirst Do While Not .Close Case 1 End End Select End Sub Private Sub rconEmp_Connect(ByVal ErrorOccurred As Boolean) Select Case ErrorOccurred Case True MsgBox "Connection Failed!".MoveNext Loop ' Commit the changes? If MsgBox("Save all changes?".If cSalary <> !emp_Salary Then ' If changed.AbsolutePosition) txtFields(4) = !emp_Salary If MsgBox("Show next record?".

End Sub Private Sub rEng_InfoMessage() Dim sMsg As String Dim vErr As Variant For Each vErr In rEng.2 shows a DSN-less connection. Likewise. The Prompt argument is a constant. from Listing 6.4.Number) & _ ": " & vErr. dsName is the name of the data source or is a zero-length string. you do not need to specify the dsName argument.rdoErrors sMsg = Str$(vErr. Connect is a string specifying connection parameters.3 This program. which makes the data read-write. • The CommitTrans method commits all changes to the database across the entire rdoEnvironment object. the default is False. The syntax of the method is shown in the next code example. but you must still specify an empty string. If the argument is not specified. and controls whether (and to what extent) ODBC connection dialogs are presented to the user. whereas Listing 6. If the user ID and . the CommitTrans and RollbackTrans methods affect all of them. as shown in Listing 6. which I discuss later in this chapter. "ODBC Message" Next End Sub Private Sub renvCoriolis_BeginTrans() ' Put code here for begin trans event End Sub Private Sub renvCoriolis_CommitTrans() ' Put code here for commit trans events MsgBox "Changes Saved" End Sub Private Sub renvCoriolis_RollbackTrans() ' Put code here for rollback events MsgBox "Changes Discarded" End Sub Figure 6. vbOKOnly + vbInformation. as listed in Table 6. Listing 6. • The OpenConnection method creates a new rdoConnection object.1 has an example of the method being used with a DSN. If you supply the DSN parameter in the connect argument.1.Description MsgBox sMsg. the Roll-backTrans method rolls back all changes across the entire rdoEnvironment object. If there are several active connections (rdoConnection objects).1. In the syntax. The read_only argument is set to True if the connection is to be opened as read-only. provides examples of using various Remote Data Objects.

OpenConnection (dsName. prompt for missing parameters. Otherwise. or you will cause an error in your application. All rights reserved. prompt for any missing information. The only setting allowed for the Options argument is the constant rdAsyncEnabled. Prompt. Otherwise. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. rdDriverNoPrompt If not enough connection information. present ODBC connect dialog. Read EarthWeb's privacy statement. Options) Table 6. . Constant Description rdDriverPrompt If no dsName is specified. Copyright © 1996-2000 EarthWeb Inc.1 connects in this manner and then executes a While Wend loop until the connection is established. The code example in Listing 6.4 Valid connection prompt constants. behaves like rdDriverPrompt. read_only.password parameters are not supplied. use default. _ Connect. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. rdDriverComplete If connection includes DSN parameter. Be careful not to attempt to manipulate the rdoConnection object until the connection is established. which causes the connection to be performed asynchronously. rdoEnvironment. they are taken from the rdoEnvironment object and the dsName argument must be supplied. rdDriverCompleteRequired Behaves like rdDriverComplete except doesn’t allow the user to change any information already provided.

" & _ "PWD=Coriolis.2. _ Connect:="UID=Coriolis. you generally can omit the DBF and DBN parameters and substitute an ENG parameter that specifies the name of the server. Connect:="UID=Coriolis. (In the preceding example.VBP): ' Be sure to modify the path! Set rconEmp = . The following code example is a modification of the code shown in Listing 6." & _ "DBF=C:\Examples\Coriolis VB Example.db.1 to connect to the sample Sybase SQL Anywhere database (the entire listing is on the CD-ROM in the project file RDOTransactionsNoDSN. _ Prompt:=rdDriverNoPrompt. If it is not found. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- DSN-Less Connections A problem with ODBC is that you can’t always rely on the user PC having the correct ODBC settings. also performs a DSN-less connection. _ Prompt:=rdDriverNoPrompt.To access the contents.0. It is simpler than the Sybase SQL Anywhere example because my SQL Anywhere server is a standalone product.OpenConnection(dsName:="". Options:=rdAsyncEnable) The equivalent connection with Microsoft SQL Server appears in the next code segment.DSN=''". This tells the ODBC manager which database driver to load and then passes on to that driver the information needed to connect to the database without relying on a DSN. When you specify a DSN (data source name). Listing 6. the ODBC manager looks into the Windows Registry for an ODBC configuration matching that name.Driver=Sybase SQL Anywhere 5. a better answer may be to provide a DSN-less connection string. Set rconEmp = . The parameters you need to supply vary from database to database." & _ "Server=Test.OpenConnection(dsName:="". Options:=rdAsyncEnable) . ODBC may be able to prompt your user for the connection parameters. I need to not only connect to the server.PWD=Coriolis. later in this chapter. but also I have to start the database engine. However.) If you connect to an engine that is already running. click the chapter and section titles.DSN=''".Driver=SQL Server." & _ "DBN=Coriolis.

Listing 6. You can manipulate an rdoConnection object synchronously or asynchronously. asynchronous environment. When you do so. Four command buttons connect to the database. asynchronous RDO application. However. you must use the WithEvents keyword when declaring the object variable: Private WithEvents rconEmp As rdoConnection. begins by creating an rdoEnvironment object. shown in Figure 6.2 The event-driven. You can use the collection’s Add method to do so. it is automatically appended to the rdoConnections collection.2 is an application that uses Remote Data Objects in a completely event-driven. The rdoConnection object generates a half-dozen events that can be valuable in an asynchronous environment. you can also create a standalone rdoConnection object using the EstablishConnection method (discussed later in this section). For the four navigation buttons.4. It also supports event-driven techniques. Nine textbox controls display data. RDO Event-Driven Asynchronous Programming Listing 6. When you do create a standalone rdoConnection object. The application. Option Explicit Private WithEvents rEng As rdoEngine Private WithEvents renv As rdoEnvironment Private WithEvents rcon As rdoConnection Private WithEvents rrs As rdoResultset Private rq As rdoQuery Private Enum query_direction first_time = 0 forward = 1 backward = 2 End Enum Private Sub Command1_Click(Index As Integer) Dim Dim Dim Dim Dim Dim iRtn As Integer sRaise As String sMsg As String sConn As String cSalary As Currency cSaveSal() As Currency Select Case Index Case 0 ' Connect to the database .The rdoConnections Collection And rdoConnection Object The rdoConnections collection contains all rdoConnection objects within an rdoEnvironment object. I used the Image control. You normally create the rdoConnection object using the OpenConnection method of the rdoEnvironment object. it is not appended to the collection automatically. disconnect from the database. I use the outer buttons as BOF and EOF buttons to move to the first and last records. run a query. To take advantage of event-driven processing. and close the application. I use the inner two buttons to move backward and forward one row at a time.

line_item.ord_cust_no " & _ "And line_item.Enabled = True Case 3 End End Select End Sub Private Sub Form_Load() ' Set the query ' Enable/disable command buttons Command1(1). " & _ "customer. line_item.QueryTimeout = 3 ' Create resultset object Set rrs = ." & _ "DBN=Coriolis.line_item_no.Enabled = False Command1(2).PWD=Coriolis.DSN=''"." & _ "Driver=Sybase SQL Anywhere 5.Enabled = False Image1(2). line_item.cust_fname." & _ "DBF=C:\ \Examples\Coriolis VB Example." & _ "item. Options:=rdAsyncEnable) Case 1 ' Run query Set rq = rcon. rdOpenDynamic.cust_no = orders.ord_date " & _ "From customer.item_no = line_item. rdAsyncEnable + rdExecDirect) End With Case 2 ' Disconnect rcon.Enabled = False ' Enable connect button Command1(0).OpenConnection(dsName:="". _ "Select customer.line_ord_no = orders.db.cust_lname.line_price. customer.Close ' Disable movement buttons Image1(0).cust_fname.OpenResultset("Test".0. customer. _ rdConcurValues. " & _ "orders. orders.Enabled = False .line_no") ' Set properties of the connection With rcon .line_qty.ord_no.Caption = "Connecting …" Command1(0).item_desc.Enabled = False Image1(1). line_item. orders " & _ "Where customer. " & _ "line_item. item. _ Prompt:=rdDriverNoPrompt.line_total. " & _ "orders.Enabled = False ' Be sure to change path in your application! Set rcon = renv.cust_lname.line_item_no " & _ "Order By customer.ord_no.cust_no.ord_no " & _ "And item. _ Connect:="UID=Coriolis.CreateQuery("Test". " & _ "line_item.Enabled = False Image1(3).

MoveLast rdAsyncEnable ShowRec first_time End Select End Sub Private Sub rcon_BeforeConnect(ConnectString As String.CursorDriver = rdUseOdbc .MoveFirst ShowRec first_time Case 3 rrs.Close End Sub Private Sub Image1_Click(Index As Integer) Select Case Index Case 0 ShowRec backward Case 1 ShowRec forward Case 2 rrs.Enabled = Image1(2).Enabled Command1(3).LoginTimeout = 10 End With End Sub Private Sub Form_QueryUnload(Cancel As Integer. "coriolis") ' Set properties With renv .Command1(0).Enabled = Image1(3). "coriolis".Enabled Image1(0).Close renv.Enabled = Image1(1). _ Prompt As Variant) Dim sMsg As String sMsg = "About to connect to the database using" & vbCrLf & _ . _ UnloadMode As Integer) ' Ensure all objects are closed rq.rdoCreateEnvironment _ ("Test".Enabled = = True = True False False False False ' Force the form to display Show ' Create environment Set renv = rdoEngine.Close rcon.

Enabled = True Caption = "Connected" End Select End Sub Private Sub rcon_Disconnect() Dim iCtr As Integer MsgBox "Disconnected" ' Enable connect button Command1(0).Enabled = True ' Disable move buttons Image1(0).Enabled = True Caption = "Connect Failed!" Case False MsgBox "Connection Succeeded!" ' Enable query button Command1(1).rdoErrors sMsg = Str$(vErr.Enabled = False ' Clear all text boxes For iCtr = 0 To 8 txtFields(iCtr).Text = "" Next End Sub Private Sub rcon_QueryComplete(ByVal Query As RDO. vbOKOnly + vbCritical Dim sMsg As String Dim vErr As Variant For Each vErr In rEng.rdoQuery. vb0konly + vbInformation End Sub Private Sub rcon_Connect(ByVal ErrorOccurred As Boolean) Select Case ErrorOccurred Case True ' Connect failed! MsgBox "Connection Failed!".ConnectString MsgBox sMsg. _ ByVal ErrorOccurred As Boolean) Select Case ErrorOccurred Case True Dim sMsg As String .Number) & _ ": " & vErr.Enabled = False Image1(1).Description MsgBox sMsg. vbOKOnly + vbInformation Next ' Reenable connect button Command1(0).

SQL Next Case False MsgBox "Query Successful" ' Enable movement buttons Image1(0).Dim vErr As rdoError For Each vErr In rdoErrors sMsg = Str$(vErr. _ vbYesNo + vbQuestion.rdoQuery. vbOKOnly + vbInformation.Enabled = True Image1(1).AbsolutePosition = rrs.Number) & _ ": " & vErr.Description MsgBox sMsg.MovePrevious End Select ' Display all fields With rrs txtFields(0) = !cust_no txtFields(1) = !cust_fname txtFields(2) = !cust_lname txtFields(3) = !ord_no txtFields(4) = !ord_date txtFields(5) = !line_item_no txtFields(6) = !item_desc txtFields(7) = !line_qty txtFields(8) = !line_price End With End Sub Private Sub rcon_QueryTimeout(ByVal Query As RDO. Query. _ Cancel As Boolean) ' Query timed out Dim iRtn As IFontDisp iRtn = MsgBox("The query timed out! Keep working?".Enabled = False Command1(2).AbsolutePosition = 1 Then Exit Sub rrs.Enabled = True Image1(2). "Query Error") .Enabled = True ' Display first record Call ShowRec(first_time) End Select End Sub Private Sub ShowRec(direction As Integer) Select Case direction Case first_time ' Do nothing Case forward If rrs.RowCount Then Exit Sub rrs.Enabled = True Image1(3).MoveNext Case backward If rrs.Enabled = True Command1(1).

If iRtn = vbNo Then Cancel = True Else Cancel = False End If End Sub Private Sub rEng_InfoMessage() ' This code illustrates the interception of any informational ' messages from ODBC Dim sMsg As String Dim vErr As Variant For Each vErr In rEng. I iterate through all the rdoError . "ODBC Message" Next End Sub Private Sub renv_BeginTrans() ' Put code here for begin trans event ' The application does not actually perform updates End Sub Private Sub renv_CommitTrans() ' Put code here for commit trans events MsgBox "Changes Saved" End Sub Private Sub renv_RollbackTrans() ' Put code here for commit trans events MsgBox "Changes Discarded" End Sub Figure 6. vbOKOnly + vbInformation. In this event. The Run Query and Disconnect buttons and the navigation buttons are disabled. If the connection is successful.rdoErrors sMsg = Str$(vErr. If the query does not complete in three seconds. the QueryTimeout event is fired and the user has the choice of allowing the query to continue working. The rdoConnection object’s Connect event is used to determine whether the connect was successful. If not. The QueryTimeout property is deliberately set to a short interval: three seconds. all error messages are displayed.Description MsgBox sMsg. Of the four command buttons. the application attempts to perform a DSN-less connect to the database.Number) & _ ": " & vErr. When the user clicks Run Query. the Connect button is disabled and the Run Query button is enabled. the application creates an rdoQuery object composed of a join of three tables and then attempts to open an rdoResultset object using the rdoQuery object as the source. When the query is completed. If not.4 Data is displayed in the event-driven. When the user clicks the Connect button. asynchronous query application. I evaluate whether the query ran successfully. the QueryComplete event of the rdoConnection object is triggered. only Connect and Close are enabled.

you should check messages in the rdoErrors collection. For example. All database activities. The Connect button is re-enabled. all objects are closed and the navigation and Disconnect buttons are disabled. In this manner. occur in an asynchronous manner. The completion of a query does not necessarily indicate it was successful. The Run Query button is disabled and the Disconnect button is enabled. For instance. If the user clicks the Disconnect button.2. The two parameters passed to the event are ConnectString and Prompt. Therefore. The Connect event might also provide an opportunity to display and evaluate any informational messages added to the rdoErrors collection.objects. prevent the connection from occurring. I did not include the capability for updating the data because this is a query-only application. including the MoveLast method. No arguments are passed to this event. The user can now use the navigation methods to move forward and backward through the data. as shown in the following example. • The QueryTimeout event is triggered when a query. It provides an opportunity to. various other events monitor database RDO operations. In Listing 6. You might place code in this event to perform housecleaning chores such as closing the rdoEnvironment object. the query will continue running for as many seconds as . The navigation buttons are also enabled. I use the Connect event to ensure a successful connection to the database. you do not want to execute a query against the database until you have successfully connected. _ Prompt As Variant) MsgBox ConnectString End Sub • The Connect event is fired immediately after the connect has completed. the running query will automatically cancel. If an error was encountered. Cancel defaults to True. If the query was successful. for example. • The QueryComplete event is triggered whenever any query executing within the rdoConnection object is completed. two arguments are sent to the event: Query is a reference to the query that just completed. If you set the value to False. ErrorOccurred is a Boolean that returns True if an error was encountered. your application may automatically connect to the database but need to occasionally work in “offline” mode. • The Disconnect event is triggered when the connection is successfully closed. the QueryComplete event determines whether to display data and enable the navigation buttons in the application. has been running for the number of seconds specified in the QueryTimeout property. Two arguments are passed: a reference to the query that is running and a Boolean Cancel that indicates whether to cancel the query. The use of the event-driven model replaces the awkward coding in Listing 6. so if you don’t code this event.2. whether synchronous or asynchronous. The BeforeConnect event provides an opportunity for you to ask the user whether he or she wants to proceed with the connect.1 where I performed a loop after calling an asynchronous method waiting for the method to complete. The following example displays the connect string prior to connecting: Private Sub rcon_BeforeConnect(ConnectString As String. This can be valuable when your program needs to know when it is okay to manipulate the connection. control returns to the program as soon as database events occur. I call a general procedure to display the first record. • The BeforeConnect event is triggered immediately before an attempt is made to connect to the database. Throughout the listing. In Listing 6.

Copyright © 1996-2000 EarthWeb Inc. The default is False. meaning that the query will not be prevented from running. and Cancel is a Boolean that allows you to stop the query from running. All rights reserved. Two arguments are passed: Query is a reference to the query that is about to execute.specified in the QueryTimeout property. _ Cancel As Boolean) Dim iRtn As Integer ' Change the query Query. An example follows: Private Sub rcon_WillExecute (Query As rdoQuery.SQL & _ "?". You can use this event to prevent an update of the database or to change the query. .SQL = "Select * From Employee" ' Give the user a chance to cancel the query iRtn = MsgBox ("Run the query: " & Query. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. The event occurs at the rdoConnection level for any query within the connection. • The WillExecute event occurs immediately before a query is to run anywhere in the rdoConnection. True has the effect of canceling the query and will also generate a runtime error indicating that the query was canceled. vbYesNo + vbQuestion) If iRtn = vbNo Then ' Cancel the query Cancel = True End If End Sub Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement.

no logging is done. On the other hand. short queries can default to 1 second. the value will default from the rdoEnvironment object’s CursorDriver property. • The LastQueryResults property returns a reference to the rdoResultset associated with the last query that successfully completed. setting this value too low can adversely impact performance by increasing network and database traffic. If not set (or set to an empty string). • The LogMessages property is a string used to set ODBC logging. the value will default from the rdoEnvironment object. For longer queries. • The hDbc property is a Long that contains the ODBC connection handle. I discussed the requirements for this property earlier in the chapter in the OpenConnection method of the rdoEnvironment object. In general. ODBC messages are written to that file. . consider increasing this value to minimize the number of hits on the database server. click the chapter and section titles. If not specified. if the setting is too large. If the value is set to a valid file path and name. If not specified. The default is 1. • The CursorDriver property specifies the type of cursor to use. • The LoginTimeout property is a Long specifying how many seconds to allow for logging on to the database server before generating an error.000 (1 second). Do not use this handle if you are not familiar with the ODBC API. • The Connect property specifies the database connection parameters. the user may wait longer for the data. Because Visual Basic must poll the database to determine whether the query is complete.To access the contents. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoConnection object has a number of properties you use to manipulate the connection: • The AsyncCheckInterval property is a Long that specifies how many milliseconds Visual Basic should wait before polling the database to determine whether an asynchronous query has completed.

Listing 6. Although you may be using ODBC version 3. If the value is larger or smaller than that permitted by the database. All rights reserved. no other properties of the object are available. the minimum value allowed by the database is used instead.5. Likewise. inserted. . While this property is False (the asynchronous operation is not complete). this property will reflect version 2. Generally. most databases require that you delete the original row and add a new row. • The RowsAffected property returns the number of rows deleted.1 used this property to determine when a query had finished. whereas Listing 6. and RollbackTrans methods will have no effect. • The StillExecuting property determines whether an asynchronous operation is completed. • The Transactions property is a Boolean that indicates whether the connected database supports transaction processing.1 showed the use of this property to determine when a connection was completed. you are better off using rdOperationUpdate because it entails less work on the database server and less network traffic. CommitTrans. Read EarthWeb's privacy statement.2 used an event-driven method (Connect) to signal the completion of the connection. • The UpdateOperation property is used for optimistic batch updates within the connection. the value defaults from rdoEnvironment. If this property returns False. Setting the LogMessages property is the same as using the Log function in the ODBC Administrator applet in the Control Panel. However. and you should minimize the amount of logging you do because ODBC operations are much slower while performing logging. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Listing 6. whereas Listing 6. • The QueryTimeout property specifies how many seconds to wait before an active query within the connection times out.You should let only one application at a time perform logging. or updated in the most recent query within the rdoConnection object. Copyright © 1996-2000 EarthWeb Inc. if the underlying ODBC driver conforms to ODBC version 2.2 used the QueryComplete event. If not specified. the database does not support transaction processing and the use of the BeginTrans. It is a Long set to either rdOperationUpdate (use an Update statement for each row being changed) or rdOperationDelIns (use a Delete statement followed by an Insert). Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. if you need to change the primary key of a row. • The Version property returns the ODBC version number to which the ODBC driver conforms as a string.

they must be set prior to using the object (that is. If these statistics are not up-to-date. discussed earlier in this chapter. Source is a string containing either an SQL . click the chapter and section titles. the object is not automatically appended to the collection. The syntax appears in the next code example. against the database. The rdoQuery object is not associated with any rdoConnection object until you set the ActiveConnection property of the rdoQuery. When preparing a query. options] • The Execute method runs a specified query. rdoConnection. The syntax follows. the scope is environment-wide. The syntax for the method is shown in the following code example. If the arguments are not set when the object is created.SQL] TIP When To Prepare A Statement A good rule of thumb when determining whether to prepare a statement is that the amount of benefit derived is inversely proportional to how well the database is maintained. rdoConnection. and the optional SQL argument is the SQL property to be assigned to the object. You can only invoke this method while the StillExecuting property is True. including update queries.To access the contents. The Name argument is the Name property to be assigned to the object. if the statement is executed dynamically—many RDBMSs use an optimization strategy more akin to generalized rules. CommitTrans. the database’s query optimizer uses various statistics to plan an access path.CreateQuery Name [.EstablishConnection [prompt. If you create an rdoQuery object using the DIM statement (as I do in Listings 6.2). the preparation process could actually hurt the query performance. • The Close method closes the rdoConnection object. before executing the query). • The Cancel method is used to cancel an asynchronous connection. If you don’t prepare a statement—in other words. • The EstablishConnection method is used to connect to the server (if you did not do so when you created the rdoConnection object). • The CreateQuery method is used to create a new rdoQuery object and add it to the rdoQueries collection. and RollbackTrans methods perform transaction management chores.1 and 6. Although you can manipulate transactions at the connection level. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoConnection object supports several methods: • The BeginTrans. read_only. The arguments are the same as those for the OpenConnection method of the rdoEnvironment object. Check your specific database’s documentation for more details. as discussed earlier in the chapter when I discussed the rdoEnvironment object.

Valid locktype constants are shown in Table 6.6. You can execute row-returning queries and stored procedures using Execute. • The OpenResultset method is similar to DAO’s OpenRecordset. The Options argument can contain one or both of the following constants: rdAsyncEnable causes the operation to run asynchronously. rdExecDirect causes the query to run without first being prepared on the database. Constant rdOpenForwardOnly rdOpenKeySet rdOpenDynamic rdOpenStatic Constant rdConcurReadOnly rdConcurLock rdConcurRowVer rdConcurValues rdConcurBatch *For some databases. source is either an SQL statement or the Name property of an existing rdoQuery object. If the query will run only once or if it is a short query. it will usually run marginally faster if you specify rdExecDirect. See your ODBC driver documentation for more details. Open a keyset-type result set. In this context. source is the only mandatory argument. Description (Default) Use read-only.5. these are the only valid lock types for static-type result sets. later in this chapter. locktype is used in multiuser environments for con-currency control. Server-side cursors do not allow more than one statement.5 Valid rdoResultset type constants. Description (Default) Open a forward-only-type result set. Instead. Listing 6. Set resultset = rdoConnection. If the query is likely to run several times or if it is longer in duration (more than three seconds or so).statement or the name of an rdoQuery object. rdAsyncEnable causes the result set to be opened asynchronously. rdoConnection. type. as listed in Table 6.6 Valid rdoResultset lockedit constants.3. rdExecDirect causes the statement to be executed directly instead of first being prepared on the database. I illustrate this method using an existing rdoQuery object as the data source. client-side cursors may allow the use of more than one statement. however. option]) Table 6. preparation is similar to compilation. Open a dynamic-type result set.* Use pessimistic concurrency.* Use optimistic batch updating. In both Listings 6. type is a Long with which you specify the type of result set to open. locktype. . Use optimistic concurrency based on row values. Use optimistic concurrency based on row IDs. It creates a new rdoResultset object using the syntax shown in the next code example. Options NOTE The source argument of an rdoResultset object can contain more than one SQL statement with some cursor models. uses this method to execute an action query. you might get somewhat faster performance by not specifying rdExecDirect. I discuss more advanced aspects of transaction management—including concurrency issues—in Chapter 11. it is not a good idea because there is no way to get the return values. you should use an rdoResultset for these types of tasks. Table 6. but depending on the ODBC driver.OpenResultset _ (source[.2.Execute Source. option is a Long in which you may specify the constants rdAsyncEnable or rdExecDirect. For specifying an rdoQuery object.1 and 6. the name is case-sensitive. Open a static-type result set.

Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . Copyright © 1996-2000 EarthWeb Inc. All rights reserved.

When you use it. You can also encounter a situation called a deadly . The safest locking is pessimistic. click the chapter and section titles. You cannot update any rows. where the entire table is locked. When you open a result set as read-only. if too many pages are locked. as are your options. Membership in the result set is not fixed. of course. no other user will be able to access any other row on that database page. More On Concurrency And Locking I discussed some of the issues involved in concurrency management as they relate to DAO in Chapter 5. The keyset-type result set is updatable and movement forward and backward is unrestricted. there are no concurrency issues. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- More On RDO Result Set Types As with DAO record sets. in which case it might escalate the lock to a table lock. The forward-only-type result set allows only forward movement through the result set. For RDO. the issues are similar. You can use columns from more than one table. It is most useful when you need to quickly access certain data with no dynamic forward and backward searching. Changes made by other users are not detected until the object is closed and reopened or until it is refreshed. you want to choose the RDO result set type that is most efficient while still meeting your requirements. the entire page of the row being updated is locked as soon as it is placed into edit mode. A static-type result set has fixed membership of the rows and columns.To access the contents. the database begins to run out of resources. However. Membership in the result set is fixed. Further. because you will not be updating the data.

A trappable error is then generated.Bookmark). for some examples of batch updating. which means only the row being affected gets locked. rdConcurValues causes a column-by-column comparison of all values on the row to be updated. the page is not locked until the row is about to be updated. if one user has page 1 locked. the ODBC driver might not fully support this feature. the size of the page is a function of both the ODBC driver and the back-end database. If an update fails because another user has altered a record. which does not guarantee that changes made by other users will be detected. All the updates are batched together and sent to the database if the database and ODBC driver support it. With some databases. the size might be 4K. Another user might have page 2 locked. However. I discuss these properties later in the chapter when I discuss the rdoResultset object. When you do so. whereas with others. (I discuss batch updates in more detail later in this chapter. ODBC will generate an informational message that is appended to the rdoErrors collection. If another row identifier is not available. The advantage is that you can use the UpdateCriteria property to fine-tune your Where clause. set the BatchSize property to 1.Bookmark = rdoResultset. because the database has to do extra work. In a worst-case scenario. you lose . Note that. If you invoke a certain type of lock and the ODBC driver does not support it. ODBC will attempt to use a row identifier. the page size might be an option set when the database was created. the page size may be 2K (2. For instance. Some databases support true row-level locking. only the row’s primary key is used. such as a timestamp column (if available). which changes the row to reflect the changes made by the other user. to determine whether the row has changed. another user has modified the row. To do so. later in this chapter. which causes the updates to be sent one at a time. Again.048 bytes). The two processes wait until one lock times out. Unfortunately. Check your database or ODBC documentation for more details. With optimistic locking.) Even if your database does not support processing of more than one update at a time. a trappable error occurs. the database might not release that lock until it can access page 2. See Listing 6. If any values are different than when the row was retrieved.embrace where two processes lock each other out. the DBA might have to manually end a transaction.3. you cannot guarantee that another user hasn’t modified the row since you retrieved it. unlike with Jet. another level of locking is substituted. You might want to use rdConcurBatch for performance reasons. there is a performance penalty with rdConcurValues. For still others. and the database terminates one of the transactions. With rdConcurRowVer. and the database cannot release it until it can access page 1. This feature is a safer option than rdConcurRowVer when a timestamp column is not available. in a true ODBC environment. My recommendation is to add a timestamp column when practical and use this option where concurrency is an issue. You can set the current row’s Bookmark property to itself (rdoResultset. you might still want to use rdConcurBatch.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement.any changes that your program made (though you can save them to some variables first). All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

It is removed when you close it. perhaps with a new query. If you set this property to Nothing. you can manipulate the rdo-Resultset object in an event-driven manner if you create a reference to it using the WithEvents clause. Note that because a number of procedures will be referencing the object. The rdoResultset object is a representation of all rows returned from a query. You can append the result set to a different collection by changing the ActiveConnection property to another valid rdoConnection object. You manipulate rdoResultset in much the same manner that you manipulate the Recordset object under DAO. you should declare it at the module level. You can create an rdoResultset object using the OpenResultset method of the rdoConnection. I prefer the use of Private. As with several other RDO objects. the two keywords are synonymous. It contains the rdoColumns collection. the result set is still created (the BOF and EOF properties will be False).To access the contents. or rdoTable objects. When you create an rdoResultset object. Because rdoColumns is the default property. Although you can declare it using the Dim keyword. but Private is more precise: Private WithEvents rrs As rdoResultset. At the module level. Even if the query returns no rows. I discussed the use of this method as well as implications for certain arguments earlier in the chapter in the rdoConnection section. click the chapter and section titles. omitting the reference to the collection and simply providing the Name property of the appropriate rdoColumn object. you can specify a column name. Conversely. it is automatically appended to the rdoResultsets collection. the rdoResultset is removed from the collection but does not free its resources. rdoQuery. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoResultsets Connection And rdoResultset Object The rdoResultsets collection contains all rdoResultset objects within an rdoEnvironment object. The events that the rdoResultset object supports follow: • The Associate event is triggered after you use the ActiveConnection property to associate the result set with a new rdoConnection object. the Disassociate event is triggered when an rdoResultset object is set to . You might want to place some code in this event to initialize the result set.

) rdUpdateFailed tells RDO that the update failed. which you would trap in your Update method. • The ResultCurrencyChanged event is essentially the same as DAO’s Reposition event. Read EarthWeb's privacy statement. it is your program’s responsibility to do so. If you set the ReturnCode argument to rdUpdateSuccessful. there are no new results). Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. RDO will also not attempt to update the database. Private Sub object. delete. You use it to tell RDO what you have done or simply to modify RDO’s behavior. (If doing so. The WillAssociate event is triggered immediately before a result set is associated with a new connection. it will not change the status of the rows or columns either. RDO will not attempt to perform the update and will not modify any column or row statuses. and you normally use it when you are performing optimistic batch updates. The default is rdUpdateNotHandled. You can place your own code in this event to override the default behavior of RDO. rdUpdateWithCollisions gives you an opportunity to prevent an update without changing row and column statuses. It has one argument. The WillDisassociate event occurs immediately before a result set is to be disassociated from a connection.WillUpdateRows(ReturnCode as Integer) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. even if the method returns False (that is. This event provides a good place to perform data validation when you are not using the Remote Data control. However. ReturnCode. • The RowStatusChanged event is triggered immediately after any edit. • The ResultsChanged event happens after any use of the MoreResults method. it is important to modify row and column statuses in code for those updates that were successful. It is triggered by any change in the current position with the rdoResultset. which tells RDO to go ahead and handle the update using its own rules. However. . RDO will not attempt to perform the updates itself and will set the status of all rows and columns to rdRowUnModified and rdColUnModified. All rights reserved. You can ascertain the actual status of the row using the Status property.Nothing and is disassociated from an rdoConnection object. or insert. If you set the ReturnCode to rdUpdateWithCollisions. Copyright © 1996-2000 EarthWeb Inc. • The WillUpdateRows event occurs immediately before any update to the database is to occur. RDO will generate a runtime error. as shown in the following sample code.

If it is True. click the chapter and section titles. Those rows that are successfully . • The BatchCollisionCount property returns the number of records that did not complete the last batch update. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoResultset object has a rich set of properties you can use to monitor and manipulate the result set: • The AbsolutePosition property returns the current record number within the result set. See my discussion of the Associate event earlier in this section for more information. Setting this property to Nothing disassociates the result set from the connection. Note that unlike DAO’s AbsolutePosition property. This can only happen in a multiuser environment or when your application opens multiple record sets on the same data. you can invoke the Update method again. If no record is current. ' Move to the third row rrs. and attempting to reference it will result in an error. This combination of properties allows your application to move to each row and correct the problem. Use this property along with the BatchCollisionRows property. A collision in a batch update occurs when you attempt to update a record that has been altered since you retrieved it. which is zero-based. You can also use this property to set the current row to a particular row number. as shown in the next code segment.To access the contents. Once the problem is rectified. these two properties (BatchCollisionCount and BatchCollisionRows) are repopulated. If there are no rows.AbsolutePosition = 3 • The ActiveConnection property returns a reference to the rdoCon-nection object to which this rdoResultset belongs. If there are any more collisions. AbsolutePosition is -1. the AbsolutePosition property should be valid. You can avoid this problem by checking the Bookmarkable property. then AbsolutePosition is undefined. which is an array of bookmarks of those records on which collisions occurred. RDO’s AbsolutePosition property is one-based: You cannot use this property to move within a dynamic-type or forward-only-type result set.

and related properties and methods.OpenConnection(dsName:="". _ "Coriolis".rdoCreateEnvironment("Env2".3 shows batch updating and the resolution of collisions using the BatchCollisionCount. _ Prompt:=rdDriverNoPrompt. Listing 6.3 The RDO batch update demonstration program. The application simulates a second user by creating a new query object in another connection and environment. which effectively loses your changes. Figure 6. set the default cursor lbStatus = "Creating RDO Engine …" rdoEngine.rdoEnvironments(0) ' Create second environment Set rEnv2 = rdoEngine. Listing 6. Option Explicit Dim WithEvents rEng As rdoEngine Dim WithEvents rEnv1 As rdoEnvironment Dim WithEvents rEnv2 As rdoEnvironment Dim WithEvents rCon1 As rdoConnection Dim WithEvents rCon2 As rdoConnection Dim rq1 As rdoQuery Dim rq2 As rdoQuery Dim WithEvents rrsEmp1 As rdoResultset Private Sub cmdUpdate_Click() Dim sConn As String Static cRaise As Currency Dim sMsg As String If cRaise = 0 Then cRaise = 1 Else ' So the user can change the data back cRaise = cRaise * -1 End If ' In order to do batch updating. _ . Another method to see the new values is to access the rdoColumn object’s BatchConflictValue property. "Coriolis") ' Now. It sends a single action query to the database using the Execute method to alter a row.rdoDefaultCursorDriver = rdUseClientBatch ' Use default environment for first environment lbStatus = "Creating 2 Environment Objects …" Set rEnv1 = rdoEngine.5 shows the application. connect to the database ' Be sure to set your own path! lbStatus = "Connecting to the database …" Set rCon1 = rEnv1. The application refreshes the row in question to display the values as changed by the other user. BatchCollisions.updated have their row and column statuses changed so RDO will not attempt to update them again. thus forcing a collision to occur.

_ "Select * From Employee") ' Set properties of the connection With rCon1 . _ Prompt:=rdDriverNoPrompt.QueryTimeout = 3 ' Create resultset objects Set rrsEmp1 = .StillConnecting DoEvents Loop ' Create the query object lbStatus = "Opening Result Set …" Set rq1 = rCon1." & _ "DBN=Coriolis." & _ "DBF=C:\ \Examples\Coriolis VB Example. Options:=rdAsyncEnable) ' Wait for connection Do While rCon1.PercentPosition) Text1 = !emp_no & " " & LTrim(!emp_fname) & _ !emp_lname Text2 = !emp_salary DoEvents .Caption = Str$(.PercentPosition Label5.Value = .PWD=Coriolis.EOF ProgressBar1.StillConnecting DoEvents Loop ' Make second connection Set rCon2 = rEnv2.db.DSN=''".0.OpenConnection(dsName:=""." & _ "DBF=C:\ \Examples\Coriolis VB Example. rdOpenDynamic.DSN=''". _ Connect:="UID=Coriolis. rdAsyncEnable) ' Wait for result set Do While rrsEmp1." & _ "DBN=Coriolis. _ rdConcurBatch." & _ "Driver=Sybase SQL Anywhere 5.0." & _ "Driver=Sybase SQL Anywhere 5.db.CreateQuery("Emp".OpenResultset("Emp". Options:=rdAsyncEnable) ' Wait for connection Do While rCon2.Connect:="UID=Coriolis.StillExecuting DoEvents Loop End With With rrsEmp1 lbStatus = "Editing Records …" ' Move through all records Do While Not .PWD=Coriolis.

BatchCollisionRows(0) Text1 = !emp_no & " " & LTrim(!emp_fname) & _ " " & !emp_lname Text2 = "" Text3 = !emp_salary If MsgBox("Collision Detected.StillExecuting DoEvents Loop rCon2.Close ' Perform the batch update to the database lbStatus = "Batch updating …" rrsEmp1.MoveNext Loop ' Simulate a second user changing a record lbStatus = "Simulating a second user …" Set rq2 = rCon2. See changes made?".Bookmark = ." & vbCrLf & _ "Force updates anyway?" ' Give user opportunity to force updates .BatchSize = 1 rrsEmp1.Update ' Scroll to next record .Bookmark = .CommitTrans rq2.BatchUpdate False.CreateQuery("emp2". _ "update employee set emp_salary = emp_salary + 3" & _ " where emp_no = 101") rq2. _ vbYesNo + vbQuestion) = vbYes Then ' Also see the BatchConflictValue of the rdoColumn .Close rCon2.Execute rdAsyncEnable ' Wait for it to complete Do While rq2.BatchCollisionCount) & " records " & _ "have been altered by another user.BatchCollisionCount > 0 Then ' Move to first collision to demonstrate ' use of the batchcollisions array . False ' Check to see if any collisions If .' Put the record in edit mode .Edit ' Give them a raise! !emp_salary = !emp_salary + cRaise Text3 = !emp_salary ' This is a local update — the database ' is not getting updated yet! .Bookmark Text4 = !emp_salary Else sMsg = Str$(.

Listing 6. If both values are True. Some databases or ODBC drivers do not support sending more than one statement at a time. The Bookmarkable property tells you whether you can reference the Bookmark. The following code segment saves a Bookmark. then there are no rows (and the RowCount property is equal to 0). You can save a reference to the current row by saving the value of this property to a variable of type Variant. vbYesNo & vbQuestion) = vbYes Then _ ' True forces the update . moves to the first row.Close rEnv1. You can also change the current record by setting the Bookmark property to a previously saved value. there is no current record and attempting to access any data results in a trappable error.BatchUpdate False.Close lbStatus = "RDO objects closed" End Sub Private Sub Command1_Click() End End Sub Figure 6. • The BOF and EOF properties are similar to the DAO counterparts. I use this property in Listing 6. If either value is True.If MsgBox(sMsg.3 also illustrates some uses of the property.Close End With ' Close rdoConnection and rdoEnvironment rCon1. EOF returns True.5 The RDO batch update sample program detecting a collision with another user. All result sets except forward-only-type support the Bookmark property. If the current record is before the first record. BOF will return True. and then moves back to the saved position. • The BatchSize property controls how many statements will be sent to the server at a time during a batch update. Likewise. • The Bookmark property is a reference to the current row. True End If End If End If ' Close the rdoResultset . The default is 15.3. This method is preferred over using the AbsolutePosition property. if the current record is after the last record. Dim vBookMark As Variant ' Manipulate the result set With rrs .

For instance.Bookmark = rrs. if you are updating a long series of records. • The EditMode property returns a Long indicating the edit mode state of the current record. but any changes you have made will be lost. PercentPosition may be useful to maintain a progress bar for the user. as is also shown in the code example. use the AbsolutePosition or Bookmark properties. • The hStmt property returns a Long containing the ODBC statement handle.vBookmark = .MoveFirst . rdEditNone indicates the current row is not being edited. rdEditAdd indicates that a new row has been added. although it is not precise. ' Move 75% of the way through the result set rrs. if there are 200 rows and you are displaying the 50th. it has the effect of refreshing the current record.EOF . the property will be equal to 25 (25 percent). If no rows have been added or modified. • The LockEdits property returns a Boolean indicating whether the current locking is pessimistic (True) or optimistic (False). On the other hand. You can also use this property to set the current row. The following example illustrates the movement to the most recently modified row: rrs.PercentPosition = 75 ' pbStatus is a progress bar With rrs Do Until . rdEditInProgress indicates that the row is being edited and that the current row is in the copy buffer.Edit !Emp_Salary = !Emp_Salary * 1. See my discussion of the OpenResultset method earlier in this chapter where I discuss concurrency settings. This feature is most useful when another user has changed a row that is currently being edited. The following example will set the current row to be approximately 75 percent of the way through the result set. The row will be changed to reflect that user’s changes. • The Name property is a string containing the first 255 characters of the SQL statement.Bookmark = vBookMark End With NOTE If you set the Bookmark property to the current Bookmark. The row in the copy buffer has not been saved to the database.LastModified • The LockType property is used to set or return the concurrency locking type for the result set.Bookmark . • The PercentPosition property is a Single with which you gauge approximately where you are in the result set.08 . You cannot get a Bookmark reference to a deleted row. this property contains zero. If the row source is a query object. the Name property is equal to the Name of the rdoQuery object. Use the LockType property to manipulate the locking. For more precise movement. • The LastModified property returns the Bookmark of the most recently added or changed row.

However. Avoid referencing this property if you do not absolutely need to know how many rows there are. I attempted to use the PercentPosition property to keep a status bar up-to-date as I moved through 35 records. RowCount will return -1 to indicate an error. . For larger result sets. it might be more accurate.) • The Status property is a Long that returns a constant indicating the status of the current row or column (when accessing the rdoColumn object). the value of RowCount is guaranteed to be accurate.3. For each record.MoveNext Loop End With NOTE In Listing 6. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. • The Restartable property returns a Boolean that is True if the database supports the re-execution of the same query (via the Requery method). All rights reserved. You can also set this property to override the status given by RDO. • The RowCount property returns a Long telling you how many rows are in the current result set. when you reference it. (Note that some ODBC drivers are not capable of returning a row count.PercentPosition DoEvents .pbStatus. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. These constants are itemized in Table 6. consider invoking the MoveLast method yourself so that you can do it asynchronously.7.Value = . the result set invokes a MoveLast method if necessary to determine the number of rows. You might want to do this when managing your own updates. Copyright © 1996-2000 EarthWeb Inc. If you do. as I discussed in “More On Concurrency And Locking” earlier in this chapter. Read EarthWeb's privacy statement. the value never changed from 50. An invalid result set might return a RowCount of 0 instead of -1. Unlike in DAO.

Check individual columns within the rdoColumns collection. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Constant Table 6. including Listing 6. click the chapter and section titles. The current row or column has been deleted.3. If transactions are not supported. The current row or column has been modified. Just because the result set is updatable does not mean that all columns are updatable. as I discussed earlier in this section. results can be committed or rolled back). CommitTrans. the rows . If it is opened read-only or is a forward-only type. This chapter contains several examples of the use of this property. You cannot reference any other property of the result set until the asynchronous operation is complete. Description No updates or adds of this row have been done or are pending.To access the contents. • The Updatable property is a Boolean that returns True if the current result set can be updated. You also cannot access any method except Cancel. Some columns may not be updatable. • The Type property returns the type of result set. however.5. Any number of reasons dictate why a result set is not updatable. • The Transactions property returns a Boolean that is True if the database and driver support transaction processing (that is.7 Valid row and column Status constants. Note. The current row or column has been inserted. as listed in Table 6. rdRowUnModified rdRowModified rdRowNew rdRowDeleted rdRowDBDeleted • The StillExecuting property returns True while an asynchronous operation is executing. that you might want to take an event-driven approach. The row has been deleted in the result set and in the database. the BeginTrans. and RollbackTrans methods have no effect.

the result set probably will not be updatable. the more resources are required. rdCriteriaTimeStamp Use the timestamp column in the WHERE clause. Perhaps you don’t care that another user has updated information such as an address. In such a case. If the columns returned are not sufficient to form a WHERE clause. For instance. The more restrictive the criteria (such as rdCriteriaAllCols). you want to use the list of restrictive update criteria that will guarantee the integrity of your data. however. • The UpdateCriteria property is used with optimistic batch updates to set how the WHERE clause will be constructed in the SQL UPDATE statement. rdCriteriaAllCols rdCriteriaUpdCols Use all columns in the WHERE clause. If your result set does not include a primary key. Possible values are listed in Table 6. your UPDATE statement sent to the server will look something like the following: UPDATE CUSTOMER SET BALANCE = 500 WHERE CUST_NO = 10284 AND BALANCE = 300 . If you have a timestamp column. another user has updated the balance. you generally require a primary key to perform an update. Assuming the customer’s balance is 300 and you want to update it to 500.8 Valid concurrency UpdateCriteria constants.cannot be updated. you would use rdCriteriaUpdCols. In general. Table 6. Use the primary key and those columns being updated for the WHERE clause. in the meantime. The default is rdOperationUpdate. Using rdCriteriaKey probably does not make sense in a multiuser environment because it does not help at all to ensure that another user has modified a row while you are editing it.8. then rdCriteriaUpdCols is a reasonable choice. which species that updates will be . You certainly do not want to update the balance if. Assume you are updating the balance on a bank customer’s record. the result set is probably not updatable. • The UpdateOperation property specifies how updates are to occur. rdCriteriaAllCols is an absolute guarantee of detecting any changes because you are comparing all columns as you read them to their present values on the database. NOTE My copy of Microsoft’s Help file switched the explanations of the rdCriteriaAllCols and rdCriteriaUpdCols. If you do not care about the columns you are not updating. Constant Description rdCriteriaKey Use the primary key for the WHERE clause. rdCriteriaTimeStamp is a good compromise because any changes by another user will alter the timestamp. This comparison is expensive.

you want to use UPDATE.done with the SQL UPDATE statement. rdOperationDelIns causes two statements to be generated—a DELETE of the original row and an INSERT of the new row. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. but if for some reason you need to alter the primary key of a record. Read EarthWeb's privacy statement. most databases require that you do so by deleting the original row and then inserting a new row. Generally. . Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

The following example creates a new row for the result set rrs and then moves to it so it can be edited: With rrs . Once it is deleted.Bookmark = . you must move to a valid row in the result set. Once a row is deleted. When there is nothing to cancel. the only method that you can use is Cancel. no error occurs until you attempt to save the row to the database. the CancelUpdate method is ignored. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoResultset has a number of methods that you use to manipulate data: • The AddNew method creates a new row in an updatable result set. The CancelBatch method cancels all pending changes in a result set opened using the ClientBatch cursor library. • The Delete method deletes the current row. While an asynchronous operation is running (see StillExecuting earlier in this section). the current row remains current. • The CancelUpdate method undoes any changes pending from the copy buffer after an AddNew or Edit operation. Note that when you create a new row. You need to move to the new row using the LastModified property. You can cancel a pending AddNew with the CancelUpdate method. any changes made to the row are lost. Also note that if you move off the new row without updating the database (with the Update or BatchUpdate methods). • The Close method closes the result set and removes it from the rdoResultsets collection.AddNew . click the chapter and section titles.LastModified End With • The Cancel method cancels a currently executing asynchronous operation. it . You can use the EditMode property to determine if there are any pending changes that can be canceled. If you attempt to add a row to a result set that is not updatable.To access the contents.

. vbTab is the default. You must first declare a variable of type Variant. Null) • The GetRows method moves one or more rows from the result set into a two-dimensional array. The default is vbCr. a MoveLast is performed. Moving to another record without first saving the changes causes the changes to be lost. to determine how many rows were returned. as shown in the following example. The Col_delimiter is an optional Variant that specifies what character to use to delimit columns.GetClipString (Rows.cannot be referenced. In invoking the method. RDO copies only those rows that are available. where the first dimension specifies the column within the result set and the second dimension denotes the row. The lock is not released until you save the change or cancel the edit. The syntax is shown in the next code example. If it was the last row. Note that if the result set uses pessimistic locking. otherwise. It then checks the status of the EOF property to make sure that the row wasn’t the last one in the result set. You must use the Update or BatchUpdate methods to save the changes to the database before moving off the row or the changes will be lost. ResulsetString = object. a MoveNext is performed: With rrs . The Ad Hoc Report Writer sample application that I discuss at the end of this chapter uses this method to populate a grid control. This function is most useful for populating grid controls that support the Clip method. Row_delimiter is also an optional Variant used to delimit rows in the string. If there are not enough rows to satisfy the request.Delete If . The only way to undelete the row is in the context of a single transaction using the RollbackTrans method. enabling it to be edited by the user or by the program. as also shown in the example. you need to use the UBound function on the array.MoveLast Else . _ Col_delimiter. • The GetClipString method is similar to GetRows (which I discuss next) except that it returns the data as a delimited string. the database page where the rows reside on the database is locked as soon as you invoke the Edit method.MoveNext End If End With • The Edit method copies the current row to the copy buffer. specify the number of rows to copy. Row_delimiter. The Rows argument specifies how many rows to return. The following example deletes the current row.EOF Then . The Null argument is an optional Variant with a default of an empty string that is used to specify what value to return when a Null column is encountered. Therefore.

The method has an optional argument. MovePrevious scrolls to the prior row. When you use this method.3 contains examples of using both methods. This method retrieves the rows from the next SQL statement. as when you open a new result set. The rdoResultset scrolls to the first row. which has the effect of refreshing the result set to show any changes made by other users. RDO will scroll backwards.GetRows (100) ' Display how many were actually copies MsgBox UBound (vArray. Listing 6. 2) + 1 • The MoreResults method is used when the data source of the result set contains more than one SQL SELECT statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. The rows argument specifies how many rows to move. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. which is optional. The syntax is shown in the following code segment. rdAsyncEnable. . evaluates to the Bookmark of a row from which you want to scroll: rrs. Copyright © 1996-2000 EarthWeb Inc. all saved Bookmarks are invalid. All rights reserved.Move rows[. The from argument. If it is negative. in which case the changes are queued until you invoke the BatchUpdate method. from] • There are four other move methods: MoveNext scrolls to the next row.Dim vArray As Variant ' Get 100 rows vArray = rrs. and MoveFirst and MoveLast move to the first and last rows. • The Update method saves the changes made to the current record to the database unless you use the ClientBatch cursor library. • The Move method moves a specified number of rows forward or backward in the result set. • The Requery method is used to re-execute the current SQL SELECT. Read EarthWeb's privacy statement. to cause the method to execute asynchronously.

Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Referencing rdoResultset Columns Every rdoResultset has a collection of rdoColumns. Specifically. Likewise.Text = rrsEmp!Emp_ID Using the exclamation (!) operator in this manner is called reference by implication. as shown in the following code example.To access the contents. rdoEngine.Value The code snippet references the rdoColumn object by name.Text = rrsEmp. rdoEnvironment. Two arguments are passed to the event. (You can also reference the object by its ordinal position within the collection. and rdoConnection. click the chapter and section titles. The reference to the column’s parent object. When manipulating the result set in code.rdoColumns("Emp_ID"). The rdoColumns Collection And rdoColumn Object The rdoColumn object represents a column within a record set. You need to use DDL in an action query to modify a table structure. The following line of code is simpler to read and somewhat faster to resolve and execute: txtFields(0). which is actually the column name from the SQL SELECT. you reference the individual rdoColumn objects: txtFields(0). query. the rdoColumn object supports some event-driven processing. The rdoColumn objects within an rdoColumns collection are created automatically when you create an rdoResultset or rdoTable. Like rdoResultset. rdoColumns. • The WillChangeData event is triggered immediately before a column value is going to be changed. Value is the default property of the rdoColumn object and does not have to be explicitly referenced. so the explicit reference is not necessary. it supports two events that you can use before or after a value has changed. Although you can use an rdoTable object’s rdoColumns collection to map the underlying database table.) rdoColumns is the default property of the rdoResultset object. you cannot use it (or any RDO methods) to manipulate the table’s structures. or table. is implied. The NewValue argument indicates the new value of the column that will be . you need to declare a reference to the object using the WithEvents qualifier: Private WithEvents rcolEmp As rdoColumn. To take advantage of this behavior.

_ Cancel As Boolean) • The DataChanged event occurs immediately after the data has been updated to the database.KeyColumn = True Then MsgBox "Cannot Update Primary Key!" txtFields(iCtr).Value = Null Else . To try this yourself. rdTypeLongVarChar ' Column is character data If .SetFocus Exit Sub Else ' Verify the type of data required Select Case . As written. create a form with an array of textbox controls named txtFields. As with the DAO Field object.Updatable = False Then MsgBox "Cannot Update This Field!" txtFields(iCtr).4 A generic routine to edit the contents of textboxes against the data requirements of table columns. the second textbox corresponds to the second column. I have highlighted the lines of interest. RDO triggers a trappable error. Private Sub rcolEmp_WillChangeData (NewValue As Variant. You can set the Cancel argument to True.Value = txtFields(iCtr) Else ' Use null if necessary If len(txtFields(iCtr)) = 0 Then . A number of properties tell you about the nature of the column.rdoColumns(iCtr). this value is False.rdoColumns(iCtr). some properties are more pertinent when dealing with tables.SetFocus Exit Sub ElseIf . The Name property is the name of the underlying database column.Type Case rdTypeChar. which has the effect of preventing the change from happening. ' rrs is a result set ' txtFields is an array of textbox controls Dim iCtr As Integer Dim vTest As Variant With rrs For iCtr = 0 to 8 If .rdoColumns(iCtr).rdoColumns(iCtr).4 illustrates many of them in use. Listing 6.Value = txtFields(iCtr) End If .AllowZeroLength Then ' Empty String okay . this routine is very generic and can be used to perform basic validation on almost any result set. and so on. The first textbox will display and update the value in the first column. The listing loops through all of the textbox controls and compares their contents to the requirements of the corresponding column of the result set. Listing 6. whereas others are more pertinent when dealing with queries and result sets.rdoColumns(iCtr). The rdoColumn object has some 16 properties that you use to manipulate data and the object itself.rdoColumns(iCtr). If you prevent a change.rdoColumns(iCtr).modified. rdTypeVarChar. By default.

Value = Null End If End If End Select End If Next End With Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.SetFocus Exit Sub Else .rdoColumns(iCtr).Text If IsNumeric(vTest) Then ' Contains a number .Can it be null? If .Value = txtFields(iCtr) ElseIf Len(txtFields(iCtr)) > 0 Then ' Contains non-numeric data MsgBox "Invalid Value: " & txtFields(iCtr) txtFields(iCtr).Required Then ' Null not allowed MsgBox "Value Required!" txtFields(iCtr). . All rights reserved.SetFocus Exit Sub Else ' Does not contain a number . Read EarthWeb's privacy statement.rdoColumns(iCtr).End If Case Else ' Data is non-character (no dates on this table) vTest = txtFields(iCtr). Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.rdoColumns(iCtr). Copyright © 1996-2000 EarthWeb Inc.

767 Signed 8-byte floating-point number . After that. For purposes of brevity. You can add those tests easily enough. This is a Boolean that is True when character data (Char and VarChar) can be a zero-length string. In the listing. In the listing. and I have disallowed any maintenance to it. I look for columns that are a character data type and handle those differently than numeric data types.9. Table 6. I check the Updatable column.9 Valid rdoColumn Type constants. If the value is False. I next check the AllowZeroLength property. date or time. 2)” Numeric data with precision and scale such as “Numeric (11. 2)” Integer with range of approximately +/. I generate an error message. Next. If the data type is character.1 billion Integer with range of -32.768 to +32. you must specify Null when there is no data. These are the valid data types for a column. I did not evaluate whether the column’s data type was. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The code first checks the KeyColumn property. click the chapter and section titles. for instance. if Null is not allowed and the text box is empty.2. which returns True if the column is part of the primary key. This value is also a Boolean that will be True if the column can be updated. Constant Description rdTypeCHAR Fixed-length character (see Size property) rdTypeNUMERIC rdTypeDECIMAL rdTypeINTEGER rdTypeSMALLINT rdTypeFLOAT Numeric data with precision and scale such as “Numeric (11. Most databases do not allow you to update the primary key. I evaluate the Type property in a Select Case construct.To access the contents. This property is a Long containing one of the constants listed in Table 6.

If the text box is empty. The Value property.Variable-length character. rdUpdatableColumn indicates that the column can be changed. 1-byte integer with range of -256 to +255 Single binary digit If the column’s data type is numeric. If there is non-numeric data. This would be a valid edit of character data: If Len(txtFields(iCtr)) > . 12-byte integer rdTypeTINYINT rdTypeBIT Signed. Attributes And rdUpdatableColumn Then…. To test for any single attribute. rdAutoIncrColumn indicates that the column is an auto-incrementing column. I then make sure a number is entered into the textbox. The Status property indicates whether the column has been modified as a constant. rdFixedColumn indicates a fixed-length column.3 and the discussion of batch updates earlier in this chapter).rdTypeREAL rdTypeDOUBLE rdTypeDATE rdTypeTIME rdTypeTIMESTAMP rdTypeVARCHAR Signed 4-byte floating-point number Signed 8-byte floating-point number Date Time Timestamp (date and time) Variable-length character with maximum length of 255 rdTypeLONGVARCHAR . which returns True if the column cannot be Null.Size Then The Attributes property combines several other properties and may contain one or more constants. returns or sets the value of the column.rdoColumns(iCtr). as listed in Table 6. you should use the And operator: If rrs!emp_no. a message is generated. rdTimeStampColumn indicates a timestamp column. of course. . Although I did not use it in the listing. The OriginalValue is similar except that it provides the value of the column before it was altered by the user or application. I then check the Required property.7 earlier in this chapter. you may find the Size property useful in your edits. whereas rdVariableColumn indicates a variable-length column. The BatchConflictValue property is useful when a batch collision occurs (see Listing 6. maximum length set by database or driver rdTypeBIGINT Signed. usually associated with the primary key. It returns the maximum size (in bytes) of the underlying column. maximum length set by database or driver Fixed-length binary data with maximum rdTypeBINARY length of 255 Variable-length binary data with maximum rdTypeVARBINARY length of 255 rdTypeLONGVARBINARY Variable-length binary data.

The BindThreshold property returns the largest number of bytes of data that can automatically be bound to a column without using the GetChunk method. The datasource argument is the variable from which you are reading to append to the column. Read EarthWeb's privacy statement. The rdoColumn object has only three methods. Copyright © 1996-2000 EarthWeb Inc. You can also set this property to the largest column size that you want to be automatically bound. only the remainder of the column is read. Likewise. The ChunkRequired property is a Boolean that returns True when you must use the GetChunk and AppendChunk methods to access binary and long character data from a column.AppendChunk datasource Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. If there are not enough bytes left in the column to fill the buffer. Dim vChunk As Variant vChunk = recordset!column.GetChunk (bytes) recordset!column. The GetChunk and AppendChunk methods are used with binary data or very long character data (rdTypeLONGVARCHAR). bytes is the number of bytes to read with each iteration. You use the ColumnSize method to return the actual size of the binary data stored in the column. .The SourceColumn and SourceTable properties return string variables containing the names of the column and table from which the data in the column is derived. the AppendChunk method appends a chunk at a time to a column. GetChunk is used to iteratively retrieve a “chunk” of data at a time. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. perhaps to read a Microsoft Word document that has been stored in a table. The syntax for each is shown in the next code segment.

your database’s syntax may differ slightly: CREATE PROCEDURE raise_no (IN r INTEGER. The parameter can be input. p) INTO rp . IN p INTEGER. I created the following simple stored procedure to compute the power of a number. ?) In Listing 6. You can use the rdoParameter object as a placeholder in stored procedures or in queries. ?. the application illustrates both the methodology of calling . r and p. The overall operation is similar to using DAO’s Parameter objects. Parameters are implicitly created when you place question marks in your query or call to a stored procedure. Although the following syntax is fairly generic. I provide a listing for the RDO parameters application that you see running in Figure 6. I have highlighted the lines of code that call the raise_no stored procedure. the stored procedure expects two input arguments. The application allows you to test both parameterized stored procedures and queries. It raises the number r to the power of p and passes the result to the output argument rp. An output parameter is used where a stored procedure will return results.To access the contents. An input parameter supplies a value to a query (as in a WHERE clause) or stored procedure. Although not terribly complex. END In this example. you must use the CALL keyword to execute the procedure on the database. To call this from Visual Basic.6. OUT rp INTEGER) BEGIN SELECT power (r.5. click the chapter and section titles. you need to create an SQL statement that looks like the following: CALL raise_no (?. or both. output. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoParameters Collection And rdoParameter Object The rdoParameters collection contains all parameters of a query. With a stored procedure. RDO creates an rdoParameter object for each question mark (?) it sees in an rdoQuery object’s SQL property.

max(emp_salary).Value Case 1 ' Parameter query Set rq = Nothing Set rrs = Nothing sSQL = "Select min(emp_salary).stored procedures from Visual Basic as well as how parameters are created and used.rdoParameters(0).rdoParameters(2).CreateQuery("SP". sum (emp_salary) from " & _ "employee where emp_gender = ? and emp_dept_no = ?" & _ "group by emp_gender.rdoParameters(1).rdoParameters(2).StillExecuting DoEvents Wend txtResult = rq.5 The RDO parameters demonstration program. sSQL) rq(0) = txtParms(0) rq(1) = txtParms(1) Set rrs = rcon.rdoParameters(2).StillExecuting . emp_dept_no " Set rq = rcon.Direction = rdParamInput rq.rdoParameters(0). ?)" Set rq = Nothing Set rq = rcon.Type = rdTypeINTEGER rq(0) = iRoot rq(1) = iPower rcon.Execute ("SP") While rcon.OpenResultset("PARM") While rcon.Type = rdTypeINTEGER rq. " & _ "avg(emp_salary). sSQL) rq.CreateQuery("PARM". Option Explicit Dim WithEvents reng As rdoEngine Dim WithEvents renv As rdoEnvironment Dim WithEvents rcon As rdoConnection Dim WithEvents rrs As rdoResultset Dim rq As rdoQuery Private Sub Command1_Click(Index As Integer) Dim Dim Dim Dim iRoot As Integer iPower As Integer iCtr As Integer sSQL As String Select Case Index Case 0 ' Stored procedure iRoot = Val(txtRoot) iPower = Val(txtPower) sSQL = "Call raise_no (?.Direction = rdParamInput rq.) Listing 6. (I discuss stored procedures in greater depth in later chapters. ?.rdoParameters(1).Direction = rdParamOutput rq.Type = rdTypeINTEGER rq.

_ Prompt:=rdDriverNoPrompt.StillConnecting DoEvents If sSlash = "/" Then sSlash = "\" Else sSlash = "/" End If Caption = Caption & sSlash Wend Caption = sCaption Screen.CursorDriver = rdUseOdbc .UID=Coriolis.LoginTimeout = 10 ' Create connection Set rcon = .rdoColumns(iCtr).Value Next Case 2 ' Close End End Select End Sub Private Sub Form_Load() Dim sCaption As String Dim sSlash As String * 1 ' Connect to database Show sCaption = Caption Caption = Caption & " Connecting …" Screen. "coriolis".".DoEvents Wend For iCtr = 0 To 3 txtSalary(iCtr) = rrs.OpenConnection(dsName:="". _ Connect:="DSN=Coriolis VB Example.MousePointer = vbDefault End Sub .rdoCreateEnvironment _ ("VB"." & _ "PWD=Coriolis.MousePointer = vbHourglass ' Create environment Set renv = rdoEngine. Options:=rdAsyncEnable) End With ' Wait for connection to complete While rcon. "coriolis") ' Set properties With renv .

I use the Direction property to explicitly tell RDO whether the parameter will be used for input or output. Copyright © 1996-2000 EarthWeb Inc. RDO can ascertain this information by itself. The Name properties of each parameter are simply Parameter1. I explicitly reference the properties when I set the return result from the procedure. They are maintained for backward compatibility. Other possible values are rdParamInputOutput and rdParamReturnValue. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Possible values are listed in Table 6. omitting the property names. The form allows the user to supply a gender and department number and use those values as parameter values when creating the result set. Because rdoParameters is the default property of the rdoQuery object and Value is the default property of the rdoParameter object. such as rdoConnection. In the next two lines of code.6 The RDO parameters demonstration program. which is provided by other objects. The Type and Updatable properties are similarly available from rdoColumn. Normally.9 earlier in this chapter. you must first use the Refresh method of the collection. The application then determines various summary salary information and displays it. this is normally not necessary. Parameter2. and all the information and methods that they provide are supported by other objects. I simplified the syntax as shown. Again. The rdoTables Collection And rdoTable Object Microsoft discourages the use of the rdoTables collection and rdoTable object. When the rdoQuery object is created using the preceding syntax for the SQL property. The Name property is equivalent to the SourceTable property in an rdoColumn object. For illustration purposes. Place a question mark in the query wherever you desire a parameter to be filled in at runtime. I also specify the data type of each parameter using the Type property. and so on. RDO creates three parameters—one for each question mark placeholder. I set the Value property of the input parameters. To reference it. All rights reserved. Read EarthWeb's privacy statement.Figure 6. rdoTable provides a definition of a table or view in a query or result set. . Queries work much like their DAO parameter counterparts. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. The RowCount property is available from the result set. The only method the object supports is the OpenResultset method.

the requirements for ODBC functionality to use rdoPreparedStatement are more stringent than they are for rdoQuery. If using rdoPreparedStatement. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The rdoPreparedStatements Collection And rdoPreparedStatement Object Like rdoTables. The use of the Remote Data control is analogous to the DAO Data control. The Error event is triggered when a database error is encountered while no VB code is running. The control generates only four events. Source is the source of the error. HelpFile and HelpContext refer to the help file and context ID that provide more information about the error. All their properties and methods are provided by rdoQuery. rdoPreparedStatements and rdoPreparedStatement are provided for backward compatibility only. CancelDisplay allows you to display the error (rdDataErrDisplay) or proceed without displaying the error (rdDataErrContinue). The effort is little more involved than a simple search and replace in your code.To access the contents. The Error event works much like the Data control’s Error summary event except it provides more information. it appears on the toolbox and can be used in a manner similar to that for the Data control. . Its use provides some loss in flexibility but provides an even simpler development scenario. The Scode argument is the ODBC return code. as shown in the following syntax. you must add it as a component from the Project menu. To use the Remote Data control. The default value is rdDataErrDisplay. click the chapter and section titles. Further. simpler method for developing database applications than does DAO while retaining a high degree of both familiarity and compatibility. you should consider converting. Once you have done so. The Number and Description arguments are the error number and error descriptions from the Err object. The Remote Data Control RDO provides a much cleaner.

Private Sub MSRDC1_Error(Number As Long. In other words. if the result set is closed. Find method (not implemented).10 Remote Data control Validation event Action constants. Update canceled. Table 6. The form is being unloaded. Constant Description rdActionCancel rdActionMoveFirst rdActionMovePrevious rdActionMoveNext rdActionMoveLast rdActionAddNew rdActionUpdate rdActionDelete rdActionFind rdActionBookmark rdActionClose rdActionUnload rdActionUpdateAddNew rdActionUpdateModified rdActionRefresh rdActionCancelUpdate rdActionBeginTransact rdActionCommitTransact rdActionRollbackTransact Cancel the operation when the Sub exits. You use this event as you would use the rdoConnection except that it does not provide information about the query itself. It occurs before any operation that would cause the current row to no longer be the current row. CommitTrans method. MoveLast method. MoveFirst method. HelpContext As Long. The current row changed. The syntax is shown in the next code example. this event is triggered first. CancelDisplay As Boolean) The QueryCompleted event occurs after a query has completed executing. A new row was inserted into the result set. The event is also fired prior to the Update method. The Bookmark property has been set. if the user or application scrolls to a new row. AddNew method. HelpFile As _ String. MovePrevious method. Action tells you what operation is pending that caused this event to be triggered. Source As String. of course. Likewise. Close method. whether asynchronously or synchronously. The Reposition event is triggered after a new row becomes the current row. RollbackTrans method . This gives you an opportunity to validate any changes made by the user as well as to cancel the pending operation that triggered the event. this event is triggered first. Scode As Long. during asynchronous operations. Delete method. Possible values are listed in Table 6. MoveNext method.10. the operation will be canceled. It is most useful. The RowCurrencyChange event of the rdoResultset is also triggered. regardless of what caused the row to display (such as a user clicking one of the move buttons). Update operation (not UpdateRow). Refresh method executed. The Validate event is perhaps the most useful of the four events generated by the Remote Data control. Description As _ String. If you change the value to rdActionCancel. BeginTrans method.

The Remote Data control has a number of properties that mostly parallel those of other RDO objects. rdBOF causes a move before the first record. _ Reserved As Integer) When the Validate event fires. Private Sub MSRDC1_Validate (Action As Integer. All rights reserved. you should perform your business rule edits (I discuss this at length under the Validate event in Chapter 5) and cancel the operation that triggered the event if there is a data problem. and Resultset. Similarly. such as Connect. SQL statement changed. which return or set the action to take when BOF or EOF is True. which is the default. If the Remote Data control moves to another row. Additionally. Copyright © 1996-2000 EarthWeb Inc. For BOFAction. BatchCollisionRows. Read EarthWeb's privacy statement. the changes to the current record are made automatically. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. you should check to see whether any bound data has changed. The two properties that are not derived from other RDO objects are BOFAction and EOFAction. rdMoveLast for EOFAction causes the last record to remain the last record when a MoveNext is issued. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the value rdMoveFirst. triggering a Validate event on the first row and a Reposition event on the now invalid row. which causes the AddNew method to be invoked.rdActionNewParameters rdActionNewSQL Change in parameters or order of columns or rows. If so. rdEOF behaves similarly for EOFAction. . causes the first record to remain the first record when a MovePrevious is attempted. you can set EOFAction to rdAddNew.

this method will cause all of the bound controls to revert to their original values. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Remote Data control has a number of methods derived from other RDO objects: BeginTrans. If the ClientBatch cursor library is being used. Select which columns you want to display in the report. and Cancel.7. CommitTrans. The source code is not printed here in order to save a few square miles of the rain forest. Bonus: The RDO Ad Hoc Report Writer Included on the CD-ROM is the RDO Ad Hoc Report Writer application. You can click on any two tables and list their columns in the listboxes shown in the figure. the local result set is updated but the database is not updated until you invoke the result set’s BatchUpdate method. This is basically an “undo” method. • The UpdateControls method causes all bound controls to be repopulated with columns from the result set. The running application is shown in Figure 6. You can even do a self-join by selecting the same table for both listboxes. You will normally use this method either in a multiuser environment or when the parameters being passed to a parameterized result set have changed. • The UpdateRow method is essentially the same as the rdoResultset Update method except that the Validate event is not triggered. If the user has changed some value in bound controls before the result set has been updated. click the chapter and section titles. similar to the Requery method of rdoResultset.To access the contents. RollbackTrans. Other methods include the following: • The Refresh method causes the result set to be closed and reopened. It connects to the specified database and then retrieves a list of tables. Remote Data control result sets must be either keyset type or static type. Use the two combo box controls to specify how the two tables are to be joined. press the Build button to build and display the SQL . I urge you to start it and study some of the code. When ready.

read Chapters 7 and 8 where I introduce ADO and OLE DB and then cover techniques to migrate from RDO to ADO. you might want to move ahead to Chapter 11 where I discuss advanced database concepts. or however many tables. similar to the query facility in Visual Basic’s Visual Data Manager. Likewise. for some DAO concepts not covered in this chapter. I have provided guidance on the use of RDO. if you have not already done so. You will need to devise a way to show more listboxes or simply display all of the columns in one listbox. Previous Table of Contents Next . For instance. If you are doing pure ODBC development and do not want to consider ADO. I will expand upon this application in future chapters. four. to run this application on an Oracle database. Otherwise. Figure 6. Where To Go From Here In this chapter. press the Run button to execute the select. Note that you will have to alter the SELECT statement that retrieves the table and column names. The code will work for three. Otherwise. Many or most of them are equally applicable to RDO.SELECT statement. change the table select statement to either of the following: SELECT table_name FROM user_tables ' Or you can use the following SELECT table_name FROM all_tables WHERE creator = 'CORIOLIS' An examination of the listing will show that the choice to limit selects to only two tables was arbitrary.7 The RDO Ad Hoc Report Writer. Simply change the number of subscripts for the sActTables variable and change the loop counters in the BuildQuery procedure. including building an application with it. If you want. you can then alter the SELECT statement in the textbox. The results appear in the grid control at the top of the form. including numerous code examples and as much real-world advice as I could fit into one chapter. take a look at Chapter 4 if you have not done so yet because I spent some additional time discussing the Remote Data control. You may also want to review Chapter 5.

Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved. .

To access the contents. I will introduce you to the use of the Active Data Objects (ADO) data model. Microsoft also includes ODBC under MDAC. as well as the OLE DB technologies upon which it sits. I will guide you through more advanced application of these techniques into a scalable network or Web-based model. Microsoft Data Access Components Microsoft Data Access Components (MDAC) is the umbrella over Microsoft’s COM-based database development initiatives. MDAC consists of Active Data Objects (ADO). . I will guide you through most of the essential aspects of ADO development. click the chapter and section titles. Strictly speaking. In subsequent chapters. Remote Data Services (RDS). and OLE DB. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 7 Introducing ADO And OLE DB Key Topics: • Microsoft Data Access Components • Overview of OLE DB • Overview of ADO • Event-driven programming and ADO • Using the Active Data control • Using ADO schema objects • Transaction management with ADO • Concurrency management with ADO In this chapter. MDAC is common to all Microsoft development tools and is likely to be embraced by other tool vendors.

It is an evolutionary step from ODBC. and Microsoft is likely to release functional improvements from time to time. UDA seeks to blur or make invisible the distinction between data in a local Microsoft SQL Server database and data on a Web page across the world. but was not replaced by. To the user. Finding all business data and then getting it into a central repository is no trivial undertaking. not knowing or caring what applications actually build the document. DDE evolved into. a user works on a document. . computations performed by Excel. Bill Gates made a speech at Comdex where he espoused a “document-centric” way of computing. Because all computing and all documents eventually deal with data. now redubbed ActiveX. A good page to bookmark in your browser is www. You should be able to download and incorporate into VB new releases of MDAC as they occur. MDAC is evolving rapidly. and Excel into a centralized database. The document might have some text created by Word. where you can keep an eye on the latest trends. A central underpinning of Microsoft’s Universal Data Access (UDA) model is to not copy the data into a central location but rather to devise a methodology to access it in its native format. DAO. MDAC takes care of the details of massaging and merging that data behind the scenes.0. and graphics created by PowerPoint. Under this scenario. but UDA will not replace any of those technologies soon. It also does not guarantee that all the information is accessible because often. In other words. which added an event-driven environment much like RDO’s event-driven paradigm. The first incarnation of this thrust was Dynamic Data Exchange (DDE). not knowing or caring where it is coming from either. Oracle. we need to back up a step and take a look at data access in general. Universal Data Access Data warehouses and similar systems seek to make available all corporate data in a central repository where it can be analyzed for the purpose of making more informed business decisions.With VB6 comes MDAC 2. This often involves copying data from disparate sources such as Access. data is stored in unstructured and inaccessible formats such as email messages and Web pages.com/data/ado. if you have an Employee table stored on a relational database. and RDO. Object Linking and Embedding (OLE).” UDA seeks to provide a high-performance interface to relational and nonrelational data sources in a common manner. UDA is a logical follow-up to Gates’s document-centric thrust: The user deals with data. However. you should be able to dynamically join it to your email server to find all messages from “John Smith” whose subject is “Widget Sales. Recall that in 1990. The concept is called Universal Data Storage (UDS). it is all the same.microsoft. The “shell” that the user is in might well be your Visual Basic application. To appreciate why Microsoft introduced MDAC.

which is now a part of ADO. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.0 and above. • Integrate the remoting services previously provided by the Active Data Connector (ADC). It is essentially a low-overhead wrapper around the OLE DB API.Goals Of MDAC Microsoft has espoused several goals for its MDAC efforts: • Provide the programming interface to create data-bound Web pages in Internet Explorer 4.” The two terms are synonymous. It adds key support for building client/server applications residing on traditional networks or on Web-based networks. • Provide the programming interface to create dataware middle-tier components in client/server applications. Active Data Objects You will sometimes see the “Active” in ADO called “ActiveX. and I use the simpler word “Active. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. particularly on Internet Information Server (IIS) 4.0 and above. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved.” ADO is to OLE DB what RDO is to ODBC. including the Internet.

manipulate record sets. In that aspect. It provides an interface to applications that make disparate data sources look as though they were the same data source. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- OLE DB OLE DB can be considered analogous to ODBC. The very nature of OLE DB is to create the data interface in a component-based manner. OLE DB defines these components: • Enumerator—Searches for available data sources and other enumerators and is used by consumers that are not customized to a single data source. • Data Source object—A component that contains the mechanism to connect to a database and through which you will manage transactions. click the chapter and section titles. Their relationship is shown in Figure 7. It sends a query to the database and receives the results. Providers and consumers are components under COM and DCOM.To access the contents. • Session object—A representation of the current database connection. By definition. An OLE DB data consumer is an application that uses OLE DB-provided data. and so on. It logically organizes structured or unstructured data into rows and columns so that it can be accessed in a common way (such as via SQL SELECT statements). For instance. A service provider is an OLE DB component that does not actually own any data but provides some other service.1. Once the data is received. . it is a data consumer. it sends the data to your application and thus also acts as a data provider. The data source is analogous to the RDO environment and the DAO workspace. a query processor that sits between your application and the OLE DB provider reacts to data requests from your program. an OLE DB service provider is both a data consumer and a data provider. A data provider is any software component that exposes its data via an OLE DB interface.

For instance. and product. your application does not need to understand the inner workings of OLE DB any more than it needs to understand the complexities of the ODBC API. or all three. You might summarize sales at various levels: region. ADO places a programmatic wrapper around OLE DB. ADO Overview ADO allows your application to access any data that is exposed via an OLE DB interface. OLE DB. These objects can be exposed if you want. month. making your task easier. your application can freely relate any OLE DB data source to any other OLE DB data source.1 shows the relationship of the application (including Internet-based applications) to ADO and OLE DB. Further. assume you are analyzing sales and customer data. an SQL command is termed a text command.1 ADO as it relates to the application.) • Rowset object—The object with which you manipulate and view data. It is the equivalent of the DAO record set and the RDO row set. such as “sales in the northeast for 1999. • Error object—Contains information about database errors not occurring as a result of code errors and is akin to the DAO and RDO error objects. Figure 7. By and large. state or province. • Command object—Used to execute SQL commands.roughly analogous to the RDO connection and DAO database or connection objects. You can see where this takes on a multidimensional aspect. roughly analogous to the RDO and DAO query objects. Figure 7. and you can think of it as roughly akin to a Visual Basic multidimensional array. You would want to be able to cut across each of these elements at any level of detail. ADO And RDS . Multidimensional data is often used in decision-analysis systems and seeks to “roll up” or summarize data at various meaningful levels. (In OLE DB. product. • Transaction object—Allows you to work with the database in terms of a transaction or logical unit of work. ADO MD ADO MD (multidimensional) allows your application to access multidimensional data for any OLE DB for which there is an MD interface. month. However. and the database.” You might then want to “drill down” by state.

Read EarthWeb's privacy statement. . Copyright © 1996-2000 EarthWeb Inc.Remote Data Services (RDS) is a development model where the client application never physically connects to the database. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. these applications are three-tiered. All data access occurs through an intermediary such as Internet Information Server (IIS) or Microsoft Transaction Server (MTS). All rights reserved. Instead of the traditional two-tiered application. Once a separate product. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. RDS is incorporated into ADO.

not all data types specified in ADO are exposed to Visual Basic. see the DataTypeEnum Enum structure in the object browser.1 Valid ADO data types. Description 8-byte signed integer Binary Boolean Null-terminated Unicode string Fixed-length string Currency Date stored as Double where the whole part is the number of days since December 30.1 lists the most common data types you will encounter. click the chapter and section titles.) For a complete list. (In fact. 1899. Constant adBigInt adBinary adBoolean adBSTR adChar adCurrency adDate Table 7. and the fractional part is the fraction of a day Date as yyyymmdd Time as hhmmss Date and time stamp as yyyymmddhhmmss plus a fraction in billionths Number with fixed precision and scale Double No value 32-bit error code adDBDate adDBTime adDBTimeStamp adDecimal adDouble adEmpty adError . Not all data types will apply to all data providers.To access the contents. Table 7. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- ADO Data Types ADO specifies a number of data provider-specific data types.

you can program using the RecordSet and Field objects alone.2 The ADO object model. Either way. RecordSet. Figure 7. these ADO data types help you to interpret or set the underlying data. Also. note there is no equivalent to the DBEngine or rdoEngine objects in DAO and RDO. note that there are only four collections: Errors.2 are briefly explained here: • The Connection object represents a connection to a database. Notice that the relationships are not hierarchical. some do not. for instance. Properties. the relationship between Parameter and Properties is omitted. Using ADO Objects Figure 7. each Connection object. There is no overall “owner” of other ADO objects. In fact.2 shows the relationship of ADO objects to one another.adGUID adInteger adLongVarBinary adLongVarChar Globally unique identifier (GUID) 4-byte signed integer (Long) Long binary value (Parameter object only) Long string value (Parameter object only) Long null-terminated string value (Parameter object adLongVarWChar only) adNumeric Number with fixed precision and scale adSingle adSmallInt adTinyInt adUnsignedBigInt adUnsignedInt Single Integer 1-byte signed integer 8-byte unsigned integer 4-byte unsigned integer adUnsignedSmallInt 2-byte unsigned integer adUnsignedTinyInt 1-byte unsigned integer adUserDefined adVarBinary adVarChar adVariant adVarWChar adWChar User-defined variable Binary value (Parameter object only) Variable-length string value (Parameter object only) Automation Variant Null-terminated Unicode string (Parameter object only) Null-terminated Unicode string Although most of these data types have VB equivalents. The ADO objects shown in Figure 7. For simplicity. has its own Errors collection. and Connection objects are all standalone. Note . Fields. Instead. Finally. The Command. and Parameters.

For instance. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. the Property object is used to represent properties of ADO objects that are nonstandard ADO properties. using many of the same application types that I used in Chapters 5 and 6. To use ADO objects.DLL. • The RecordSet object is used to view and manipulate data much like DAO’s RecordSet and RDO’s rdoResultSet. . containing only the RecordSet and Field objects. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. unless you are using the ActiveData control. Typically. the Connection object will have somewhat different properties based on whether you are connected to SQL Server or Oracle. The latter is a scaled-down version of the former. • The Command object represents an SQL statement such as a SELECT or UPDATE or some other data provider-specific command. All rights reserved. • The Parameter object is much like its DAO and RDO counterparts. • The Field object represents a field or a column in a ResultSet. • The Error object is used to retrieve and handle error conditions from the database. • The Property object represents a characteristic of various ADO objects.that the database may or may not be a relational source such as Oracle. It can be any OLE DB data source. In the following pages. or legacy data from a mainframe. you must make a reference to the ADO library. Copyright © 1996-2000 EarthWeb Inc. I outline the use of ADO. You use it to specify variable values in queries and so on. Read EarthWeb's privacy statement.DLL and MSADOR15. such as email. There are actually two libraries: MSADO15. an unstructured text file.

and adStatusErrorsOccurred signifies that there were errors during the operation. or halt the operation to occur (such as connecting to a database). For events where errors can occur. you are warned that you cannot cancel the pending event. The possible values of adStatus are contained in EventStatusEnum. which is a reference . Those events triggered immediately before an operation allow you to examine. of course. click the chapter and section titles. are committed. you can set the property to adStatusUnwantedEvent. modify. ADO defines two families of events: Connection events occur when transactions begin. you will also be passed pError. Finally. you must declare them using the WithEvents clause: Dim WithEvents acon As Connection Dim WithEvents ars As RecordSet Most events are fired immediately before or after an operation such as a query. ADO provides a good deal more information when events are triggered than do DAO or RDO. They usually begin with Will (such as Will-Connect). ADO supports an event-driven access model. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The ADO Event Model Like RDO. which tells ADO not to notify you of subsequent occurrences of the event. RecordSet events are events that happen when changes are made to a record and when you navigate through records. adStatusOK indicates that the operation completed without errors (although some events still generate warning messages). Otherwise. you can set this property to adStatusCancel to cancel the operation that is about to occur. or when a Command or Connection begins or ends. adStatus. They usually are appended with Complete (such as ConnectComplete). This option is applicable only to Will events. The Connect and RecordSet objects support events. If adStatus is set to adStatusCantDeny.To access the contents. Nearly all events pass to the application a status flag. are rolled back. To gain access to their events. Those events triggered immediately after completion are most valuable in asynchronous operations or in determining if there were any errors.

Typical constants are adRsnMove. _ ByVal pConnection As ADODB. but you need to set the object to Nothing to completely eliminate it from memory (Set acon = Nothing).Error. _ ByVal pConnection As ADODB. If there was an error. the user moves to another record. you would have two independent Connection objects.EventStatusEnum.Error. The possible values are enumerated in EventReasonEnum. if you were connected to both Oracle and SQL Server in an RDO session. which is appropriate because two independent database connections can each generate a unique set of errors. If you were to operate on an Oracle database and perform a join to an SQL Server database. The Connection object is similar to the rdoEngine object. where the Errors (or rdoErrors) collections are a function of the DBEngine or rdoEngine objects. If SQL Server generated an error 1/10 of a second after Oracle. All 15 constants currently defined are listed in the object browser. This is true for the events generated as well. The Connection object also has a Properties collection. Under ADO.to an Error object describing the error. for instance. Typically. you should iterate through the Errors collection. you are passed a reason code if. _ adStatus As ADODB. any sequence of errors overlays the most recent sequence of errors. each connection maintains its own error information. say. which denotes the reason the event occurred. The Connection Object The Connection object represents an open connection to a data source. If you were to simultaneously execute two different queries on two different databases under RDO. solving this dilemma. Each Connection object has an Errors collection. it wins: You would never see the Oracle errors. and the Connection events in the following section. search on EventReasonEnum. then this value is Nothing. and adRsnClose. I discuss the specifics of the RecordSet events in “The RecordSet Object” later in this chapter. Closing a connection breaks the open connection to the data source. More to the point. You should also iterate through the Errors collection whenever the Connection object’s InfoMessage event is triggered.Connection) Private Sub acon1_CommitTransComplete _ (ByVal pError As ADODB.Connection) Private Sub acon1_ConnectComplete _ . as discussed later in this chapter in the section “The Errors Collection And Error Object.” If there was no error. The following examples show the syntax for each of the events supported by the Connection object: Private Sub acon1_BeginTransComplete _ (ByVal TransactionLevel As Long. Contrast that setup with DAO or RDO. _ adStatus As ADODB.EventStatusEnum. which I discuss later in this chapter. things would get interesting if they both generated errors. Some of the RecordSet object’s events pass adReason. adRsnAddNew. _ ByVal pError As ADODB.

_ ByVal pConnection As ADODB. _ ByVal pConnection As ADODB. _ CursorType As ADODB.EventStatusEnum. _ UserID As String.LockTypeEnum.EventStatusEnum.Error. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Recordset.EventStatusEnum.EventStatusEnum.Connection) Private Sub acon1_ExecuteComplete _ (ByVal RecordsAffected As Long.EventStatusEnum. _ ByVal pConnection As ADODB.Connection) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.(ByVal pError As ADODB.Recordset.Command. _ adStatus As ADODB.EventStatusEnum.Error. _ LockType As ADODB.Connection) Private Sub acon1_WillExecute(Source As String. _ ByVal pConnection As ADODB. _ adStatus As ADODB.Connection) Private Sub acon1_InfoMessage(ByVal pError As ADODB.Command. _ adStatus As ADODB. Options As Long. Options As Long. _ ByVal pConnection As ADODB.Error.Connection) Private Sub acon1_Disconnect _ (adStatus As ADODB. _ adStatus As ADODB. Password As String. _ ByVal pRecordset As ADODB. . Copyright © 1996-2000 EarthWeb Inc. _ ByVal pRecordset As ADODB. _ adStatus As ADODB. _ ByVal pCommand As ADODB. Read EarthWeb's privacy statement.EventStatusEnum. _ adStatus As ADODB. All rights reserved. _ ByVal pCommand As ADODB.Error.Connection) Private Sub acon1_WillConnect(ConnectionString As String. _ ByVal pConnection As ADODB. _ ByVal pConnection As ADODB.CursorTypeEnum.Connection) Private Sub acon1_RollbackTransComplete _ (ByVal pError As ADODB. _ ByVal pError As ADODB.

To access the contents. Use the Connection object’s properties as described here: • The Attributes property specifies whether the connection performs retaining commits or aborts. A retaining commit (adXactCommit-Retaining) implicitly starts a new transaction whenever a CommitTrans is performed. or after a transaction has been rolled back. • The CommandTimeOut property defines. ADO cancels the command and generates an error. after a transaction has been committed. The WillConnect event occurs immediately before an attempt to connect to the database. Likewise. The default is 30 seconds. but not all providers support this. the additional information might be an SQL warning. in seconds. Password. You can set these properties. The BeginTransComplete. and Options contain other connection parameters. my recommendation is to set this value much lower than 30. The TransactionLevel is discussed under IsolationLevel later in this section. which is also my recommendation because it needlessly extends the duration of a transaction. If a command times out. and Rollback-TransComplete events are triggered after a transaction has begun. how long to wait while a command is executing before timing out. For most online processing. RecordsAffected returns the number of records affected by the command. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The InfoMessage event is similar to its RDO counterpart. It is triggered whenever an operation has completed successfully but the data provider has returned additional information. Use these events for any transaction handling that your application requires and to intercept any errors. the record set will be empty. and pRecordSet returns a reference to the record set created by the command. The ExecuteComplete event is triggered when a command has completed execution. if any. In ODBC. The nature of online processing is . notifying you when the connect and disconnect operations are completed. You can modify any of these parameters at this point. UserID. A value of 0 means there is no timeout (the command will execute until completed). The default is to not perform retaining commits or aborts. CommitTransComplete. A retaining abort (adXactAbort-Retaining) starts a new transaction whenever a RollbackTrans is performed. click the chapter and section titles. ConnectionString contains the ConnectString property of the Connect object. If the command ran successfully but did not return any records. ConnectComplete and DisconnectComplete are especially valuable in asynchronous operations.

db. Microsoft Index Server.Open ("UID=Coriolis. and you might want to bookmark the page www. the vagaries of traffic will make the performance of your commands less predictable." & _ "DBF=C:\ Examples\Coriolis VB Example. contained in the Connect object’s ConnectString and the ActiveData control’s ConnectionString properties. ADO will attempt to connect to an ODBC data source. dsn=Coriolis VB Example. this is the only parameter allowed. If you are executing a command over the Internet.com/data to keep track of new developments. This is the default provider. Balance my advice with some common sense. The ConnectionTimeOut property is similar except it sets how long to wait before an error occurs when attempting to connect to a data source. so you will want to account for that. If your command is the cause of a lengthy execution." & _ "DBN=Coriolis. Jet. which is reasonable. • Remote Server is used to specify the path of the server in an RDS connection. • The ConnectString property is much like RDO’s Connect property.Open ("PROVIDER=MSDASQL.") . set the Provider argument equal to “MSDASQL”. Using The Connect String The ADO connect string. the only other parameter allowed is Remote Server. ADO recognizes only four parameters within the connect string. The default is 15 seconds. Visual Basic recognizes only four arguments in the connect string. PWD=Coriolis. is how you specify various parameters for connecting to the data source. Other parameters in the connect string are database and driver dependent. This argument is mutually exclusive with any other ADO connect-string parameter. pwd=coriolis.0." & _ "uid=coriolis. Microsoft and other vendors will be developing OLE DB providers for other data sources. and ODBC. the only other parameter allowed is Remote Provider. SQL Server. • FileName specifies the name of a file containing connection information. but the second uses a DSN-less connection: Set aCon1 = New Connection aCon1. The Microsoft OLE DB provider for ODBC allows you to connect to any ODBC data source. With Visual Basic. The four parameters are: • Provider specifies the name of the OLE DB provider. If used. Any other arguments are passed directly to the data source. ODBC is a near-universal access point for relational databases. you need to tune it. so even if it’s omitted. The following snippet of code creates two Connection objects and then connects to the database. To specify the connection to an ODBC data source.that few records are affected and any lengthy duration is indicative of a larger problem—either with your command or with the database itself. Each uses the Microsoft OLE DB provider for ODBC. • Remote Provider is used in RDS connections to specify the name of a remote provider. If the source of the problem is the database. Active Directory Service. If supplied. Any others are passed through to the OLE DB provider without ADO attempting to interpret them." & _ "Driver=Sybase SQL Anywhere 5.microsoft. The first uses a traditional DSN connection. Microsoft delivers OLE DB providers for Oracle.") Set aCon2 = New Connection aCon2. In the meantime. It contains the information necessary to connect to and log on to the database. If used. Your DBA needs to investigate a database problem. an excessively lengthy command only compounds the problem.

You can set this value at any time on a Connection but it is read-only on an open RecordSet object. Normally. Note that RDS permits only adXactUnspecified.Jet. .) For Microsoft SQL Server. Although there are few instances where you would need to use this option. Even more. which you would normally use when you need to join an ISAM data source for which no OLE DB provider exists to another OLE DB data source. you lose the flexibility of the client-side cursor. it necessitates the adXactChaos constant. it specifies how “visible” a cursor is. but the level cannot be determined. see the Visual Basic help file (for OLE DB providers provided by Microsoft) or the vendor’s documentation. Table 7. use MSDAORA. If you are using RDS. the DSN already implies the database (as defined in the ODBC setup). in other words. You can specify a Database= argument with either a DSN or DSN-less connection. • The CursorLocation property determines where a cursor is to be located (similar to how you set the cursor library under RDO). You normally would not want to see any changes until they are committed to the database. Specifying a different database has the effect of altering the DSN’s definition. However. Description Provider is using a different isolation level. you should use the server-side cursor.0 version by the time this book is printed. the provider name is SQLOLEDB.OLEDB.” meaning that you cannot see changes made in other transactions until they have been made permanent (committed). You should not be creating large record sets in the online transaction environment. For instance.2 summarizes the possible values. Specifying a default database allows you to omit this information. The provider name is Microsoft. which does allow you to see changes made in other transactions even if they have not been committed. ADO will manage the cursor. The property specifies the isolation level of the cursor. (Microsoft may have delivered a Jet 4. Note that adUseNone is obsolete and is retained for backward compatibility only. Isolation can be considered similar to variable scope in Visual Basic.3. For Oracle.51. For the former. the exact parameters may vary from database driver to database driver. • The DefaultDatabase property is not available with all OLE DB providers and is not available with RDS. The opposite of adXactCursorStability is adXactReadUncommitted (these two constants are mutually exclusive). adUseServer specifies that the server will manage the cursor. You will normally want to retain the default values. this is more efficient and the cursor is more sensitive to changes made by other users.As with RDO. The value adUseClientBatch is synonymous. My recommendation is that if you are generating a large result set. you will do this when generating a report. This provides some flexibility in that the client-side cursor often has features not supported by a server-side cursor. • The IsolationLevel property can be set at any time but does not take effect until the next transaction begins. Constant adXactUnspecified Table 7. adXactCursorStability specifies that you will use “cursor stability. The value adUseClient specifies that a local cursor will be used. not specifying cursor stability has a devastating impact on performance at the database level because of all the extra work the database has to do. you can only specify adUseClient. Microsoft also delivers an OLE DB driver for Jet. For the specifics of these and other OLE DB provider connection strings. For larger record sets. adXactChaos specifies that the transaction cannot overwrite pending changes from more highly isolated transactions. This has implications when you join together two different data sources where you would normally have to qualify object names with the database name.2 Valid IsolationLevel constants. adXactIsolated specifies that the cursor essentially works oblivious to and invisible from all other transactions. It specifies a default database for the Connection. which is also on by default.

calling one of these methods does cause an error. Read and write. Others are denied read permission.3 Valid Mode constants.3. In the following code snippet. • The State property is used to determine the current state of the connection. • Cancel cancels the current asynchronous operation (either an Execute or a Connect). or some other provider-specific command text. CommitTrans. transactions are not supported. If this property is not present. adStateExecuting and adStateConnecting indicate that an asynchronous command execution or connection is in process. • The Execute method is used to execute a Command object. If the command is a row-returning query. No one can open the connection with any permissions. I discuss transaction and concurrency management in Chapter 11. • The Mode property specifies the read and write permissions.) Can see changes in other transactions only after they have been committed. and ad-StateOpen indicates that it is open. Constant adModeUnknown adModeRead adModeWrite adModeReadWrite adModeShareDenyRead adModeShareDenyWrite adModeShareExclusive adModeShareDenyNone Table 7.adXactChaos adXactBrowse (Default. adXactReadCommitted Same as adXactCursorStability. Can view changes in uncommitted transactions. The Connection object supports eight methods. the first example is used for non-row-returning queries. but you can requery to refresh the record set with those changes. adXactIsolated Transactions are isolated from other transactions. and RollbackTrans methods are used in transaction management. if the object does not support transactions. and the second is for queries that do return rows. table name. If the provider supports transactions. Unlike with RDO.) Cannot overwrite pending changes from more highly isolated transactions. adXactRepeatableRead Cannot see changes made in other transactions. Others are denied write permission. Description Permissions have not been or cannot be set. RollBackTrans undoes all changes to the record set during the current transaction and begins a new transaction. The other constants are listed in Table 7. No one else can access the data source. adXactReadUncommitted Same as adXactBrowse. Write-only. most of which are similar to their RDO counterparts: • The BeginTrans. adStateClosed indicates that it is closed. You can only set it before making the connection to the data source. the Properties collection will have an object named Transaction DDL. adXactSerializable Same as adXactIsolated. adXactCursorStability (Default. The CommandText argument is an SQL statement. CommitTrans makes all changes to the record set during the current transaction permanent on the database and begins a new transaction. Use BeginTrans to begin a transaction. Read-only. For RDS. stored procedure. The . it must be adModeUnknown. the results must be assigned to a RecordSet object.

as shown in the next example. You will use the OpenSchema method to retrieve information from the database and help automate the process of constructing reports. You can think of a schema as a schematic of the database. UserID. You may set Option to adAsyncConnect to cause the connection to occur asynchronously. The criteria argument is a further refinement of the query_type. Options) Table 7.5.Execute _ (CommandText.5. as shown in the code example.OpenSchema _ . ConnectionString was described earlier in this section in “Using The Connect String. CommandText is a table name. RecordsAffected. CommandText is a stored procedure. connection. The syntax is shown in the following code snippet. (Only the more commonly used query types are shown. Constant adCmdText adCmdTable adCmdTableDirect adCmdTable adCmdStoredProc adCmdUnknown adExecuteAsync adFetchAsync • Open is used to establish a connection to a data source. The next code example shows the syntax for the method. that opens two schemas using the adSchemas query type. Under RDS. Set arsSchema(1) = acon. which are from the second command in the code example. Type of command in CommandText is not known. this value will be -1. It is used to return schema information from the database.4 Valid Execute constants.) You specify criteria in the form of an array. it is the layout of tables and columns. which you can find on the CD-ROM. Options Set recordset = connection. Generate an SQL query returning all rows from the table named in CommandText. When executed. The query_type parameter is one of the constants listed in Table 7. The Options argument specifies how to interpret CommandText and whether to perform the operation asynchronously.OpenSchema(adSchemaTables) Set arsSchema(2) = acon. so all the tables are brought back. such as an SQL statement.RecordsAffected property is a Long returning how many records were affected by the command. connection. Execute asynchronously.4 lists possible values. Remaining rows after the initial quantity specified in the CacheSize property should be fetched asynchronously. The code does not specify a criteria argument. as also shown in Table 7. Figure 7. Description Evaluate CommandText as a command. show only views. Table 7.” UserID and Password specify the user ID and password for the connection. which is read-only.Open ConnectionString. Option • The OpenSchema method has no counterpart in DAO or RDO. If there was an error. Return all rows from the table named in CommandText. refer to the VB help file for a complete listing. The second two. This command is the basis for further refining the Ad Hoc Report Writer project from Chapter 6. RecordsAffected. Password. the connection is not actually made until a RecordSet is opened. Notice that the first two text boxes show the table name and type.Execute CommandText.3 shows an application. All the arguments are optional. it returns a RecordSet of type static-cursor.

3 The ADO Open Schema demonstration program. All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Empty.(adSchemaTables. Query Type adSchemaColumns Criteria TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME adSchemaForeignKeys PK_TABLE_CATALOG PK_TABLE_SCHEMA PK_TABLE_NAME FK_TABLE_CATALOG FK_TABLE_SCHEMA FK_TABLE_NAME adSchemaPrimaryKeys PK_TABLE_CATALOG PK_TABLE_SCHEMA PK_TABLE_NAME adSchemaProcedures PROCEDURE_CATALOG PROCEDURE_SCHEMA PROCEDURE_NAME PARAMETER_TYPE adSchemaTables TABLE_CATALOG TABLE_SCHEMA TABLE_NAME TABLE_TYPE adSchemaViews TABLE_CATALOG TABLE_SCHEMA TABLE_NAME Figure 7. "VIEW")) Table 7. Empty. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement.5 OpenSchema query types and optional criteria. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Array(Empty.

and the second list box is filled with all the columns on that table using this short piece of code: Private Sub lbTables_Click() .4 This screen allows the display of all the columns in any table. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- You can see the beginning of the ad hoc report writer in the application shown in Figure 7. The left-hand listbox is filled in with the names of all tables on the database. the user can click any table. the user clicks the Tables or the Views button. After connecting. click the chapter and section titles.MoveNext Loop End Sub The View button works in a similar manner. Once the listbox is filled. "TABLE")) Call Showtables Figure 7.4.EOF lbTables.AddItem arsSchema(1)!Table_Name arsSchema(1). This is done with the following code: Set arsSchema(1) = acon. Empty.OpenSchema _ (adSchemaTables.To access the contents. The code then loops through the RecordSet and populates the listbox: Private Sub Showtables() lbTables. Empty.Clear Do While Not arsSchema(1). Array(Empty.

5 shows an application.Name Next Next Each Property object has four properties itself. Empty.Clear Do Until arsSchema(2).OpenSchema _ (adSchemaColumns. . (The Parameter object. Table 7. With the Field object.Name & " : " & aprop.6 Valid Attributes constants for Property objects. I have clicked the BaseTableName property.Text If sTable = "" Then Exit Sub ' Retrieve the column names Set arsSchema(2) = acon. The code to iterate through the properties is not terribly complex. Figure 7.Properties lbProp(3). The following example iterates through each of the Field objects (afld) in a RecordSet (ars) and. the textbox shows that the Value is employee. contained on the CD-ROM.AddItem arsSchema(2)!Column_Name arsSchema(2).AddItem _ "-" & afld. The Attributes property is one or more of the constants listed in Table 7.Dim sTable As String sTable = lbTables. the application returns its value in the textbox. when present.5.5 The ADO Properties demonstration program.) Figure 7. and Field objects all have a Properties collection containing provider-specific Property objects.AddItem afld.Name For Each aprop In afld. When you click any property. its value is listed.EOF lbColumns. along with its Properties collection. Command. also has a Properties collection. for each.Fields lbProp(3). that iterates through each of the four Properties collections and lists their names in listboxes on each tab page. each Field in the RecordSet is listed. RecordSet. The Name property identifies the property. If you click the Field name itself. Array(Empty. Empty)) lbColumns.6. In Figure 7.MoveNext Loop End Sub The Properties Collection And Property Object The Connection. sTable. iterates through each Property object (aprop): For Each afld In ars.

Constant adPropNotSupported adPropRequired adPropOptional adPropRead adPropWrite Description Indicates that the property is not supported by the provider.SQLState & vbCr & _ "Native: " & aErr.Errors. Any time you perform an action that might result in an error or warning. is much like its DAO and RDO counterparts. The Errors Collection And Error Object The Errors collection.Open sCon If acon. the collection is cleared and one or more new Error objects is placed into the collection. Property can be read.Description & vbCr & _ "SQL State:" & aErr. consisting of Error objects. . Any time a provider (data source) error occurs. The following code example illustrates this: Set acon = New ADODB. Property can be written to.6. Some provider messages are added to the Errors collection but do not halt program execution. you should check the collection’s Count property to ensure there were no messages.NativeError & vbCr & _ "Source: " & aErr.Errors. you should first invoke the Clear method of the collection to clear any entries.Clear ' Make new connection acon.Source MsgBox sMsg Next End Sub The code example generates a message box similar to what is shown in Figure 7. Following the database operation.Connection ' Clear any errors acon. Value of this property must be set before data source is initialized.Number & "-" & aErr.Errors) End If Private Sub ShowErrors(errs As Errors) Dim aErr As Error Dim sMsg As String For Each aErr In errs sMsg = "Message from the data provider:" & vbCr & _ aErr. Value of this property does not need to be set before data source is initialized.Count > 0 Then ' Message from the data provider Call ShowErrors(acon.

7 Error message detailing an invalid SELECT statement. Read EarthWeb's privacy statement. the NativeError property is the data provider’s own error code. It is a five-character string. Figure 7. Generally. . The Error object has several properties and no methods. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. SQLState corresponds to the ODBC SQL state.) Figure 7. as documented in the ANSI SQL standards.7 shows the text returned from a data provider for an invalid SELECT. Conversely. Copyright © 1996-2000 EarthWeb Inc. they are handled by Visual Basic’s normal runtime error-handling system. (The sample Properties program on the CD-ROM deliberately invokes an error and then recovers to “fix” the problem. this is the data provider itself. The Source property is the name of the object in which the error was generated. which is enumerated in your ODBC driver documentation. The Number property is similar to the Err object’s Number property and uniquely identifies the error (or warning) condition. ADO errors themselves are not entered into the Errors collection. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.6 Message from the data source provider being displayed to the user.Figure 7. The Description property comes from either ADO or the data source provider itself and is a short description of the error condition.

click the chapter and section titles.ActiveConnection = acon • The CommandText property is a string containing the command to be executed. you can specify a connecting string (see the ConnectString property of the Connect object earlier in this chapter) in which case ADO will create a Connect object but will not assign it to a variable. an existing Command. It essentially represents a command to be executed by the data provider—typically but not necessarily an SQL statement.To access the contents. You can’t execute a command outside of the context of a valid connection. a stored procedure. . ADO sets the Command object’s ActiveConnection property to Nothing automatically. if you close the connection. The command might be an SQL statement.CommandText = "Select * from employee" • The CommandTimeOut property is a long with a default of 30 that specifies how long the command can execute before generating an error. The following example sets the ActiveConnection property of acmd. a table name. The following example sets the CommandText property to an SQL SELECT statement: acmd. Setting ActiveConnection to Nothing disassociates it from a Connection. Optionally. the Command object has a Parameters collection. The Command object has several properties: • The ActiveConnection object is used to associate the Command object with a Connection object. to the previously opened Connection acon: acmd. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Command Object The Command object is much like the DAO QueryDef and RDO rdoQuery objects. Conversely. If the command is parameterized. or some other command recognized by the data provider.

For short. • The State property indicates the current state of the object. adStateClosed indicates that it is closed. The Type argument specifies the data type of the parameter. With adCmdTable. whereas adStateOpen indicates that it is open. at which time ADO will validate it. you can use a record-returning command to create a RecordSet. • The Prepared property is a Boolean that. as an SQL statement. (Default) The type of command in the CommandText property is not known. adStateExecuting indicates that an asynchronously executing command is still executing. as listed in Table . If any rows are returned. the data provider attempts to generate a query that will return all columns and rows from the table name specified in the CommandText property.7 Valid CommandType constants. they are discarded. To execute a Command. Description CommandText is a command such. Generate an SQL query returning all rows from the table named in CommandText. Use the CreateParameter method to create a new Parameter object using the syntax shown in the next code example. adExecuteNoRecords CommandText is a command or stored procedure that does not return rows. which I discussed earlier in this chapter in the section “The Connection Object. Return all rows from the table named in CommandText. If the command is executed asynchronously. adCommandFile CommandText is a saved (persisted) RecordSet. you will normally set this property to adCmdText or simply leave it at its default of adCmdUnknown. use its Execute method. For SQL statements. CommandText is a stored procedure. • The CommandType property is one of the values listed in Table 7. causes the data provider to prepare (compile) the command before first running it. It must be combined with adCmdText or adCmdStoredProc. adExecuteNo-Records indicates that the command is an action query (for example. Not all providers support command preparation. you can use the Cancel method while it is executing to halt it. The data provider may or may not generate an error if it doesn’t support preparation. For longer-running commands or if the command will be executed repeatedly. Constant adCmdText adCmdTable adCmdTableDirect adCmdStoredProc adCmdUnknown Table 7.7 and tells ADO how to interpret the CommandText property. an UPDATE statement) that returns no rows.A value of 0 specifies that there is no timeout. if set to True.” As noted. You must manually append the Parameter to the Parameters collection. it generally doesn’t make sense to prepare the command because this also takes time. one-time commands. preparing it first probably makes sense.

1 earlier in this chapter. The Direction argument is used in the same manner as the DAO and RDO Direction counterpart. Value) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.7. The Size argument specifies a maximum length or size where the data type is variable length. Type. . Read EarthWeb's privacy statement. or both. See the Direction property of the Parameter object for more information.CreateParameter (Name. output. _ Direction. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Set parameter = command. The Value argument sets the actual data value stored in the parameter as an optional Variant. Copyright © 1996-2000 EarthWeb Inc. Size. All rights reserved. it sets whether a parameter is input.

and it generates an error if there are not enough parameters.) The CommandText property of the Command object has five question marks. as discussed earlier in this chapter. each of which represents a placeholder for a parameter. click the chapter and section titles. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Parameters Collection And Parameter Object The Parameters collection and Parameter object work similarly to their DAO and RDO counterparts. emp_dept_no. Listing 7.1 Using parameters in ADO.To access the contents.CommandText = _ "Select emp_no.1 shows a query being constructed with five parameters. Listing 7. emp_fname. " & _ . " & _ "emp_ssn. emp_lname. Parameters represents all the parameters or arguments to a query or stored procedure. See “The rdoParameters Collection And rdoParameter Object” in Chapter 6 for a generalized discussion of parameterized queries and stored procedures. (The running application is shown in Figure 7. then. ADO expects. Each Parameter object has a Properties collection. emp_dob. Private Sub cmdRun_Click() Dim sSex As String * 1 Dim iCtr As Integer If Option1 Then sSex = "M" Else sSex = "F" End If ' New command object Set acmd = New Command acmd. that five parameters will be supplied.8 and is included on the CD-ROM.

emp_fname" acmd. sSex) Set aparm(1) = acmd. Val(txtDeptTo)) ' Append the parameters For iCtr = 0 To 4 acmd. • The Attributes property is used to describe the Parameter. _ adParamInput. After the parameters are created. 1. The Direction is set to adParamInput. In each. adNumeric. . Val(txtDeptFrom)) Set aparm(4) = acmd."emp_salary. adParamNullable indicates that the Parameter can accept Null values. adNumeric. . adNumeric.CreateParameter("SalFrom". adLockOptimistic. You use the CreateParameter method of the Command object to create the five needed parameters (previously declared as an array of type Parameter).CreateParameter("DeptTo". Val(txtSalTo)) Set aparm(3) = acmd. . but I could have been supplied it after the fact as well (aparm(0). an appropriate data type is supplied. . I also supplied the value of the parameter.ActiveConnection = acon ' Create Parms and Set Values Set aparm(0) = acmd. I append them to the Parameters collection and then execute the query creating an output RecordSet. indicating that the parameter is an input parameter. and adParamLong indicates that the Parameter can accept very long binary or character data with the AppendChunk method. adCmdText Call ShowRecs End Sub Figure 7.Append aparm(iCtr) Next ' New RecordSet Set ars = New Recordset ars. _ adParamInput. Unfortunately.Open acmd. _ adParamInput.CreateParameter("Sex". ADO does not automatically create the Parameter objects as do DAO and RDO.CreateParameter("DeptFrom". it is more appropriate for stored procedures. adOpenDynamic.CreateParameter("SalTo". . It can be one or more of the following constants: adParamSigned indicates that the Parameter accepts signed numbers.8 A parameterized query screen. _ adParamInput. _ adParamInput. This could have been omitted.Parameters. adNumeric. Val(txtSalFrom)) Set aparm(2) = acmd. emp_gender " & _ "From employee " & _ "Where emp_gender = ? " & _ "and emp_salary between ? and ? " & _ "and emp_dept_no between ? and ? " & _ "order by emp_lname. . adChar.Value = sSex).

Note that the VB documentation specifies some data types that you are not likely to encounter. where data is the data you are appending to the Value property of the Parameter. All rights reserved. adParamOutput for output parameters. so it is important that you set this property correctly to prevent program errors. Read EarthWeb's privacy statement.• The Direction property is used to specify the type of Parameter. particularly for stored procedures. A number with a precision of 11 and a scale of 2 is 11 digits wide with 2 of those digits to the right of the decimal. .1) require that you set the precision and scale of the number. • The Value property sets or returns the actual value of the Parameter. You use this method when you need to move large amounts of character or binary data into a Parameter. The Parameter object has only one method: AppendChunk. ADO reserves memory based on this property. When you use this method. and precision refers to how many of those digits are to the right of the decimal point. and adParamReturnValue for parameters that are used as return values (such as the number of rows returned from a stored procedure). • The NumericScale property sets the scale of numeric values. the data provider can determine the direction of the Parameter but. • The Size property sets the maximum width of character data types. Copyright © 1996-2000 EarthWeb Inc. You can do this as part of the CreateParameter method (as I did in Listing 7. if it can’t.1. Certain SQL numeric data types such as adNumeric (see Table 7. you need to specify the Direction yourself. Its data type is Variant so that you can use any underlying data type.AppendChunk data.1) or after the parameter has been created using the syntax parameter. as listed in Table 7. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.Direction = constant. Subsequent calls add data to the end of the existing data. The first time you call this method. Scale refers to how many digits are in the number. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. be sure that the Attributes property has adParamLong set. adParamUnknown indicates that the Direction is unknown. Use the object browser to see a complete listing. whereas Precision sets the precision of numeric values. The syntax for the method is parameter. adParamInputOutput for parameters that are both input and output. such as adVarChar. • The Type property specifies the data type of the Parameter object. Normally. any data in the Parameter is overwritten. where constant is equal to one of the following values: adParamInput for input parameters.

I expand upon these concepts in the next several chapters. On the CD-ROM. The RecordSet object has two collections: Properties and Fields. ADO uses the terms records and fields. edit. The Field objects work in essentially the same manner as they do with DAO and RDO (where they are called rdoColumns). Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The RecordSet Object The RecordSet object is the ADO object with which you will interact the most. The application is capable of opening multiple maintenance forms within an MDI form.9 shows an employee maintenance application running. and delete them. Figure 7.To access the contents. much like DAO. Where RDO refers to rows and columns. NOTE The CD-ROM has a number of applications that illustrate the use of RecordSet objects. so I leave it until then to dissect and discuss the applications themselves. It represents a set of records from the data provider and provides the ability to scroll through the records as well as add. You can use shorthand to reference the value of any field using the familiar exclamation-point convention: ars!emp_no . the application name is ADOEmployeeMaint. The default property of the RecordSet is the Fields collection. and the default property of individual Field objects is Value. Figure 7.9 The employee maintenance application. click the chapter and section titles.

then the forward-only cursor is more efficient than the dynamic cursor. ADO. Set the cursor type before opening the RecordSet or when you use the Open method. but they are outweighed by the similarities. If you have used DAO RecordSet objects or RDO ResultSet objects. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. You would normally use this type of cursor when building reports. you must explicity call the CancelUpdate method. • The keyset cursor is similar to the dynamic cursor except that it prevents access to records that other users have added. Note that not all cursor types are supported by all data providers. . There are some differences. then you should be pretty comfortable with the ADO RecordSet. however. you use a cursor. and it prevents manipulation of records that other users have deleted. ADO provides four types: • The dynamic cursor allows unrestricted movement forward and backward through the RecordSet. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. • The forward-only cursor is identical to the dynamic cursor except that you can only move forward through the RecordSet. Read EarthWeb's privacy statement. (A record can be deleted from the database after you have retrieved it into your RecordSet). All rights reserved. you may or may not be able to use bookmarks to move. For instance.To move through a set of records. NOTE In DAO and RDO. moving to a new record or row without first saving your changes causes those changes to be lost. • The static cursor creates a nonupdatable RecordSet that allows unrestricted movement but does not see changes made by other users. To not save the changes. Depending on the data provider. You want to use the cursor model that meets your needs while using the least amount of resources. Copyright © 1996-2000 EarthWeb Inc. automatically saves your changes when you move to a new record. if you only need to loop through the records once.

_ adStatus As ADODB. _ adStatus As ADODB.EventStatusEnum. _ adStatus As ADODB. _ ByVal pRecordset As ADODB.EventStatusEnum. especially when performing asynchronous operations. ByVal pError As ADODB.EventReasonEnum. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The RecordSet object supports a number of events that are useful. _ ByVal MaxProgress As Long.Error. _ ByVal pError As ADODB. I discussed some generalities about ADO events earlier in this chapter in the section “The ADO Event Model.EventStatusEnum.EventStatusEnum.Recordset) Private Sub ars_MoveComplete _ (ByVal adReason As ADODB. _ ByVal pRecordset As ADODB. _ . _ ByVal pError As ADODB. _ ByVal pRecordset As ADODB. _ ByVal Fields As Variant.” In all RecordSet events.Error.Recordset) Private Sub ars_RecordChangeComplete _ (ByVal adReason As ADODB.To access the contents. _ adStatus As ADODB. _ ByVal pRecordset As ADODB.EventReasonEnum. The syntax of each event follows: Private Sub ars_EndOfRecordset(fMoreData As Boolean. _ ByVal pRecordset As ADODB. _ adStatus As ADODB.Recordset) Private Sub ars_FetchProgress(ByVal Progress As Long.Recordset) Private Sub ars_FetchComplete(ByVal pError As ADODB.EventStatusEnum.Recordset) Private Sub ars_FieldChangeComplete(ByVal cFields As Long. pRecordSet is passed as a reference to the RecordSet for which the event occurred.Error. _ adStatus As ADODB. click the chapter and section titles. _ ByVal cRecords As Long.Error.EventStatusEnum.

_ ByVal Fields As Variant.Recordset) Private Sub ars_WillChangeRecordset _ (ByVal adReason As ADODB. MoveNext.Recordset) Private Sub ars_RecordsetChangeComplete _ (ByVal adReason As ADODB. you could add more records to the RecordSet. adStatus As ADODB.EventStatusEnum. Open. FetchProgress is called periodically during an asynchronous fetch operation. _ ByVal pRecordset As ADODB. CancelUpdate. The Fields argument is an array containing those Field objects that will be or were changed. cRecords indicates how many records will be or were changed. _ ByVal pRecordset As ADODB. such as MoveFirst or MoveNext. The WillChangeField event is called before the Field is changed. It is conceivable that. • MoveComplete is triggered at the end of any Move operation. Unless adStatus is set to adStatusCantDeny. MovePrevious. set fMoreData to True. • The RecordSetChangeComplete event is called after a RecordSet has been changed . and MaxProgress is an estimate of how many records are expected to be fetched. _ ByVal pRecordset As ADODB. whereas the WillChangeRecord event is called immediately before one or more records are changed.Recordset) Private Sub ars_WillMove _ (ByVal adReason As ADODB. The WillMove event is where you normally place any final edits of data changes. • The FieldChangeComplete event is called after a Field object in a RecordSet has been changed.EventReasonEnum. The WillMove event is triggered immediately before any of the following methods: AddNew. and Resync. and cFields is a count of the number of objects in the array. Progress is a count of how many records have been fetched into the RecordSet so far. _ adStatus As ADODB. • FetchComplete is called whenever a fetch operation has completed. _ ByVal pRecordset As ADODB. Update.EventStatusEnum. _ ByVal pRecordset As ADODB. _ adStatus As ADODB. Move. you can cancel the operation by setting adStatus to adStatusCancel.EventReasonEnum. _ adStatus As ADODB. This is where you want to place any code that updates the screen based on the now current record. and UpdateBatch. CancelBatch. Delete. MoveLast. Bookmark. _ ByVal pError As ADODB. Delete.EventStatusEnum.Recordset) Private Sub ars_WillChangeField(ByVal cFields As Long. There is no corresponding BeginningOfRecordSet event.EventStatusEnum. The following methods trigger these events: AddNew.EventReasonEnum.Error.EventStatusEnum. _ adStatus As ADODB.EventReasonEnum.Recordset) • The EndOfRecordSet event is triggered by an attempt to move beyond the end of the RecordSet. • The RecordChangeComplete event is called immediately after one or more records in the RecordSet are changed. MoveFirst. _ ByVal cRecords As Long.Recordset) Private Sub ars_WillChangeRecord _ (ByVal adReason As ADODB.ByVal pRecordset As ADODB. If so. while in this event procedure. Requery.

if you set CacheSize to 20 records. The following example sets a page size of 20 and then moves to page 3. It can also be one of the following constants: adPosBOF indicates that BOF is True. The default is 10. You can use bookmarks between the two RecordSet objects interchangeably. The following code example illustrates saving a bookmark and then scrolling to it: Dim vBookMark As Variant vBookMark = ars. or Resync method. adUseServer specifies that the server’s cursor services are to be used. Open. Valid values are adOpenForwardOnly.Bookmark = vBookMark • The CacheSize property sets the number of records that are buffered locally (at the client). ' Set page size ars. The property can be set at any time but only affects the next retrieves. you might set this property to 20. and . you cause the RecordSet to scroll to the first record of the specified page.Bookmark ' Move to the last record ars. This specification can be more efficient but may not have all the functionality of client-side cursors.MoveLast ' Move to saved position ars. which is the first record on page 3. Filter. You may find that with certain data providers. adOpenKeySet. • BOF and EOF are Booleans that. Also. When you attempt to move to the 21st record. If there are no records. if True. • Bookmark is a variant with which you can record the current record and return to it in the same way as in DAO and RDO. The RecordSet object has a number of properties that help you monitor or manipulate it: • The PageSize property allows you to break your RecordSet set into logical pages. • The CursorType property sets the RecordSet type as discussed at the beginning of this section. The current record will then be 41. Note that the last page might not be full (there could be fewer records on it than specified in PageSize).AbsolutePage = 3 • The AbsolutePosition property is a one-based reference to the current record number. If you use the Clone method on the RecordSet.PageSize = 20 ' Move to page 3 ars. adPosEOF indicates that EOF is True. and adPosUnknown indicates the RecordSet is empty or that the provider does not provide this property. adUseClient specifies that the cursor will be maintained locally. when the RecordSet is opened. indicate the current record is before the beginning of the RecordSet or after the end. adPosUnknown is equal to -1. the AbsolutePosition and RecordCount properties are unavailable if you use adUseServer. adOpenDynamic. You can use the Resync method to force records already cached to reflect changes made by other users. see the RecordCount property later in this section. This allows you to take advantage of the AbsolutePage property. if you had a screen that displayed 20 records at a time. both properties will be True. • CursorLocation specifies where the cursor is to be located. the new RecordSet inherits all the saved bookmarks as well. Requery. For instance. The WillChangeRecordSet is called immediately before those methods. For instance. which makes it compatible with DAO record sets and RDO result sets where -1 indicates no records or rows. the first 20 records are read and cached locally. By setting this property. PageSize sets or returns the number of records in a logical page. PageCount returns the total number of pages in the RecordSet.due to the Close. another set of 20 records is read.

adLockOptimistic specifies that a record is only locked when it is updated. properties such as AbsolutePosition reflect the filter. For batch mode. adLockBatchOptimistic specifies that records will not be locked when edited and that the updates will be done in batch mode (and locked at that time). You can set the filter to a criteria string using comparison operators such as “EMP_LNAME = ‘Smith’” and you can join those comparisons together using Boolean operators such as And and Or.8. then ADO cannot determine the number of records. If the RecordSet does not support approximate positioning or bookmarks. specifies that the records cannot be altered. There are some restrictions on how you nest these (see the VB help file for more details). and adEditAdd indicates that the current record is new. Optimistic locking. of course.8 Valid Filter constants. You can also set Filter to an array of Bookmarks. raises concurrency issues that I address at more length in Chapter 11. View only the most recently cached records. but the changes have not been saved. Note that the details of how locking is implemented may vary based on the provider. adEdit-InProgress indicates that the current record is being edited. Note also that you cannot use adLockPessimistic for local cursors. Pessimistic locking.adOpenStatic. • Use the MaxRecords property before the RecordSet is open to restrict the number of records retrieved. It allows you to specify a Field object Name to sort the results by.AbsolutePosition & " of " & ars. adLockPessimistic specifies that a record will be locked as soon as it is edited. Delete. Finally. • The EditMode property is used to return the edit mode of the current record. Constant adFilterNone adFilterPendingRecords adFilterAffectedRecords adFilterFetchedRecords Table 7. The following code example displays the current record number as well as record count: txtRecCount = ars. or UpdateBatch method. Setting the property to an empty string (“”) or to adEditNone removes any filtering. you must use either adOpenStatic or adOpenKeySet. adLock-ReadOnly. Description Remove the current filter.RecordCount • The Sort property is available only when adUseClient is set for CursorLocation. view only records changed but not yet saved to the server. The RecordSet will be accessed in that order. If you will be performing batch updates. • The LockType property sets the type of record locking. adEditDelete indicates that the current record has been deleted. so it is not generally recommended. adEditNone indicates that there is no edit in progress. If this property is equal to -1. the default. • The RecordCount property returns the number of records in the RecordSet. on the other hand. You can optionally specify the direction of the sort by appending ASCENDING or DESCENDING. has a tendency to create lock escalations on the server. • The Filter property is a variant that you can use to filter which records in the RecordSet can become current. then referencing this property will cause all records to be retrieved in order to determine an accurate record count. Resync. The following code example sorts a RecordSet of employee records by salary in descending order: . adFilterConflictingRecords View records that failed the last UpdateBatch attempt. When a filter is in place. View only records affected by the last CancelBatch. you can set it to one of the constants in Table 7.

next.Sort = "emp_salary DESCENDING" End if • The State property is used to determine the current state of the RecordSet. It can be an SQL statement. The record is new. and prior records. or a Command object. adRecConcurrencyViolation The record was not saved because optimistic concurrency was in use. adState-Connecting.If ars. MoveNext. The record was not modified. adRecPermissionDenied The record was not saved because the user has insufficient permissions. MoveLast. reference the object itself. The record was not saved because it refers to a pending insert. adStateExecuting. • Status returns status information about the current record.1. last. The record was modified. Constant adRecOK adRecNew adRecModified adRecDeleted adRecUnmodified adRecInvalid adRecMultipleChanges adRecPendingChanges adRecCanceled adRecCantRelease Table 7.9. adRecDBDeleted The record has already been deleted from the data source. not the Name property of the object. The record was not saved because it would have affected multiple records. or adStateFetching. adRecOutOfMemory The record was not saved because the computer has run out of memory. a file name (for a saved RecordSet). adRecObjectOpen The record was not saved because of a conflict with an open storage object. a stored procedure. adStateOpen. • The Source property indicates the source of the RecordSet. The new record was not saved because of existing record locks. The record was not saved because its bookmark is invalid. adRecMaxChangesExceeded The record was not saved because there were too many pending changes. as shown in Listing 7. The RecordSet methods are similar to those available in DAO and RDO: • Use the Move methods to move through the RecordSet. Description The record was successfully updated. a table name.CursorLocation = adUseClient Then ars. The record was deleted. The Move method allows you to move an absolute number of records forward or backward. adRecSchemaViolation The record was not saved because it violates the structure of the underlying database. Specify . The record was not saved because the operation was canceled. and MovePrevious scroll to the first.9 Valid Filter constants. If using the latter. Possible values are adStateClosed. It will contain one or more of the constants listed in Table 7. MoveFirst. adRecIntegrityViolation The record was not saved because the user violated integrity constraints.

“emp_salary < 90000”). You can optionally specify a starting point from which to move (the default is to move from the current record). which refreshes the records that meet the current Filter condition. criteria is a string containing the field name to be searched. The default is adSearchForward. If you specify 5. >. start specifies the position from which to start searching. For ReSyncValues. or adResyncUnderlyingValues. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. you can also specify a saved bookmark from which to start searching. You can specify instead adAffectCurrent. searchDirection.as an argument the number of records to move. You can optionally specify two arguments: AffectRecords and ReSyncValues. . The default is the current record. for example. Use the Resync method to refresh records in the RecordSet to reflect the changes of any other users. Specifying a negative number will cause the search to begin before the starting position. which is similar to the Find method available in the DAO Jet workspace. which specifies that changes are not overwritten and pending updates are not canceled. start) ' Example of searching for all last names beginning with S ars. it is the equivalent of closing and reopening it. The default is 0. and the value to be searched for (for example. searchDirection specifies in what direction to search. specify either adResyncAllValues. ' Syntax of the Find method Find (criteria. AffectRecords defaults to adAffectAll to refresh the entire RecordSet. or adAffectGroup. which causes any pending updates to be canceled. You can also use Like for pattern searches. and so on). Specify a valid Bookmark as a starting point. • Not well documented is the Find method. Alternatively. you can specify one of the following constants: adBookmarkFirst or adBookMark-Last. Note that using the Resync method does not retrieve rows added by other users. A negative number scrolls backward. note that if a row in the current RecordSet has been deleted by another user. Copyright © 1996-2000 EarthWeb Inc. adSearchBackward causes the search to occur backward from the starting position.Find ("emp_lname like 'S_*'") • Use the Requery method to re-execute the RecordSet. Read EarthWeb's privacy statement. the search will begin on the sixth row after the starting position. SkipRows. However. which refreshes only the current record. SkipRows specifies how many rows to bypass from the starting position before searching. Also. <>. both of which cause moving to start from the first or last record. The syntax is shown in the following code. the comparison operator to use (=. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved. an error will be generated and added to Errors.

To access the contents. • Update saves any changes made in the current record. The file is not closed until the RecordSet is closed. or adAffectAll. You can also set values using the optional Fields and Values arguments. The items in Values must correspond positionally to the Field objects and must be equal in number. Repeated calls to Save cause the records to be appended to the file. If there are any batch collisions. • The CancelUpdate and CancelBatch methods cancel pending changes. only filtered records are saved to the file. click the chapter and section titles. If you scroll from one record to another. Fields allows you to specify which Field objects of the RecordSet will be made available for editing. • UpdateBatch is used to update the database with pending changes. If you specify Fields. The syntax for the method is shown in the next code snippet.AddNew Array("emp_lname". The . 23000) • Delete is used to delete the current record. ADO automatically invokes the Update method. _ Array ("Smith". as in the AddNew method. you can add an optional argument to specify which changes are to be canceled. When Update is called. are much like those found in DAO and RDO. all the records that meet the current Filter criteria are deleted. Use the Filter and Status properties to find those records with conflicts. calls to the Update method save the changes within the RecordSet itself. Use adAffectCurrent. the current record remains current. If you are in batch mode. using the Save method. a message is added to the Errors collection. • You can save the RecordSet as a file. records aren’t saved to the database until you call the UpdateBatch method. "emp_salary"). a process known as persisting. • Use AddNew to add a new record. The following example illustrates: ars. "emp_fname". If you specify the argument adAffectGroup. You can optionally specify the Fields and Values arguments. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The RecordSet object’s editing facilities. adAffectAll is the default and causes changes to all records to be updated to the database. you can also specify Values as an array of values to place into each of the objects in Fields. While in batch mode. You can specify either the Name properties or the ordinal numbers of each of the Field objects in an array. outlined in the following list. The argument adAffectCurrent causes only the current record to be updated to the database. If the Filter property is set. "John". adAffectGroup. with some enhancements. adAffectGroup causes only changes to records that meet the Filter condition to be updated to the database. With CancelBatch.

a RecordSet may return True for adUpdate. indicating that there is nothing in the type and location of the cursor that would preclude updates.Clone • The final method of the RecordSet object is Supports. whose record set features the currently open RecordSet supports. When the cloned RecordSet is opened. the cloned RecordSet has the same locking as the original. RecordSet. adUpdate. Read EarthWeb's privacy statement. the nature of the data in the RecordSet set. adApproxPosition. and the data provider itself. the type of CursorType. However. The speculation is that these additions will include formats such as reports or other formatted data.Supports (adMovePrevious) Then MsgBox "Can Move Previous" Else MsgBox "Can Not Move Previous" End If • Constants that you can pass are adAddNew. Copyright © 1996-2000 EarthWeb Inc. The adApproxPosition tests whether the RecordSet supports the AbsolutePosition and AbsolutePage properties. note that the Supports method does not guarantee that the feature is available under all circumstances. adNotify. and the method returns True or False to determine if the feature is supported. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. but Microsoft has placed it the PersistFormatEnum structure. adMovePrevious. You pass it an argument of type CursorOptionEnum. The following example illustrates the Supports method by testing whether the MovePrevious method is supported: If ars. Also. Otherwise. adDelete.FileName argument is self-explanatory. All rights reserved. PersistFormat • The Clone method creates a copy of the RecordSet. which specifies a RecordSet format. . adBookMark. adResync. For example. Note that these features are largely a function of the type of CursorLocation. such as a multiple table join. It is currently the only value that can be specified. adFind. may mean that some fields will not be updatable. The default for PersistFormat is adPersistADTG. adHoldRecords indicates that you can retrieve more records without committing any pending changes. including all saved bookmarks. the current record is the first record. indicating that other formats will be added in the future.Save FileName. and adUpdateBatch. The following example creates a cloned RecordSet: Dim arsClone As RecordSet ' Clone the original RecordSet Set arsClone = ars. adHoldRecords. A saved RecordSet can be opened later using the Open method of the RecordSet. You can optionally specify adLockReadOnly to make the cloned RecordSet read-only. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Most of these are self-explanatory.

Other constants are used less often but are documented in the Visual Basic help file under “Attributes. The DefinedSize property of the Field object contains its maximum width in bytes and is typically used for character fields. which indicates that the Field can be updated. and size. and adFldRowVersion indicates that the Field object contains a time or date stamp. as noted earlier in this chapter in the section “The Properties Collection And Property Object.” • The Name property is the name of the Field as stored on the database or as specified in the command that retrieved the data. such as its value. Each Field object contains basic information about the field. • The Type property contains a constant indicating the basic data type of the field as listed in Table 7. click the chapter and section titles. The individual Field objects represent the individual fields in the RecordSet.1. usually for concurrency purposes. The Field object contains the Properties collection. whereas the NumericScale property returns the number of digits to the right of the decimal point. adFldIsNullable indicates that the Field can contain Null values. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Fields Collection And Field Object The Fields collection represents all the fields in a RecordSet. Some of the more common Attributes constants include adFldUpdatable.” • The Value property lists the current value of the Field. such as adVarChar. whereas the . adFldFixed indicates that the Field is fixed width. adFldLong indicates that the Field is a long binary field on which you can use the AppendChunk and GetChunk methods. • The Attributes property is one or more constants that describe characteristics of the Field.To access the contents. The ActualSize property returns the number of bytes actually stored in the Field. such as adNumeric. data type. The Precision property returns the number of digits in numeric fields.

10 shows an application that was quickly assembled using the Active Data control.DataControl object. it is almost identical to the Remote Data control. and the RDSServe. you can display the bitmap. The following example will retrieve the contents of the Field using a buffer size of 2.DataFactory object. It is included on the CD-ROM as ADOData-Control. See the AppendChunk method in the “The Properties Collection and Property object” earlier in this chapter.ActualSize Do Until lFldSize < 1 ' Read a chunk vBuffer = ars!emp_picture. The Field object has only two methods. Once the contents are read. Assume that you have a Field object named “emp_picture” that contains a bitmap picture of an employee. you must add it as a component via the Project|Components menu. The Active Data Control Like RDO and DAO. . which you can draw on your form to simplify programming.OriginalValue property contains the value of the Field when first retrieved from the database. Dim vBuffer As Variant Dim vPic As Variant Dim lFldSize As Long ' Size of the Field lFldSize = ars!emp_picture.0. In practice. Figure 7. AppendChunk and GetChunk. the RDS. Select the Microsoft ADO Data Control 6. Other ADO Objects ADO supports three objects used in Remote Data Services: the RDS. I discuss this and other concurrency issues in Chapter 11. Use GetChunk to make iterative calls to retrieve data from a Field and store it in a variable.048 bytes. ADO provides a data control.GetChunk (2048) lFldSize = lFldSize – 2048 ' Append chunk to variable vPic = vPic & vBuffer Loop The AppendChunk method appends data to a Field object. which are both used to manipulate long binary and character data fields.DataSpace object. This is a concern if another user has changed the record after you retrieved the RecordSet. To use it. The UnderlyingValue property retrieves the current value as stored on the database.

Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. It does not have a Validation event as does the intrinsic Data control. Read EarthWeb's privacy statement. Its properties are basically those of the Connection object. Some RecordSet properties are also exposed directly in the Active Data control. For developing an ADO application from scratch. Copyright © 1996-2000 EarthWeb Inc. but most RecordSet properties and all RecordSet methods are exposed via the RecordSet property of the control itself. The Active Data control supports the Refresh method. after covering those materials. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. instead. The main advantage of the Active Data control is the same as that of the Remote Data control and the intrinsic Data control: simplicity of programming at the expense of some flexibility in application design. .Figure 7. The biggest convenience is the fact that you can bind other controls directly to the Active Data control. It also has an Error event triggered when an entry is made to the Errors collection. All rights reserved. Where To Go From Here This chapter presented a fairly detailed overview of OLE DB and ADO. You should be fairly comfortable with ADO development. For more advanced database techniques. I move you into the realm of multitiered applications and Internet-based development in Chapters 12 and beyond. use the WillMove event. I encourage you to read Chapter 8. read Chapter 11. and the control can be considered a surrogate for the Connection object.10 An application built using the Active Data control. Chapters 9 and 10 expand on the concepts covered in this chapter. The Active Data control supports the same events as the RecordSet. If you plan to convert existing DAO or RDO applications to ADO. Finally. which rebuilds the RecordSet.

ADO Compared To DAO And RDO As I discussed earlier in the book. In prior chapters. in many cases. This chapter will help you convert existing applications from DAO or RDO to ADO. ADO offers VB developers a solid platform on which to develop client/server applications and. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 8 Converting To ADO Key Topics: • ADO vs. Also. I covered the key aspects of client/server development with ADO. DAO was Visual Basic’s first relational data access tool. Microsoft has attempted to incorporate the functionality of both DAO and RDO into ADO. unlike . object-oriented follow-up to DAO that offered a much more streamlined and powerful approach to database development—but it came at the expense of not being an ideal ISAM development tool. RDO and DAO • Converting from DAO to ADO • Converting from RDO to ADO • Whether or not to convert to ADO In the last chapter. may be superior to DAO or RDO. and RDO developers will have less trouble converting.To access the contents. click the chapter and section titles. but you may find it difficult at first to locate the property or method you are looking for. In particular. RDO was an event-driven. DAO developers who have done extensive work with Jet (such as replicas) may have an uphill battle in converting to ADO. ADO is more akin to RDO than it is to DAO. I discussed development with DAO and RDO and took the time to compare and contrast the three data models.

the Microsoft Active Data Objects 2. Although RDO. RDO applications should have little or no problem in terms of losing functionality.DLL. the Microsoft Active Data Objects 2. ADO also simplifies the data model while providing a more robust asynchronous. For DAO ODBCDirect applications. My recommendations on whether to convert are based on three questions: • Does ADO support your current functionality? For DAO Jet developers. You can use MSADOR15. ADO probably does include all needed functionality. is the one that you will use most often. ADO may offer enough advantages in terms of productivity that outweigh the very real economic impact of converting. event-driven programming environment. it is probably wise to wait until ADO evolves more. • Does ADO give you any technical advantages? Assuming the answer to the first question is yes. ADO Objects Although ADO has a nonhierarchical object structure. which may be a hurdle for some VB developers. There should also be a definite performance boost in ADO applications over DAO ODBCDirect.0 library. you might want to consider any advantages that ADO provides and factor those into your decision. Also.0 Recordset library. MSADO15. ADO is the wave of the future in terms of data access via Microsoft development tools and possibly non-Microsoft tools as well. say. ADO provides the capability of accessing relational and nonrelational data sources in a relatively transparent manner. If your present application works and fills your current and future business needs. consider the likelihood of having to do more development. ADO does not include all DAO functionality. why change it? On the other hand. may suffice to meet your needs. RDO developers may or may not see an immediate improvement in performance (although that should also come in time) but will benefit from the simpler data model and more elegant event model. ADO is nonhierarchical. This is a big boon to DAO ODBCDirect developers who will benefit immediately by having access to data-source-driven events. DAO will leave you with no options. the answer may well be no. Carefully review your DAO application. • Does it make economic sense to convert to ADO? This is really a two-part question. Clearly. many of the objects in . instead when you only need record set functionality. if you need to scale your application or migrate it to multitier models. there are actually two libraries. you need to add a reference to the DAO or RDO library in order to access the data objects in code. This “lightweight” library includes the Recordset and Field objects only. If you are performing tasks such as replication via the Jet engine. ADO References With DAO and RDO.DAO/RDO.DLL. With ADO. I am not a fan of technology for technology’s sake. and RDO will probably restrict your room for growth.

as summarized in Table 8. Connection objects are independent and thus do not need the equivalent of the Workspace or rdoEnvironment objects. ADO Events Like RDO. Properties. these events are entirely in the context of the Connection and Recordset objects. in some cases. Events related to the connection to the data source (including transactions) are largely within the Connection object. and events of those objects are largely part of the Connection or. Events related to the data itself are within the Recordset object. Previous Table of Contents Next . However. RDO ADO rdoEngine rdoError N/A rdoEnvironment rdoConnection rdoConnection N/A N/A rdoQuery rdoColumn rdoParameter rdoResultSet rdoTable N/A N/A N/A rdoPreparedStatement N/A Error Property N/A Connection Connection N/A N/A Command Field Parameter Recordset N/A N/A N/A N/A N/A DBEngine ADO has no object analogous to the DBEngine or rdoEngine objects. asynchronous communications.1 DAO. DAO Error Property Workspace Database Connection Container Document QueryDef Field Parameter Recordset TableDef Index User Group N/A Table 8.1. ADO permits event-driven. RDO. RDO. and ADO object cross-reference. methods. ADO’s events are a superset of those provided by RDO. Recordset object.ADO. and DAO are roughly analogous to each other.

Read EarthWeb's privacy statement. . Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved.

however. some DAO Jet functionality not present in ODBCDirect or RDO has been added to ADO. TIP Use Common Sense Before you start your conversion. although you might initially have difficulty finding them. use controls such as the Hierarchical FlexGrid control. and move that code to their ADO equivalents. As a pleasant surprise. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- ADO Properties And Methods As noted earlier. Most notable is a Find method. It may seem obvious. Before making that investment in time. I discuss these techniques in the next two chapters. it relies instead on the Filter property. back up all of your files. such as Validate. but you should never test on production data.To access the contents. consider creating a DataEnvironment object or even a data-aware class to act as the data source for your bound controls. . click the chapter and section titles. For instance. Active Data Control The Active Data control is largely compatible with the intrinsic Data control and the Remote Data control. which specifically say “OLEDB” in their description. You will also want to seek out Data control events. which allows you to filter out all but those records that failed the most recent batch update. ADO does not have a BatchCollisions property. Methods and properties that apply to ODBCDirect and RDO are present in ADO. You will have to add the control to your project and respecify its properties. Instead. Also be aware that some grid controls are not compatible with ADO. but that is a minimal investment. many DAO methods and properties that are unique to the Jet engine are entirely missing from ADO (although they may be added at some future point).

8. To illustrate the process of converting DAO and RDO applications. For instance. consider taking advantage of ADO events to accomplish the same purpose in a more streamlined manner. 3. I use two applications from Chapter 5. b. 6. If using only one Workspace or rdoEnvironment object. You might want to eventually modify code to take advantage of ADO functionality. Remove the reference to the DAO or RDO library. Add a reference to the ADO library. you are probably ready to take the leap. Globally replace all DAO/RDO variables with their ADO equivalents using Table 8. Correct as many as you can. but I am taking the attitude of just “getting it over and done with. Converting The DAO Application For the DAO to ADO conversion test. Of necessity.and RDO-specific functionality in each to provide overall guidance. I will use the Parameter Query project from Chapter 5 as well. looking for any obvious mistakes in methods or property uses. let it “settle down” by running it for a few weeks. Scan through the code. Microsoft or some third party may develop an approach that is more elegant. 10. Replace connection strings with their ADO equivalents (see Chapter 7). For DAO/RDO objects not represented in ADO: a. 7. 5. Some of the techniques are simple brute-force search and replace. Step through the code. if you were using the StillExecuting property in DAO to test for the completion of asynchronous operations. Modify declarations for the Connect and Recordset objects to include the WithEvents clause. Exercise all aspects of the program to shake out any remaining bugs or problems. 9. but there is enough DAO.Converting The Application If you have read this far in the chapter. Evaluate all RDO events and determine their ADO equivalents. Save your project and all modules to new names or to a new directory.” Follow these simple steps: 1. I chose the batch transaction program (DAOBatchUpdate on the CD-ROM) because . these applications are not as large as what you may be converting.1 as a starting point. globally replace it with a reference to a Connection object. I am going to use the sample batch update demonstration programs from Chapters 5 (DAO) and 6 (RDO). Globally replace references to the engine objects with an appropriate Connection object. 4. letting the compiler alert you to remaining syntax problems. You might want to follow along as I outline a straightforward methodology for converting. Move code from the RDO events to the new ADO events and delete references to the RDO events. 2. Once your application is working.

you want to replace all connection strings. a Workspace represents a database session. Copyright © 1996-2000 EarthWeb Inc. The code has just one: sConn = "ODBC. The revised connect string now looks like this: sConn = "PROVIDER=MSDASQL. The Batch Update Application The first step is to remove the reference to DAO and add a reference to the Microsoft Active Data Objects 2. which is a reference to the Microsoft ODBC data provider. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I also chose the parameter query application (QDefParmRSDemo on the CD-ROM) because it illustrates the use of Parameter objects and also because it uses the QueryDef and DBEngine objects not used in the batch update program. in the DAO connection string with PROVIDER=MSDASQL. is straightforward. If you refer to the code. See Chapter 7 for details about the Connection object’s Open method. you can simply replace the ODBC. The code has four such references.it exploits enough different methods and properties of DAO to be a valid example while being short enough to discuss within the space of this chapter. In ADO. the Connection object largely replaces this function. conEmp." & _ "UID=Coriolis.DSN=Coriolis VB Example.PWD=Coriolis" Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Globally replace conEmp with aConEmp.UID=Coriolis.Database=Coriolis. You need to find all places where wrkEmp is used and replace it with a reference to the Connection object." & _ "PWD=Coriolis. You can probably do a simple global replace in larger projects. ." The ADO connect string for an ODBC data source. As you will recall..DSN=Coriolis VB Example. Globally replace rsemp with arsEmp. All rights reserved. Next.0 library. which is what you will handle when converting from RDO or DAO/ODBCDirect. For this example. you will see four DAO objects declared in the cmdUpdate_Click event: Dim Dim Dim Dim wrkEmp As Workspace conEmp As Connection rsEmp As Recordset rsemp2 As Recordset The two Recordset objects are easy. Delete the wrkEmp declaration. Read EarthWeb's privacy statement.

The next several lines of code look like this: ' Now. For DSN-less connections. You can actually simply omit the PROVIDER argument because the default is MSDASQL. dbUseODBC) ' In order to do batch updating. its main purpose here is to establish an ODBC environment. Delete any references to creating a Workspace object. _ "Coriolis". Delete that line. You will specify these types of properties when you open the Recordset objects. You need to scan through your code for the most flagrant uses of DAO objects. you are probably 60 percent converted. the following lines of code immediately jump out: ' Create the workspace Set aconEmp = CreateWorkspace("ODBCWorkspace". Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Note that I also deleted the DATABASE= parameter as unnecessary. open the connection to the employee table sConn = "PROVIDER=MSDASQL. The DefaultCursorDriver property also has no equivalent in ADO.DefaultCursorDriver = dbUseClientBatchCursor Note that the Workspace variable has been renamed to a Connection variable. "Coriolis".DSN=Coriolis VB Example. which is the default under ADO anyway. Unfortunately. You will set these at the Connect object level now.To access the contents. At this point. aconEmp. set the default cursor ' driver prior to opening the connection. Other Workspace properties that you may need to deal with are isolation levels and timeout values. you can generally get away with simply deleting the ODBC argument. click the chapter and section titles. the remaining 40 percent of the work is a bit tougher. properties. and Close (which you will simply delete). Workspace methods that you need to spot are OpenDatabase (which you will replace with Open at the Recordset level)." & _ . The most obvious are uses of the Workspace object. and methods that have no one-to-one equivalency in ADO. In the code sample. OpenConnection (which you will replace with Open at the Connection level). sans Jet. The CreateWorkspace method is entirely unnecessary.

"UID=Coriolis.OpenConnection("CorEmp".PWD=Coriolis" Set aconEmp = aconEmp. before you open an object. Later in the code. _ dbOptimisticBatch) Replace it with these two lines of code using the same reasoning that applied earlier: Set arsEmp2 = New Recordset arsEmp2. if you want. you are merely replacing the existing code’s functionality without enhancing it. adLockBatchOptimistic. another Recordset was opened. . Change the OpenConnection method to the Open method of aconEmp as shown. _ adLockBatchOptimistic. add the adCmdText to make explicit that the Source of the Recordset is an SQL command. _ dbDriverNoPrompt. The dbOpenDynaset argument becomes adOpenKeySet. you can instead set the CursorType and LockType properties of the Recordset objects to adOpenKeySet and adLockBatchOptimistic prior to opening the Recordset objects." & _ "UID=Coriolis. Next.OpenRecordset _ ("SELECT * FROM EMPLOYEE".Open "SELECT * FROM EMPLOYEE".Open sConn ' Select from the employee table Set arsEmp = New Recordset arsEmp. If it is easier for you. aconEmp. aconemp. 0. _ adOpenKeySet.PWD=Coriolis" Set aconEmp = New Connection aconEmp.DSN=Coriolis VB Example. open the connection sConn = "PROVIDER=MSDASQL. adCmdText In ADO. The line of code now looks like this: Set arsEmp2 = aconEmp. _ dbOptimisticBatch) You will alter the code as shown here: ' Now. you need to replace the Workspace object’s OpenRecordSet method with the Open method of arsEmp. you will add the new Set…New lines of code as you did previously with aconEmp and arsEmp. Add the adLockBatchOptimistic argument to take into account that the DAO Workspace had a default of using batch updates.Open "SELECT * FROM EMPLOYEE". to have the connection open asynchronously. False. 0. Also. dbOpenDynaset. you must use either adOpenKeySet or adOpenStatic. dbOpenDynaset. adOpenKeySet. For the time being. NOTE I did not use the more intuitive adOpenDynamic type of Recordset because it does not support batch updating. You can add the adConnectAsync option later. sConn) ' Make sure the proper locking is set ' and open the record set Set arsEmp = aconEmp. adCmdText That pretty much takes care of any references to the Workspace object.OpenRecordset _ ("SELECT * FROM EMPLOYEE". For batch updating.

there is currently no ADO equivalent to the Force argument of DAO’s Update method to force updates to the database in the event of collisions. replace the method with UpdateBatch." MsgBox sMsg End If Instead. Also. Happily. • CancelUpdate—If doing batch updates. look for properties that have been replaced.Supports (adBookmark) The BatchSize property has been omitted from ADO. • Edit—Delete any lines that use this method." MsgBox sMsg End If By and large. Bookmarkable is replaced by the ADO Supports method: arsEmp. QueryDef. If your application uses the DBEngine. or Parameter objects. that takes care of the changes needed to run the application. For instance. The Recordset is placed into edit mode automatically any time you make changes to the record. A few key methods to spot are the following: • Update—If your code specifies the dbUpdateBatch argument.Bookmark = .BatchCollisions(0) sMsg = Str$(.BatchCollisionCount) & " records " & _ "have been altered by another user. BatchCollisionCount and BatchCollisions have been replaced by the Filter property.MoveFirst sMsg = arsEmp. Unfortunately.Filter = adFilterConflictingRecords If arsEmp. scan through the code for uses of the Recordset objects. you need to make additional modifications.Next.RecordCount > 0 Then arsEmp.RecordCount & " records " & _ "have been altered by another user. most of the methods and properties will work as is. set the Filter property to look for any batch collisions and then use the RecordCount property to see how many there are: ' Check to see if any collisions arsEmp. Previous Table of Contents Next . replace this method with the CancelBatch method.BatchCollisionCount > 0 Then ' Move to first collision to demonstrate ' use of the batchcollisions array . The example has a section of code that looks like this: If . I discuss these in the next section.

All rights reserved. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. Copyright © 1996-2000 EarthWeb Inc.

you move the declarations to the General section of the form module. Recordset. Let’s use an approach similar to how you converted the batch update project. The first step. of course. you remove the reference to DAO and add a reference to ADO using the References option on VB’s Project menu. QueryDef. to the object that provides the closest match in functionality. It employs the Database. The next step is to change object references to their ADO counterparts or. Change rsReport to arsReport. Globally change all references of dbCoriolis to aconCoriolis.To access the contents. The object declarations in the existing project follow: Dim dbCoriolis As Database Dim qdfDeptGenEmpSal As QueryDef Dim rsReport As Recordset Note that there is no explicit Parameter declaration because these objects are created dynamically by DAO when the QueryDef object is created. . Change the data type to Connection. click the chapter and section titles. Add the WithEvents clause to the Connection and Recordset declarations: Dim WithEvents aconCoriolis As Connection Dim acmdDeptGenEmpSal As Command Dim WithEvents arsReport As Recordset Note that in order to use the WithEvents clause. and Parameter DAO objects. is to save all the files under new names so that you don’t ruin the existing project. Next. Globally change qdfDeptGenEmpSal to acmdDeptGenEmpSal and the data type to Command. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Parameter Query Application The application from Chapter 5 used Microsoft Jet but would have worked just as well in an ODBCDirect workspace. where there is no counterpart.

However. EMP_SALARY FROM EMPLOYEE " & _ "WHERE EMP_DEPT_NO = [Dept] " & _ "AND EMP_GENDER = [Gender] " & _ "ORDER BY EMP_DEPT_NO. I created the application both ways (with and without explicit declarations).You must modify the connection string next.CommandText = _ "SELECT EMP_DEPT_NO. You also let the data provider default to MSADSQL instead of explicitly specifying it. EMP_NO. First. EMP_LNAME. If you open the project on the CD-ROM. you set its ActiveConnection and CommandText properties as shown: Set acmdDeptGenEmpSal = New Command acmdDeptGenEmpSal. "Coriolis".mdb" Set aconCoriolis = OpenDatabase(sCoriolis) Change these lines of code to this: sCoriolis = "DSN=VB Coriolis Example" aconCoriolis. EMP_GENDER. EMP_LNAME. the following code example shows you how. the code will execute somewhat faster.CommandText = adCmdText acmdDeptGenEmpSal. because you might choose to explicitly create the objects yourself. you will see that the explicit declarations and references are commented out. Next. Gender Char . you declare a new object. ADO will do that for you automatically. The QueryDef object dynamically created parameters by using the Jet version of a parameterized query: Set acmdDeptGenEmpSal = _ aconCoriolis.ActiveConnection = aconCoriolis acmdDeptGenEmpSal. " & _ "EMP_LNAME. _ "PARAMETERS Dept Integer. EMP_FNAME. EMP_NO. " & _ "SELECT EMP_DEPT_NO. On the CD-ROM. "Coriolis" You use a variation on the Connect object’s Open method this time by specifying the user and password as separate arguments. EMP_FNAME") You need to convert this to the more generic ODBC version (using question marks as placeholders) and create a Command object. EMP_FNAME You do not have to explicitly create Parameter objects. If you do it. The current string and connection to the database look like the following: sCoriolis = "c:\examples\coriolis. EMP_GENDER.CreateCommand("".Open sCoriolis. create two objects for the two placeholders in the command text: Dim aparmDept As Parameter . First. EMP_FNAME. EMP_SALARY FROM EMPLOYEE " & _ "WHERE EMP_DEPT_NO = ? "AND EMP_GENDER = ? " & _ "ORDER BY EMP_DEPT_NO. " & _ "EMP_LNAME.

which was merely used to ensure the RecordCount property was accurate.Parameters(0) = iDept acmdDeptGenEmpSal.Parameters("Gender") = sGender Parameter objects aren’t named in ADO (technically. You delete the MoveLast method in the DAO code sample.Parameters. You change that to a Do Until loop.Parameters("Dept") = iDept acmdDeptGenEmpSal. You also clean up the code listing where it looped through the resulting Recordset.Direction = adParamInput aparmSex. _ adOpenForwardOnly.Parameters.Open acmdDeptGenEmpSal.Type = adChar aparmSex.CreateParameter You next code the data types and directions of the parameters. the names are Param1.Direction = adParamInput aparmSex. code the actual Create statements: Set aparmDept = acmdDeptGenEmpSal.Size = 1 acmdDeptGenEmpSal. Simply change the Name property of the Parameters collection to the corresponding ordinal position: acmdDeptGenEmpSal.Parameters(1) = sGender The only other change of significance is where you open the Recordset.CreateParameter Set aparmSex = acmdDeptGenEmpSal. You specify the local cursor library to ensure the record count is accurate. which is somewhat easier to follow: . Param2. Strictly speaking. but it is good practice to be explicit: aparmDept. The DAO code sample looped through a For Next loop. adLockReadOnly The Open method of the Recordset references the previously created Command object.Append aparmSex The code uses the InputBox function to prompt for what department and sex to search for and then assigns those values as shown: acmdDeptGenEmpSal.Append aparmDept acmdDeptGenEmpSal. and so on).OpenRecordset(dbOpenSnapshot) You change it to the ADO format as shown here: Set arsReport = New Recordset arsReport. Under DAO. the data provider can normally determine this on its own.CursorLocation = adUseClient arsReport.Dim aparmSex As Parameter Next.Type = adInteger aparmDept. it looked like the next example after making the global changes: ' Set arsReport = _ ' acmdDeptGenEmpSal. .

EOF txtFields(0).MoveNext Loop End With The CD-ROM includes a second version of this project. .Text = !Emp_FName txtFields(4).' Display the results With arsReport Do Until . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc.Text = !Emp_Gender txtFields(2).Text = !EMP_DEPT_NO txtFields(1). which is a more natural presentation of the results. Read EarthWeb's privacy statement.1 The parameterized query application converted to ADO. The application is shown in Figure 8.Text = !Emp_LName txtFields(5). Figure 8. vbYesNo + vbQuestion) = vbNo Then Exit Do End If arsReport.Text = !Emp_Salary ' Display More? If MsgBox("Display More?". All rights reserved.1. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. which populates a grid control. The user is prompted for parameter values via textboxes instead of input boxes.Text = !Emp_No txtFields(3).

The project also takes advantage of the asynchronous communication opportunities available in RDO as well as the event-driven model presented in RDO. and test thoroughly. You start. looking for opportunities to streamline your projects. For this example. particularly if you are already using an ODBCDirect data model. give it some time to settle down—to shake out any bugs you may have introduced. the converted application will be a fully asynchronous. by backing up all of the work.To access the contents. First. with this application at least. go to VB’s Project menu and change the reference to the Microsoft Remote Data . it does not take advantage of ADO’s event-driven model and quite possibly does not take advantage of asynchronous communication. click the chapter and section titles. The basic principles remain the same as in DAO: Back up your work. Converting The RDO Application RDO applications are relatively straightforward to convert to ADO. globally replace RDO objects with their ADO equivalents. eyeball the code for obvious changes. Once your project is up and running. take advantage of asynchronous communications. the conversion is more complex than DAO in that. Still. and so on. Then. review the code. step through the code to catch any other problems. event-driven project unlike the converted DAO applications. I chose the ad hoc report writer example because it uses just about all of the RDO objects that you probably have used. as you might guess by my timid nature and fear of unemployment. move code to event procedures. although the completed ADO application should function in an equivalent fashion to its DAO predecessor. On the other hand. You then save all the files to new names and begin the surgery in earnest. In one sense. there is an event-driven environment from which to convert. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- DAO To ADO Summary The process of converting from DAO to ADO is not tough.

Notice that you also specify that the open should occur asynchronously.UID=Coriolis. Delete the rdoEngine and rdoEnvironment declarations. _ Prompt:=rdDriverNoPrompt. This is to adjust those events that declare RDO objects as arguments. Do a global replace of reng and renv with acon.". A scan through the code of this application will show that it makes extensive use of RDO collections. The property name is now CursorLocation and the value is adUseClient.. and password as separate arguments to the Open method. and change rdoResultSet to Recordset. The properties and methods of these objects have been largely migrated to the Connection object. you examine variable declarations. Globally replace rq with acmd. there are no ADO equivalents because Connection and Recordset objects tend to be standalone. You need to modify the connection by invoking the Open method of acon and using the now-familiar connection string. Change rdoConnection to Connection.0. You will adjust for this as you go through the code.Objects library to Microsoft Active Data Objects 2.Options:=rdAsyncEnable) acon. as shown in the following example. and change rdoQuery to Command. with ADODB." & _ "PWD=Coriolis. you see these lines of code to connect to the database: Set acon = rdoEnvironments(0) acon. Alternatively. Many times. In the cmdChoice_Click event. The revised code now looks like the following: Set acon = New Connection . Finally. Next. do a global replace of rdoError with Error. there are no ADO equivalents to the rdoEngine or rdoEnvironment objects. _ Connect:="DSN=Coriolis VB Example. Do the same for the rcon object variable. The application declares five module-level RDO objects: Private Private Private Private Private WithEvents reng As rdoEngine WithEvents renv As rdoEnvironment WithEvents rcon As rdoConnection WithEvents rrs As rdoResultset rq As rdoQuery As in DAO.QueryTimeout = Val(Text1) Call WaitConn Begin by changing the acon assignment to New Connection. The next line of code is intended to use a local cursor library. The QueryTimeout property is replaced by the CommandTimeout property.CursorDriver = rdUseClientBatch Set acon = acon.OpenConnection(dsname:="". Your module-level declarations should now look like the following example: Private WithEvents acon As Connection Private WithEvents ars As Recordset Private acmd As Command Do a global replacement of all occurrences of RDO. you could set the ConnectionString property of the object or simply pass the DSN. user ID.

sysuserperms where user_id = creator order by user_name. All rights reserved.State = adStateConnecting Using the While construct.Open "Coriolis VB Example". "Coriolis".syscolumns " The query had been constructed that way to illustrate the DISTINCT keyword.SYSTABLE table directly: select user_name || ' ' || table_name from sys.systable. A more direct approach is to query the SYS. The next line of code is to the BuildTableList procedure. is decidedly non-asynchronous. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.CursorLocation = adUseClient acon. the specific query—in this case. . to retrieve table names and the names of their creators—varies highly from database to database. Replace the one line of code with the following: While acon. _ adConnectAsync acon.CommandTimeout = Val(Text1) Call WaitConn The call to the WaitConn event is meant to flash a message on the form while still connecting. which creates a query statement: sQuery = "Select distinct creator || '. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. table_name Unfortunately. sys. An asynchronous approach would be to delete the code and move the BuildTableList call to the acon_ConnectComplete event. This seems reasonable. "Coriolis". The gut of the code in the event is the following line: While acon. A better answer is to take advantage of ADO’s OpenSchema method.acon.' || tname " & _ from sys. Read EarthWeb's privacy statement. of course.StillConnecting The StillConnecting property is replaced by the State property.

The entire code block that you seek to replace follows: Dim sQuery As String If Check1(0).Value = vbChecked Then sWhere = "" Else sWhere = " Where creator in (" & sWhere & ") " End If Else MsgBox "You must select a table owner!" Exit Sub End If ' Build the query sQuery = "Select distinct creator || '. What you do instead is replace the code and create the Recordset right in the BuildTableList procedure." End If sWhere = sWhere & "'DBO'" End If If Check1(2)." End If sWhere = sWhere & "'SYS'" End If If Len(sWhere) > 0 Then If Check1(3). Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The code passes the query to a procedure that actually creates the Recordset.Value = vbChecked Then If Len(sWhere) > 0 Then sWhere = sWhere + ".Value = vbChecked Then sWhere = "'coriolis'" End If If Check1(1).' || tname " & _ .To access the contents.Value = vbChecked Then If Len(sWhere) > 0 Then sWhere = sWhere + ". click the chapter and section titles.

OpenSchema(adSchemaTables. a period (“. The refined code now looks like the following: For iCtr = 0 To 1 lbTables(iCtr). sWhere(iCtr).Value = vbChecked Then Set ars = New Recordset Set ars = acon. replacing the Columns reference with Fields and using elements 1 and 2 (where the schemas and table names are located): .from sys. You can refine that in Chapter 9 by using the adSchemaSchemata schema. _ Array(Empty. In ADO. the creator is known as the TABLE_SCHEMA.Columns(0). The owner names are still hard-coded at this point.OpenSchema(adSchemaTables.Value = vbChecked Then Set ars = New Recordset Set ars = acon.AddItem ars.”). You change the sWhere variable to an array of four elements (0 to 3) and move the lines of code to clear the listboxes in the application to this procedure. "TABLE")) ' Show results Call ShowTables Else For iCtr = 0 To 2 If Check1(iCtr). Empty. You will simulate that with the following modified code. Empty.Clear Next sWhere(0) = "Coriolis" sWhere(1) = "DBO" sWhere(2) = "SYS" If Check1(3). The ShowTables procedure remains the same except for deleting the listbox Clear method mentioned previously and adding a modification to the AddItem method. The code currently looks like the following: lbTables(0).syscolumns " If Len(sWhere) > 0 Then sQuery = sQuery & sWhere End If Call SetResultSet(sQuery) A good chunk of the code concerns building the WHERE clause to determine which CREATOR to look for.Value Recall that the old query returned a concatenation of the Creator column. Empty. which will return a list of all schemas. _ Array(Empty. This gives you the ability to specify different schemas and iteratively add the tables to the listboxes. "TABLE")) ' Show results Call ShowTables End If Next End If Alter the values of the Where array to reflect your own database environment or simply pass an argument of Empty in the OpenSchema method to retrieve all schemas. and the Table_Name column. You can use those criteria when you use the OpenSchema method.

EOF lbCols(Index).MoveNext Loop The query was changed to the OpenSchema method using sCreator as an argument for TABLE_SCHEMA and sTable for TABLE_NAME.OpenSchema(adSchemaColumns. The user sees a screen that looks like Figure 8.syscolumns" & _ " Where creator = '" & sCreator & "' " & _ " and tname = '" & sTable & "' " & _ " order by colno" ' Build the result set Call SetResultSet(sQuery) ' Populate listbox and combo Do Until ars. ." & _ ars.Fields(1). Next.Value At this point.2 The partially converted ad hoc report writer.Value & ". as shown in the next example: Set ars = New Recordset Set ars = acon.AddItem ars. Figure 8.Fields(2). _ sCreator.lbTables(0). Using OpenSchema turns out to make the code much simpler.AddItem ars!cname cbCols(Index). The code here that you need to replace is the following: ' Build query sQuery = "Select cname from sys. you follow the code when the user clicks on a table name. you will use the OpenSchema method to generate a more generic solution that will work with any database. as in the BuildTableList procedure earlier.2.EOF lbCols(Index).AddItem ars!column_name cbCols(Index). sTable. you use the more generic ars!column_name instead of referencing the Fields collection. Array(Empty. Empty)) ' Populate listbox and combo Do Until ars.AddItem ars!cname ars. the application is capable of listing all the tables on the database. Again. In the code where you add to the listboxes.MoveNext Loop The RDO version of the code generated a query to find all the columns in the table that the user clicked on.AddItem ars!column_name ars.

Read EarthWeb's privacy statement. rdConcurReadOnly.Col = 1 End With Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Close End If Set ars = acon. adOpenKeyset. acon.State = adStateExecuting After the Recordset has been built.Row = 1 fgResults. you run into a stumbling block when you address the use of the GetClipString method of the RDO ResultSet. it merely builds up the SQL SELECT statement. the application populates the grid control with the results.ColSel = fgResults.Count should be replaced by Fields.Open sQuery. Copyright © 1996-2000 EarthWeb Inc.RecordSets. adLockPessimistic. The BuildQuery procedure is fine as is. The references to rdoColumns. _ rdOpenDynamic.1 fgResults.You are getting near the end of what needs to be converted.RowSel = fgResults.RowCount) fgResults. The code from the RDO version of the application looked like the following: ' Display data With rs sClip = .Count.Clip = sClip fgResults. You should replace the numerous references to RowCount in the procedure with RecordCount. The code follows: If acon. the SetResultSet procedure is called. you replace the text of the StillExecuting property with the State property: While ars.Rows . rdAsyncEnable) Call WaitQuery You replace the code with these simplified lines: Set ars = New Recordset ars.Row = 1 fgResults. Alas. adCmdText Call WaitQuery In the body of the WaitQuery procedure.1 fgResults.OpenResultset(sQuery.Count > 0 Then ars. When the user clicks the Run Query button. .GetClipString(.Cols .Col = 0 fgResults. There is no ADO equivalent. All rights reserved.

if brute-force. it is actually more efficient.To access the contents. . but that is going a little bit out of the way for this example. and the finished product is shown running in Figure 8. solution. You can replace the code with a straightforward. It takes a different tack in populating it. click the chapter and section titles.Row = fgResults.Col = iCol fgResults.EOF fgResults. A better solution is to bind the data source directly to the grid control. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The RDO solution was fairly efficient.MoveNext Loop End With The CD-ROM contains the code that I used to populate the grid control for the DAO version of the Ad Hoc Report Writer project. which is too lengthy to list here.Row + 1 For iCol = 0 To .Fields(iCol). although it is considerably longer.Count . The query that the application built is a self-join of the Employee table listing all employees along with their managers.Text = . as shown next: With ars Do Until . The application is now fully converted.1 fgResults.3. However.Value Next .Fields.

. review Chapters 2 and 3 and skip ahead to Chapter 11. my recommendation is to take one of your DAO or RDO applications and practice converting it. Run it in debug mode. stepping through the code and using the Immediate window to explore the values of different objects. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Between it and the DAO examples. and Chapter 10. where I start introducing advanced topics. where I discuss some advanced database issues. dive into Chapter 9. where I expand upon the use of ADO. if a bit tedious.com/data/).microsoft. I have covered most of the key methods and properties of ADO objects. neither were there deep mysteries. Take some time also to explore the Microsoft Web site for any developments since this book was written (www. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc.Figure 8. Although there was no magic bullet. Still.3 The RDO Ad Hoc Report Writer converted to work under ADO. Where To Go From Here Assuming you have read Chapter 7. If you are not yet comfortable with SQL or your database. The process is straightforward. Read EarthWeb's privacy statement. Summary The RDO example that I used to illustrate the conversion to ADO process was extensive. such as business objects. where I introduced the basics of ADO. most developers will find the effort worthwhile. Then. All rights reserved.

and aggregated Recordset objects. new releases of ADO. advanced data handling and navigation techniques. as well as functionality and performance. In addition to reviewing the new tools.com/vbasic) and the Microsoft Universal Data Access Web page (www. . The concepts and tools presented in this chapter are all very new and will evolve over time. To support these tools.com/data). new designers and viewers have been developed as well. I urge you to experiment with the technology presented here and to create bookmarks for the Microsoft Visual Basic home page (msdn. click the chapter and section titles. and the DataReport. grouped. Microsoft has introduced a number of new objects along with ADO. hierarchical. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 9 Advanced ADO Client/Server Techniques Key Topics: • Using the DataEnvironment object • Using the DataReport object • Parameterized. In this chapter. which is introduced briefly in Chapter 4. you’ll learn about the new tools that can help you to maximize the productiveness of your client/server development. you’ll also learn about some new. The tools that I show you in this chapter can add power to your running application as well as provide an unprecedented leap in development productivity. including the DataEnvironment.microsoft. Check the sites often—you’ll frequently find new articles and. most likely.To access the contents.microsoft.

workarounds. The DataEnvironment Designer The DataEnvironment Designer is roughly analogous to the User-Connection Designer in Visual Basic 5. you should monitor the Visual Basic Web site for any patches. The DataEnvironment Designer encompasses the functionality of the UserConnection Designer.1 The Data View window. select it under the View menu (or from the Standard toolbar). Bugs. and so on for at least the first six to nine months after Visual Basic 6’s general release. we had bugs. We “old-iron” types have a saying: Before PCs had mice.Bugs. you can create Connection objects that access multiple data sources simultaneously. mainframes are not unique in that respect. In this chapter. For instance. Figure 9. You can right-click the Data Links folder to create a new Data Link or right-click the Data Environment Connections folder to create a new Connection object. You can drag fields from the designer onto your VB form. plus new. The Data View Window The first item that I want to introduce is the Data View window. The DataEnvironment object and DataEnvironment Designer are new to Visual Basic 6. which created RDO objects. In this section I will introduce you to these tools and their usage. ADO-related functionality. All currently defined data links should display as shown in Figure 9. and stored procedures. Bugs I have been programming in the PC world for 20 years now. You can expand each of these and see their properties.1. But alas. You can expand any of the existing Data Links to see a list of tables. To access the Data View window. I share what bugs I found as well as some workarounds. the DataEnvironment components provide a new weapon in the arsenal of tools for the developer to attack high-powered client/server applications. you can then drag the object from the Data View window onto the DataEnvironment Designer window to create new Connection objects. views. I anticipate that there will be other bugs that I haven’t run into yet. Therefore. and appropriate data bound controls will . I encountered a number of bugs as I attempted to push Visual Basic’s new tools to various extremes. Combined. and I am not ashamed to admit that a lot of my background is on the mainframe. After you have created a new DataEnvironment object.

2. as shown in Figure 9. you’ll look at a report using Microsoft’s new DataReport object. If you have not already done so. select Microsoft Data Environment 1.3.3. First.be automatically created (!). you . From the Project|References menu.0. To use the DataEnvironment Designer. you’ll learn how to use the DataEnvironment Designer by working through example scenarios. Click on the Field Mapping tab. and select Options. choose Add Data Environment. open the DataEnvironment Designer by selecting “More ActiveX Designers” from the Project menu and then selecting the DataEnvironment Designer. 4. from the Project menu. On the General tab. I’ll walk you through two examples using the sample database. Right-click on the DataEnvironment object. such as Long. you can press the Add Data Environment button on the Data View window’s toolbar. Figure 9.3 The Field Mapping tab of the Options dialog box. as shown in Figure 9. Using The DataEnvironment Designer In this section. I will walk you through the creation of a hierarchical Recordset. 3. Here. Alternatively. you must add a reference to it: 1. you should have an idea of what it is you need to accomplish. the dialog box organizes the database data types into categories. Then. Under each category are specific data types. Before you get too far in using the designer. let’s take a look at the DataEnvironment Designer. such as adDouble and adNumeric. make sure that the Show Properties Immediately After Object Creation and Show System Objects options are both checked. you can tell Visual Basic how to map data types to bound controls on forms. 2.2. Then. The DataEnvironment Designer window will open. As you can see in Figure 9.2 The DataEnvironment Designer window. For each category. Figure 9. and a reference will be added to the Project Explorer window. For now. The Options dialog has two tabs—General and Field Mapping. Follow along as I give you the “whirlwind” tour: 1.

Read EarthWeb's privacy statement. or you can override the default and specify a different type of control. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. All rights reserved. although some are obviously inappropriate choices to use to display data. Close the dialog box after making any changes that seem appropriate. .can specify what type of bound control Visual Basic should create when you drag a field onto a form. You can then specify that each data type uses the default type of control. You can always change them again later. In the Control drop-down list box. Visual Basic lists every ActiveX object registered on your PC. 5.

The latter is a Boolean where True indicates that the object can be shared by other applications. and so on. and select Add Connection. enter the user ID and password.) When you open the DataEnvironment Designer. There are four tabs: Provider. Alternatively. Connection. a DataEnvironment object is automatically created along with a Connection object named Connect1. you can right-click the DataEnvironment object. locking level. click the chapter and section titles. or stored procedure from the Data View window to the DataEnvironment Designer window. as appropriate for the OLE DB provider. the Data Link Properties dialog box displays. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- I am hoping that Microsoft will some day also allow you to specify a default DataFormat property for bound controls in the Field Mapping dialog. The DataEnvironment object has only two properties: the Name property and the Public property. Advanced. When you do so. The easiest way to create a new Connection object is to drag a table. Visual Basic automatically creates a DataEnvironment object and a Connection object. of course. view. would make it easier to quickly control how data is displayed as opposed to having to change each field individually. I show you how to use these in the next two sections. • Advanced—Use to enter the timeout parameter. (The DataFormat property. I discussed its properties and methods in Chapter 7. • Provider—Use to select the OLE DB provider that you will be using. • Connection—Use to select the database. and so .To access the contents. The DataEnvironment Object When you add the DataEnvironment Designer to your project. The Connection Object The Connection object is a “standard” ADO object. and All.

To add a Command object to a Connection object. Alternatively. you can type in the statement or press the SQL Builder button. The SQL Builder is shown in Figure 9. you can rename the object or choose a different Connection to which this object belongs. Besides an SQL Select. I discussed its use in Chapter 7. or stored procedure from the Data View window onto the DataEnvironment Designer window. a Command object is created automatically. you can set the source of the data to be either an existing database object or an SQL Statement.4. The Command Object Like the Connection object. you can also specify a database object as . Again. the Command object is a standard ADO object. Under Source Of Data. right-click on the Connection. You can add as many Connection objects as needed.4 The All tab of the Data Link Properties dialog box. Figure 9. If you select SQL Statement. and select Add New Command. you can add multiple Command objects. as shown in Figure 9. I discuss the Command object next. • All—Use to view a summary of the Connection object’s settings. view. you can drag a table.5 The SQL Builder dialog box allows you to drag and drop to build your queries.5. Doing the latter allows you to build the query graphically. To each. NOTE When you create a Connection object by dragging from the Data View window. Right-click on the new Command object to set its properties. 2. The following shows you how to add a Command object to a Connection object and customize it in the DataEnvironment Designer: 1. you are presented with a tabbed dialog box: • General—On the General tab.on. Figure 9.

For SQL SELECT. . or Synonym. For more information on Parameter objects. you can select Stored Procedure. but this dialog box provides a convenient method of verifying or overriding the property values. similar to the SQL GROUP BY clause. the Call Syntax tab will show you the syntax for calling stored procedures but is unavailable for SQL SELECTs. the Object Name drop-down list box lists the available objects. If you choose to use a database object. ADO normally identifies all the properties of Parameter objects automatically. • Advanced—The Advanced tab has different options available depending on the data source. I have unchecked the All Records box. I will discuss this later in the chapter in the section entitled “Hierarchical Cursors. as shown in Figure 9. and entered a maximum number of records to return. such as sum and standard deviation. The parameters you see listed on the Parameters tab will generate Parameter objects at runtime. • Relation—The Relation tab allows you to associate Command objects with each other in a hierarchical relationship.6. View. as well as its data type and direction. you can set properties such as Cache Size and Lock Type. In each case. • Aggregates—The Aggregates tab allows you to aggregate your data based on one or more of several function types.being the data source of a Command object. If the data is grouped. Table. • Parameters—The Parameters tab of the Connection Properties dialog box shows all the parameters associated with a stored procedure.” • Grouping—The Grouping tab allows you to specify one or more fields on which your output will be grouped.6 The Advanced tab of the Command object Properties dialog box allows you to refine various advanced settings. subtotals are taken at the group level. For instance. In the example. TIP Adding Multiple Stored Procedures As Commands You can create multiple Command objects from stored procedures by right-clicking on the Connection object and choosing Insert Stored Procedures. You can select all or some of the procedures—Visual Basic will then create Command objects from them. see “The Parameters Collection And Parameter Object” in Chapter 8. Visual Basic will then open the Insert Stored Procedures dialog box listing the stored procedures available in the current connection. Figure 9.

Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement. All rights reserved. . Copyright © 1996-2000 EarthWeb Inc.

called the Grid. Right-click on the join line to expose its properties. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Using The SQL Builder I found the SQL Builder to be a little balky. you can assign an alias to columns. the SQL Builder’s procedures will have been refined somewhat. you can choose Ascending or Descending. There are three Or columns allowing you to string together several search criterion. By default. • The second pane. VB creates an inner join. If you click in the Sort column next to a database field. click on a column from one table and drag it to the column in the second table. if you so desire. (I am hoping that by the time VB6 ships. such as > 0. • The last pane allows you to view the output of your query. create multiple conditions one below the other. you can drag it from the Data View window. In the Grid pane. To change the order of the columns (not the sort order within a column). You can. The Sort Order allows you to refine nested ORDER BYs. which creates the And condition. (For whatever reason. shows columns that you have selected and allows you to specify sort orders. click next to each column that you want in your query. . I had a hard time figuring that out—someone else had to point it out to me. You can then change how the tables will be joined. drag each column as needed. The columns appear in the second pane as you click each. • The third pane is the text of the SQL statement.) When you open the SQL Builder dialog box. You can type an expression into the Criteria box.To access the contents.) To create a query. There is no overt provision to And your search criterion. To add a table to SQL Builder. VB draws a line denoting the relationship. click the chapter and section titles. To join tables together. and so on. you face four blank panes: • The top pane represents a graphical look at the tables. however.

these collections are 1 based while other ADO collections are 0 based.7 Building a form based on a DataEnvironment object using drag and drop. simply drag fields from the design window to the form window. It doesn’t get much easier than this. in which case Visual Basic will create all the data bound controls at once. a data grid. you’re given the options of creating data bound controls. you can right-click on any field in the Command object within the designer window and override the . NOTE When you create a Command object with the DataEnvironment Designer. You can drag with the right mouse button also. 3. Here’s how: 1. it also exposes the Recordsets collection. it creates a Recordset object if it is marked as being record returning. You can override this setting from the Advanced tab of the Command Properties dialog box. Then.7. however. You can drag the Command object itself onto the form. right-click in the dialog box. Reposition the DataEnvironment Designer window and your form window so that you can see both. The label captions default to the field name. Figure 9. In the design environment. You can also create it programmatically and manipulate its Command objects. Expand the Command object that you want to be the data source for the form. (The Font property of the form is used to default the Font property of controls subsequently added to the form). the DataEnvironment object exposes two collections: Commands and Connections. 4.To see the results of your query. The DataEnvironment collections are created at runtime when the DataEnvironment object is instantiated. At runtime. you can rapidly build your forms using drag and drop. 2. as I have done in Figure 9. Using The DataEnvironment Object The DataEnvironment object can be used much like a Data control by binding controls to it. Set the Font property of the form to whatever font and size that you want your bound controls to inherit. or a hierarchical flex data grid. As I mentioned earlier.7. When you do so and drop the Command object on the form. Confusingly. When a Command object is executed. it is automatically identified as to whether it’s record returning. as shown in Figure 9. and click Run.

of course. Copyright © 1996-2000 EarthWeb Inc. I did this for the last and first name fields in Figure 9. I would prefer that VB created an array of textboxes to more easily iterate through them at runtime. As you can see in Figure 9.8. You will need to set the DataSource. and DataField to the name of the appropriate Field object within the Command object. Maybe in the next release of VB? Visual Basic names the controls that it creates for you based on the control and the field. Figure 9. but an alternative would be to iterate through the Controls collection of the form. and DataField properties of the control.9 The DataEnvironment-driven Item Maintenance application.default caption. DataMember to the name of the Command object within the DataEnvironment. the name of the textbox for the customer last name is txtCust_LName (Cust_LName is the field name). Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Unfortunately. DataMember. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.7. Visual Basic does not provide a facility to rapidly change all the fields on one window.9. Read EarthWeb's privacy statement. You can. as seen in Figure 9. . DataSource is set to the name of the DataEnvironment object. All rights reserved.8 Properties of a control bound to the data source. You can also override the default control. create the controls manually. Figure 9.

Next. TIP Using Stored Procedures As Data Sources To bind a control to a stored procedure as a data source.) 1. and name your Command object Item. Field objects. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Using the objects in code is pretty much the same as I explained in Chapter 7. Add a form to your project. right-click on the Item Command. you must also enter a value for each of the input parameters on the Parameters tab. you must make sure that it is marked as Recordset Returning on the Advanced tab of the Command object’s Properties dialog box.To access the contents. • Visual Basic will create the Recordset objects for you and name them by adding the letters rs in front of the name of the Command object from which the Recordset objects were created. Because the Command object will be executed as soon as the form opens. For example. Select the Item table. 3. create a Command object whose data source is a table. The two things to keep in mind are: • All of the objects will be properties of the DataEnvironment object. and perhaps Parameter objects. . you should do that first. I created one to connect to a Sybase database and called it conExampleSybase. Create a Connection object as discussed earlier. the resulting Recordset will be named rsOrders. Command objects. Select Bound Controls from the context menu. click the chapter and section titles. we will program a form to maintain the Item table on the database. Creating The Basic Data Maintenance Form From The DataEnvironment Object In this section. As we go through the next several sections. (If you have not already created a DataEnvironment object. and drag it to the form. You will be manipulating Recordset objects. 2. if your Command object is named Orders. Connection objects. The first step is to create the appropriate Connection and Command objects. I’ll provide a number of examples of using the objects in code.

rsItem.rsItem.rsItem.rsItem.AbsolutePosition > 1 Then . Your navigation buttons should be pretty much like navigation buttons in any ADO application.rsItem. Now. The complete code is presented as Listing 9.AbsolutePosition lCount = deItemTest. Listing 9.rsItem.1. it performs most functions required of a data form.9.Bookmark = vBMark dispRec Case 4 End End Select End Sub Private Sub Form_Load() dispRec End Sub Private Sub Image1_Click(Index As Integer) Select Case Index Case 0 deItemTest.Bookmark lRec = deItemTest.rsItem. you will need to add navigation buttons.AddNew Text1 = "New Record" Case 1 deItemTest. Although it is bare bones.rsItem.rsItem.MoveFirst Case 1 If deItemTest. I used an array of Image controls.Update Image1_Click (3) Case 3 deItemTest.1 The code for the Item Maintenance form.4. Private Sub cmdAction_Click(Index As Integer) Dim vBMark As Variant Dim lRec As Long Dim lCount As Long vBMark = deItemTest. I also added an array of command buttons and a textbox to display the current status.) Note that the only real difference between this application and more traditional ADO projects is that the Recordset object is referenced as a property of the DataEnvironment object.rsItem. (You would want to add some code validation and so on. as seen in Figure 9.Delete If lCount > 1 Then Image1_Click (0) Else cmdAction_Click (0) End If Case 2 deItemTest.CancelUpdate deItemTest.RecordCount Select Case Index Case 0 deItemTest.

RecordCount End Sub Using Stored Procedures And Parameters With DataEnvironment Objects Figure 9.Execute txtNoEmps = deStoredProcedure. Figure 9.10 shows an application included on this book’s CD-ROM that uses stored procedures as data sources.Parameters(0) _ = val(txtRaise(0)) deStoredProcedure.Commands _ ("coriolis_NoEmps").MoveLast End Select dispRec End Sub Private Sub dispRec() Text1 = "Record " & deItemTest.Commands("coriolis_NoEmps").Parameters(0) Because the procedure has no input parameters.Execute .AbsolutePosition < _ deItemTest.MoveNext End If Case 3 deItemTest.10 is the same Employee Count stored procedure used in Chapter 8.AbsolutePosition & _ " of " & _ deItemTest. The code to execute the procedure and display the results is shown next: deStoredProcedure. it is not necessary to set any parameter values.rsItem.MovePrevious End If Case 2 If deItemTest. you have a lot of flexibility in how you code the procedures.Commands("coriolis_raise_no"). The top half of the form shown in Figure 9.deItemTest.rsItem.Commands("coriolis_raise_no").10 The Stored Procedure demo program.rsItem.Commands("coriolis_raise_no").Parameters(1) _ = val(txtRaise(1)) deStoredProcedure.RecordCount Then deItemTest.rsItem. The second stored procedure has two input parameters and one output. As in the stored procedure examples shown in Chapter 7. The first line of code executes the Command object Coriolis_NoEmps that has one output parameter.rsItem.rsItem. The second line of code then accesses the value of that Parameter object and displays its value in a textbox. The code to execute it is as follows: deStoredProcedure.rsItem.

All rights reserved. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. The third line of code executes the Command object. Copyright © 1996-2000 EarthWeb Inc.txtRaise(2) = deStoredProcedure. and the fourth line displays the result. the first two lines of code set the two input parameters equal to the value of whatever is entered into the first two textbox controls.Parameters(2) In this example.Commands _ ("coriolis_raise_no"). .

I have included a project called CustOrdDetHierarchy. If you code the InfoMessage event of a Connect object. deHierarchy has one Connection object: cmdCustOrdDet (so named because the examples access the Customer. TIP DataEnvironment Objects And Reusability You will place processing such as data validation into the DataEnvironment module and not into any form (and so on) module that accesses it. such as WillConnect and ConnectComplete (the complete ADO event model is discussed in Chapter 7). Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The DataEnvironment Event-Driven Model You do not lose the flexibility of event-driven development or asynchronous techniques when you use the DataEnvironment object. thereby maximizing code reuse and reliability. The module for the deHierarchy object exposes all the ADO Connect object events. The DataEnvironment object exposes two events: Initialize and Terminate. and Item tables). The names of the Recordset objects created are patterned after the Command . Line_Item. This provides considerable freedom to reuse the DataEnvironment object from form to form or even from project to project.Execute method. Neat! On this book’s CD-ROM. The DataEnvironment object takes all the Command objects that you create and internally performs a Set Recordset = command. any form that uses the DataEnvironment object as its data source inherits the code for the InfoMessage event.To access the contents. for instance. click the chapter and section titles. These two events are much the same as the class module’s Initialize and Terminate events and provide you with an opportunity to perform initialization and clean-up chores. In it is a DataEnvironment object—deHierarchy—that I use in examples in most of the remainder of the book. Orders.

is part of the same application. Both forms will open if you run the application. frmSPRS. Add a declaration at the module level to create a Recordset object: Private With Events rs As Recordset In the form’s Open event. The form. You use the events just as you would in a form module that creates an ADO Recordset. If you expand the stored procedure (by clicking on the plus sign). deSPDemo (included on this book’s CD-ROM).11 shows a form that I created to illustrate handling stored procedures that return a Recordset object. I borrowed the navigation buttons from the frmSPDemo form. you need to declare a reference to it. All Recordset objects that will be generated are listed in the object drop-down box without your needing to make a reference to them. I use the returned reference to navigate a Recordset. A Command object named custsByState generates a Recordset named rsCustsByState. Figure 9. I right-clicked on the stored procedure in the DataEnvironment Designer window and dropped it onto the form. If you double-click deHierarchy in the Project Explorer. I selected DataGrid. Each of these Recordset objects have their event models fully exposed as well. you can see the fields returned by the stored procedure. At the prompt. If you do so. To access a Recordset from your form.object’s name by prefixing it with an rs. I used a “canned” stored procedure from the database to create the form. its code window opens. Handling Recordset-Returning Stored Procedures Stored procedures that return Recordset objects are shown in the DataEnvironment Designer window with a plus sign next to them. make an explicit reference to the Recordset created by the DataEnvironment object: Set rs = deHierarchy. in which frmSPDemo from Figure 9. . The Properties dialog for the Command object containing the stored procedure has a checkbox on the Advanced tab indicating that the stored procedure returns a Recordset.rsCustsByState In the next section. I dragged the stored procedure again and chose Data Bound Controls. you then have access to its events at the form level as well (although I am not convinced this is a good idea in most cases).11 is included.11 This form demonstrates how to code applications that use Recordset-returning stored procedures. Figure 9.

MovePrevious instead of: deStoredProcedure. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. • I now gain access to the events of the rsdbo_sp_tables Recordset object as discussed in the prior section. rs. understand that VB only has to resolve deStoredProcedure. • I save myself a ton of typing! As you can see in the project on the CD-ROM. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. . to be of type Recordset at the module level.rsdbo_sp_tables once instead of many times. I actually make the code more efficient.After declaring a variable.rsdbo_sp_tables. for example. I coded the following line into the form’s Load event: Set rs = deStoredProcedure. Read EarthWeb's privacy statement.rsdbo_sp_tables This line of code does a few things for me: • By cutting down on the number of “dots” whenever I need to reference the Recordset. All rights reserved. for now. rs. so any references to a method or property of rs affects both.MovePrevious The data source of both the grid control and the textboxes is the same. the code is pretty much the same as for the frmSPDemo form example except that references are shortened up. I discuss this a little more in Chapter 11 but.

sometimes. I recommend pulling up the Object Browser. The DataReport provides some event-driven asynchronous control over your reporting. The DataReport Designer is broken into different sections (what are often called bands in other report writers). However. not very intuitive. of course. Each Section object has several properties. read “Writing Reports With The Microsoft Data Report Designer” in the Visual Basic Help file. When you do so. An in-depth coverage of either is beyond the scope of this book.) For more information. a new page should be started) and ForcePageBreak. before and after the section. The following is a summary of some of the highlights of the DataReport and the DataReport Designer. or that no page . You can drag and drop fields from a Command onto the DataReport or drag the entire Command object. For the latter property. you can specify that a page break always occurs before the section. click the chapter and section titles. after the section. Each Section object is part of the Sections collection. methods. The implication. The DataReport can be bound to any data source. selecting MSDataReportLib in the Library list box. but it works most naturally with the DataEnvironment object.To access the contents. (Besides. By default. select Add Data Report from the Project menu. In my testing. you probably have already used a half-dozen or so report writers in your career. The first time you use it. and events of the library. The Crystal Reports add-on has always been a good tool (and continues to be). I found the DataReport Designer to be somewhat finicky and. The key properties are KeepTogether (True means that if a section does not fit on a page. properties. To use the DataReport object. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Using The DataReport Object The DataReport object is a welcome addition to Visual Basic. is that the DataReport is highly programmable at runtime. it seems that it will be a great addition to the VB toolkit. if you so desire. Visual Basic adds a library reference. and exploring the objects. Section 1 is the Detail section. It is interesting to note that each section is actually an object (of type Section).

Show vbModal End End Sub Other methods that you can use programmatically include Refresh (to regenerate the report). index specifies the type of file to generate. The report is printed asynchronously.PrintReport(ShowDialog. RptShape. and PageTo arguments work the same as for the PrintReport method. If not supplied. Visual Basic provides a lot of flexibility in data report exports. PageTo) ShowDialog is a Boolean where True causes the Print dialog to be displayed. PageFrom. The syntax is shown in the following code: datareport. rptFuncSum. I created a standard module (included on this book’s CD-ROM) that displays a single report modally from the Main Sub procedure and then ends the program: Sub main() drCustomersOrders. but you can refer to “ExportReport Method” in the VB Help file for more information. PageFrom. rptKeyUnicodeHTML_UTF8.ExportReport(index. PrintReport. the Export dialog is opened. You select this and drop it on an appropriate section. and so on. The syntax for the PrintReport method is shown as follows: datareport. RptLine. you can show it in much the same way as you show any form. PageTo) The ShowDialog. and ExportReport. ShowDialog. Setting Range to rdPrintAllPages causes the entire report to print. A fifth control is the RptFunction control. You can specify the name of an ExportFormat object or an export key (rptKeyHTML. The Section object also has a Controls property made up of all of the controls placed on that section. or rptKeyUnicodeTest). filename is the path and file name to save the report to. You can then specify the PageFrom and PageTo arguments. Among choices for FunctionType are rptFuncAve. Range. including the dynamic alteration of its layout. Then. rptKeyText. . Range. _ Overwrite.break occurs. Of more interest are the properties. Range. methods. After you create a report. rdRangeFromTo specifies that only part of the report will be printed. and RptImage are all self-explanatory. The subject is outside the scope of the book. By using these properties and methods. Overwrite is set to True to cause files to be overwritten or False to prevent files from being overwritten. The DataReport has its own toolbox with its own version of design-time controls. and events of the DataReport object itself as well as how to use the object in your program. Omitting PageFrom or PageTo causes the Print dialog to open. RptTextBox. The ExportReport method allows you to save the report as a file. filename. PageFrom. you can exercise a lot of flexibility over your report. you need to set two properties: the DataField property and the FunctionType property.

AsyncTypeConstants. The Processing TimeOut event is triggered at defined intervals (about one second each) and allows you or the user to cancel a report in progress. ByVal ErrObj As _ MSDataReportLib.RptError. the ExportFormats property is a reference to the ExportFormats collection. _ ByVal JobType As MSDataReportLib.The DataReport object supports a number of events. Continue?". DataMember and DataSource allow you to specify the data source of the report. _ ByVal Cookie As Long. _ vbYesNo + vbQuestion) = vbNo Then Cancel = True Else Cancel = False End If End Sub You can also programmatically access or set various properties to control the appearance or operation of the DataReport object. The Error event is triggered when an error is encountered during an asynchronous event.AsyncTypeConstants. _ ByVal Cookie As Long) If MsgBox("Report Timed Out. Previous Table of Contents Next . Cancel As Boolean. AsyncProgress allows you to monitor the progress of the report. The following code example is a bare-bones error-handling routine: Private Sub DataReport_Error _ (ByVal JobType As MSDataReportLib. For instance. ShowError As Boolean) Select Case JobType Case rptAsyncExport MsgBox "Error Exporting Report" Case rptAsyncPreview If ErrObj = rptErrOutOfMemory Then MsgBox "Out of Memory!" Unload Me End If Case rptAsyncPrint MsgBox "Error Printing Report" End Select ShowError = True End Sub The next sample code demonstrates the handling of the Processing TimeOut event: Private Sub DataReport_ProcessingTimeout _ (ByVal Seconds As Long.

Read EarthWeb's privacy statement. . All rights reserved.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.

we can create command hierarchies to represent hierarchical relationships. in the process. In the real world. it is more efficient.To access the contents. This is implemented as a Shape (which I discuss later in this section). on each record in the parent . In other words. Because an order cannot exist without a customer. Visual Basic 6 and. child Recordset objects are represented as Field objects on the parent Recordset. in particular. click the chapter and section titles. For purposes of this discussion. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Command And Recordset Hierarchies The power of the relational database has always been to present data from multiple tables and. The hierarchical Recordset views tables in parent-child relationships. if you have a parent Recordset representing the Customer table and a child Recordset representing the Orders table. records on a child table depend on records on a parent table. however. The DataEnvironment Designer also helps you to build grouping and aggregate hierarchies. the Customer table is parent to the Orders table. I will refer to tables. Not only is this method somewhat more intuitive. Visual Basic 6 includes the Hierarchical Flexgrid control to display Recordset hierarchies in an intuitive manner. relate the data from one table to another. hierarchical relationships. This is a comfortable enough analogy—we looked at relationships that way when designing the database back in Chapter 2. OLE DB. From an OLE DB standpoint. we can’t have children without first having parents. When you create a hierarchical Recordset. the concept of hierarchical Recordset applies just as well to any file or data source for which there is an OLE DB data provider. provide an entirely new way of relating rows or records from one table or file to another table or file—the hierarchical Recordset. In the DataEnvironment object. In parent-child.

The easiest way to display and understand a hierarchical Recordset is to use it as a data source to a Hierarchical Flexgrid control. and select the Customer table. drag the top level Command object (cmdCustomer) onto a form. 7. The control displays each customer on the Customer table. Click the plus symbol to expand the display to show all orders. in turn. and drop it with the right mouse button. select cmdCustomer. Orders. and Line_Item tables. Select Orders for the name of the table. such as cmdCustomer.12. You can relate two Command objects after they have already been created. is named Bands. The DataEnvironment Designer window will now show the new Command (cmdOrders) as being a Field object underneath cmdCustomer. as seen in Figure 9. and select Properties. select the two fields on which these commands are related. click on the Relation tab. and then click OK. 8. In the Related Definition field. there is a Field object containing a Recordset which. Click the minus symbol to not show the order information. Right-click on the grid. as shown in Figure 9. The grid is drawn on the form. and specify its data source to be Table. Figure 9. Give it a name. Next. Cust_No and Ord_Cust_No. Again. such as cmdOrders. Select Hierarchical Flexgrid control. Add a Command object to in the DataEnvironment Designer. One of the tabs. 5. line items are also displayed with the same plus and minus symbols. and select Add Child Command.Recordset. 2. in this case. right-click on cmdCustomer. 4. 6. Now. even if you did not specify that one is the child of another. After giving it an appropriate name. Now. contains all orders related to that customer. and define the relationship as described in the preceding steps. 9. To create the hierarchical Recordset: 1. 12. and click the Relate To A Parent Command checkbox. Each .12 A Hierarchical Flexgrid control displaying a hierarchical Recordset hat contains the Customer. set its data source to be a table object. Add a child Command to cmdOrders using the same technique relating the Line_Item table to Orders using Ord_No and Line_Ord_No as the related fields. In the Parent Command drop-down list. If the customer has any orders. Go to the Properties dialog of the object that is to be the child Command. select the Relation tab. For each order. click the plus sign to display the detail line item information or the minus sign to not display the information. a plus or minus symbol is displayed next to the customer. 3. 10. Click the Add button. 11.13.

You can select what fields to display here as well as perform some limited formatting. Read EarthWeb's privacy statement. .Command object represents a band in the control. Copyright © 1996-2000 EarthWeb Inc.13 The Hierarchical Flexgrid control’s Property Pages. Unfortunately. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. I was not able to find a way to format numbers or dates without doing it in code. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Figure 9.

What the grid control thinks is band 0—the top-level band—is derived from the second highest Command object. and Line_Item tables. Orders. and then test. then your groups are composed of each unique occurrence of state and city together. When you create a Hierarchical Flexgrid control based on the group hierarchy. Assume that you wanted to group your customers by state and city. within that. Note that if you group by state and city in the same object. on the Grouping tab. edit the cmdCustomer object. click the chapter and section titles. When you create a Command group. Depending on how you build the hierarchy. The reason for this is that the definition of the data source object has changed. selecting the Grouping tab. The quickest solution is to simply . This time. In other words. Now.To access the contents. you get a band for each Command object just as you do with the hierarchical Command. You could do so by opening your Customer command and. You can group a single Command or a Command that already has a hierarchical relationship. specify Cust_St. let’s use the Command hierarchy built earlier with the Customer. and. a city group. a new object is created that is the parent of the object being grouped. You do not get a state group and. only the first grouping is displayed on the Flexgrid control. in the Properties dialog box. create a Hierarchical Flexgrid control as we did earlier. Drag it on the form. All works fine. a new Command is created consisting of those summary field(s) and is the parent in the hierarchical relationship. the Flexgrid control can be fooled. Using the sample data. only orders placed from California are displayed and there is no way to see other data. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Grouped Command And Recordset Hierarchies Command objects can be grouped in a manner similar to the way data can be grouped in SQL statements with the GROUP BY clause. All the fields that comprise the command are listed. To illustrate. if you group by one or more fields in a Command. Select the one(s) that you want to group by. Run the form again.

I have a form where I chose to sum the ord_amount column. In the Name box. in Figure 9. Assuming you have two Command objects related in a hierarchical manner. but you will have to go into Properties and reselect those fields that you want to display. and establishing hierarchies is all done with the . I will walk you through what I learned.right-click on the Flexgrid control and select Retrieve Structure. For instance. enter a meaningful name for the aggregate. grouped by state. Below that is a box where you define what you will aggregate on. you can select the function type (Sum. such as a Find dialog. You can quickly turn the form into an inquiry by state form. you can only compute the total based on the Grouping criteria. You will now have a textbox that is displaying the summarized level of the command hierarchy while the Flexgrid control displays the detail. and so on).14 This form. which contains aggregated data based on how you define it. In particular. If you chose Grand Total as your grouping level. as shown: deHierarchy. Choose Bound Data control if you dragged with the right mouse button. you can edit the properties of the parent object and select the Aggregates tab. Aggregating Data You can create aggregated commands based on hierarchical relationships and/or grouped relationships. I had no luck using the grand total aggregate or any meaningful grouping aggregations. grouping.MoveNext The form will then page through the data one state at a time—the Flexgrid will always display customers and sales for only that state in the textbox. I further refine this example later in the chapter by moving navigation to the DataEnvironment object and adding more functionality. Figure 9. I found using aggregation to be very frustrating and am assuming that the problems are beta-related (or me!). then you can select one of its columns in the Field box. Nevertheless.14. shows each customer with total sales and detail sales. Then. or Grand Total. The aggregate is a Field object. Another solution is actually a cute trick: Drag the summary Command object onto the form. and drop it anywhere except on top of the Flexgrid. and whether you have grouped the hierarchy. If you choose a child table. the child table.rscmdCustomer_Grouping. Next. Depending on what level of the hierarchy you are on. TIP Provider And The Shape Language Aggregating. StdDev. This will reinitialize the control. place a command button on the form and attach some code to scroll through the Recordset. you can aggregate based on Grouping (computations are taken on breaks in whatever field(s) you have grouped by).

I discuss the mechanics of what I did later in this chapter. (When you work with a new package and things don’t go as planned.Shape language. replaced it with my own source. A new Field object was added to the parent Command object—the same one that contains the cust_st summary field. you must set the Connection object’s Provider property to “MSDataShape” and change the Connection string from “Provider=…” to “Data Provider=…”. the next trick was to tell VB to use my version and not its own. In the Properties window of the cmd-Customer object. the tendency is to assume that you are making the error). . All rights reserved. if appropriate. Copyright © 1996-2000 EarthWeb Inc. To use the Shape language yourself. Read EarthWeb's privacy statement. I was never able to get any sort of nested computations and spent a considerable amount of time in working the problem out using VB’s tools. I placed some code into this event to see what command was to be executed and. I wanted to total sales by state. I added a new aggregate and called it TotSalesByState. I spent a considerable amount of time debugging the Shape language generated by Visual Basic. I did the same for the DataEnvironment object. You may recall from Chapter 7 that the syntax for this event includes the Source argument. After I got the Shape language squared away. I selected Sum for the function and Grouping for the aggregation level. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. To do that. I needed to edit the WillExecute event of the DataEnvironment object. Alas. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. which I discuss later in this chapter.

Visual Basic assigns the first header and footer sections to the Orders table. labels or other controls. drag the parent Command object on to the DataReport. The parent of the Orders table is Customer. . Then. On the report.15. the detail section is composed of individual line items. The footer section can be used to perform calculations (such as summing) on the preceding section (in this case. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Using Hierarchical Commands And Recordsets In DataReports You can also use your hierarchical Recordset as the source for a DataReport. the detail section). the DataReport reconfigures itself by adding (or deleting) headers and footers to reflect the number of levels of data in the Recordset hierarchy. I use the header area to show the customer number and name. though it isn’t as straightforward as it might seem. add a DataReport to your project from the Project menu. But. To do this. within appropriate sections. After this is done. The Line_Item table happens to be the child of all other tables in the command hierarchy.15 The Customer Sales Report generated by the report designer. The parent of the Line_Item table is the Orders table. in fact. Consider the report shown in Figure 9. I use this area to print the order number and date. so Visual Basic makes a higher-level header and footer pair of sections for customer-level data. click the chapter and section titles. and so on. you can drag individual fields onto the report and place them as you wish. You can add functions. On my report. it seems as though nothing has happened.To access the contents. I cannot place line item information into the customer header. For instance. At first blush. Figure 9.

add Microsoft DataList Controls 6. we have to keep in mind the issue of ownership and responsibility. I declared a reference to the rsCusts_by_State Recordset in the frmCustOrdDet form: ' In the General Declarations Section Dim rs As Recordset Private Sub Form_Load() Set rs = deHierarchy.16 The Customer Detail form enhanced with navigation and find capabilities. I refined the form that I discussed earlier under “Grouped Command And Recordset Hierarchies.0. Recall that the object has multiple commands and record sets.” On the form itself. Furthermore. I have manipulated Recordset objects directly from the forms that are displaying them. For this example.rscusts_by_state End Sub Next.Encapsulation And The DataEnvironment Object In most of the examples in this chapter. The DataEnvironment object owns them. encapsulation demands that manipulation be a function of the owning object. I added them to the deHierarchy object. Finally. in an object-oriented world.) Figure 9. (To use the DataCombo control. Instead of performing the navigation and find functions within the form. I added two other command buttons named cmdFind and cmdClose. In preparation. while valuable as an illustrative technique. which adds an OLE DB enhanced list box and combo controls to the toolbox. I added an Enum for navigational control to the general declarations section of the deHierarchy module (you may want to do it in a standard module instead): Public Enum RsMovement rsFirst = 0 rsBack = 1 rsForward = 2 rsLast = 3 End Enum Next. I added an array of four command buttons named cmdMove. dir As RsMovement) . As Chapter 8 describes. The forms that display the Recordset objects don’t actually own the record sets. This approach. My main objection is the redundancy of code—each form that displays a given Recordset must re-create the wheel in terms of navigation. instead. and so forth. I added the new DataCombo ActiveX control. I added two Sub procedures as shown: Public Sub MoveRS(rs As Recordset. Figure 9. has some problems. data validation.16 shows the form. I wanted to generalize the routines so that they could be used with any Recordset object.

.Bookmark Else Exit Sub End If rs.MoveRS rs. Back in frmCustOrdDet. iDir End Sub As you can see.MovePrevious End If Case rsForward If rs.AbsolutePosition < _ rs. passing it a reference to the Recordset and a direction.BOF) And (Not rs.Bookmark = vBMark End If End Sub The first Sub accepts as arguments a Recordset object and a variable of type rsMovement.RecordCount Then rs.EOF Then MsgBox "Record Not Found" rs.EOF) Then vBMark = rs.AbsolutePosition > 1 Then rs.Find sVal If rs. which is the Enum created earlier. sVal As String) Dim vBMark As Variant If (Not rs. Any form or module can share the MoveRS procedure.Select Case dir Case rsFirst rs. and makes a call to the MoveRS procedure.MoveFirst Case rsBack If rs. sets the direction variable. I coded the procedure to handle navigation: Private Sub cmdMove_Click(Index As Integer) Dim iDir As RsMovement Select Case Index Case 0: iDir = rsFirst Case 1: iDir = rsBack Case 2: iDir = rsForward Case 3: iDir = rsLast End Select deHierarchy.MoveNext End If Case rsLast rs.MoveLast End Select End Sub Public Sub rsFind(rs As Recordset.MoveFirst rs. of course. the routine simply checks which button was pressed.

of course. . In other words. the procedure is as follows: Private Sub cmdFind_Click() deHierarchy.The Find function allows the user to select a state from the combo box control on the form and click Find. From frmCustOrdDet. the Recordsets it generates are public by nature and there is nothing to stop any other module from manipulating them directly. The find procedure in deHierarchy is generalized to accept any Recordset and any search criteria. use the DataEnvironment as a data source to a class module and achieve some degree of encapsulation in that manner.Text & "'" End Sub These principles are not a whole lot different than the techniques we used to abstract classes in Chapter 8 and can be expanded upon to add updating. validation. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. and so on. Unfortunately. "cust_st = '" & DataCombo1. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the DataEnvironment cannot protect its members.rsFind rs. All rights reserved. It does some basic error checking and executes the search. You can.

Open As mentioned earlier.To access the contents. click the chapter and section titles. Visual Basic implements it with what is known as a Shape command. You can view the generated statement by right-clicking on the Command object.open "Shape {Select * from line_item}".14 is: recordset. you must set the Connection object’s Provider property to MSDataShape and alter the ConnectionString somewhat: con.CommandTimeout = 15 con.dsn=Coriolis VB Example. For instance.CursorLocation = adUseClient con. You are free to create the syntax yourself. groups the customers by state." & _ "uid=coriolis. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Shape Command When you create a hierarchical DataObject.pwd=coriolis. and takes a total of sales by state.Provider = "MSDataShape" con. The statement to create the hierarchical Recordset shown in Figure 9." con. As you can see.17 with the designer.ConnectionString = _ "Data Provider=MSDASQL. the Shape language generated by the DataEnvironment Designer is flawed. connection In order to use the Shape language. I attempted to create the form shown in Figure 9. . it subtotals all the sales for each customer. you can create a Recordset by using Shape language as its record source.

Notice on the second to last line that a SUM is done on cmdOrders. I found that the designer consistently referenced an object one step lower in the hierarchy than it should have whenever it attempted to manipulate summary fields.sumOrds. cmdOrders has no such field. It makes sense that the change was as “simple” as that.17 This form was generated by overriding Microsoft’s Shape language. understand that the correct syntax is more like this: Shape ( Shape {Select * From customer} As cmdCustomer _ Append (( Shape {Select * From orders} As cmdOrders _ Append ({Select * From coriolis. so I will try to explain it in this section. _ . ByVal pCommand As ADODB.Recordset. Ord_total is a column in the Orders table. In the deHierarchy object.LockTypeEnum. I placed some code in the WillExecute event. because.sumOrds) _ As TotSalesForState By cust_st The syntax is a bit difficult to follow. as I note earlier in the chapter. knowing what is wrong and doing something about it are two different things.ord_total) As sumOrds) Compute cmdCustomer. I changed that to cmdCustomer.Command. which is a field within cmdCustomer."line_item"} _ As cmdLineItem Relate ord_no To line_ord_no) _ As cmdLineItem) As cmdOrders Relate cust_no _ To ord_cust_no) As cmdOrders._ Sum(cmdCustomer. Sum(cmdOrders. Sum(cmdOrders.EventStatusEnum. LockType As _ ADODB. adStatus As _ ADODB. The syntax that the designer generated is as follows: Shape ( Shape {Select * From customer} As cmdCustomer _ Append (( Shape {Select * FROM orders} As cmdOrders _ Append ({Select * From "coriolis". But.line_item} _ As cmdLineItem Relate ord_no To line_ord_no) _ As cmdLineItem) As cmdOrders Relate cust_no _ To ord_cust_no) As cmdOrders. and the syntax was correct. _ CursorType As ADODB. cmdOrders is a child of the cmdCustomer object. What I had to do instead was a little trickery.sumOrders. For now. Unfortunately.ord_total. You cannot override the language that VB creates in the designer. I tested to see what Source was about to execute and then overrode it in this way: Private Sub conCustOrdDet_WillExecute (Source As String. The SUM occurs right before the COMPUTE cmdCustomer and creates a Field called sumOrds. Recall from Chapter 7 that one of the arguments to this event is the Source that will execute.Figure 9. I could not get any nested functions to work. _ ByVal pRecordset As ADODB. on the next line. _ Sum(cmdOrders.CursorTypeEnum. the only real difference is on the last line.ord_total) _ As sumOrds) Compute cmdCustomer. Options As Long.sumOrds) As Totsalesforstate By cust_st Although it took me quite a while to hack through the language. the generated syntax attempts to reference a field named cmdOrders. In experimenting.

CITY WHERE STATE.--------Massachusetts Attleboro Massachusetts Auburn Massachusetts Bedford Massachusetts Boston Massachusetts Burlington In a hierarchical Recordset.ByVal pConnection As ADODB. In this example. but it works. the same query would return only one occurrence of the value Massachusetts.000 question: Why bother? As I noted earlier." & _ "SUM(cmdOrders. while it (the parent) occurs only once in a hierarchical Recordset. To create the parent using Shape. city_name FROM STATE. hierarchical Recordset objects are more efficient than Recordset objects created with an SQL join.st_id = CITY. It also provides a valuable opportunity to dissect the Shape language. SUM(cmdCustomer. Before doing so.ord_total) AS sumOrds) COMPUTE" & _ "cmdCustomer.st_id ORDER BY state_name. and then Relate the two objects together: . "TOTSALESFORSTATE") Then Source = "SHAPE ( SHAPE {SELECT * FROM customer} " & _ "AS cmdCustomer APPEND (( SHAPE {SELECT * FROM " & _ "{orders} AS cmdOrders APPEND ({SELECT * FROM " & _ "line_item} AS cmdLineItem RELATE ord_no" & _ "TO line_ord_no) AS cmdLineItem) AS cmdOrders" & _ "RELATE cust_no TO ord_cust_no) AS cmdOrders. assume that you issue a select against a join of fictitious State and City tables as follows: SELECT state_name. city_name The result set would redundantly include information from the State table for each row returned from the City table: state_name city_name ---------. which I might use in more than one command). the State table is the parent.sumOrds) " & _ "AS TotSalesForState BY cust_st" End If End Sub This isn’t a perfect solution (I rely on finding the value TotSalesForState. UCase$(Source). you need to Append a new query.Connection) If InStr(1. To illustrate. let’s take a step back and ask the $64. you would code the following: Shape {Select state_name From State} To create a child. This is because the parent in a join is repeated for each occurrence of a child.

Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . city_state_id From City} Relate state_id To city_state_id} Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement.Shape {Select state_name. All rights reserved. state_id From State} Append {{Select city_name.

another Recordset. of type Variant and a second variable.To access the contents. A little explanation is in order here. We can fix that problem by providing an alias.Value Declare a variable. Unlike SQL. state_id From State} As cmdStateCity Append {{Select city_name. set rsCity equal to vCity. you cannot make a direct assignment of rsCity = vCity—you will get a mismatch error. of course. While it is tempting to assume that vCity’s underlying data type is Recordset. is how to access the Fields within the cmdState Recordset. Then. you have to include in the Select statements the two columns on which you are joining the tables. The Field object’s Value property is of type Recordset. What’s more. The resulting Recordset created from this would have three Field objects: state_name. as shown next: Shape {Select state_name. when you join two tables via the Shape command. then. city_state_id From City} As cmdCity Relate state_id To city_state_id} As CmdStateCity The key here is the naming of the inner Select cmdCity. The third Field is. and cmdCity. If assigned to a Recordset. You could access the cmdCity Recordset as shown next: Dim vCity As Variant Dim rsCity As New Recordset vCity = rsState("cmdCity") rsCity = vCity. the columns from the state table cannot be independently accessed. . click the chapter and section titles. it isn’t. Assume that you had created a Recordset named rsState. It is actually type Field. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Notice that the Relate references state_id To city_state_id. vCity. rsCity. state_id.Value. Whereas you might assume that vCity’s default property is Value (the Field object’s default property is Value). of type Recordset. So. you need to be explicit with your references. The question. vCity is still a Variant. Assign to vCity the value in the cmdCity field. Visual Basic’s example of referencing a child Recordset in the Help file was incorrect with my copy of VB6.

Private Sub disprec() Dim iCtr As Integer Dim iStart As Integer Dim iRs As Integer Dim iFlds As Integer On Error GoTo BumpIt ShowRS: iFlds = rs(iRs).iStart). which display data from one. But. two. Figure 9.Name . respectively. if you press one of the top navigation buttons (to scroll to the next customer). The listing is very lengthy.Fields. and so I will only touch upon the highlights.Fields(iCtr . or their field names. or three tables. the parent Recordset would include only 50 records. Orders.2 A code “trick” to iterate nested Recordsets.18 The Shape Testing application. There are three command buttons. To keep the parent and child Recordsets in sync. the first customer record is displayed.1 lblFields(iCtr) = rs(iRs). When you create parent/child Recordset objects. database resources. Figure 9. For the application. For each of those 351 city records.000 or so cities and towns. If you run the sample application and press the third command button. That customer’s first order is displayed and that order’s first line item is displayed. there is only the one parent record. you must set this property to True on the parent Recordset before retrieving the child Recordset.Value("city_name") Although it is strange looking. then the parent and child Recordsets move independently of one another. what else is going to go wrong today? You may recall the StayInSync property from Chapter 7.Count For iCtr = iStart To iStart + iFlds . presumably. Assuming the state table has all 50 states and 20. of course. Listing 9. how many there are.2 shows a mildly dangerous way to generically display data without knowing up front what the child Recordset objects are. On the sample application. the database only needs to return one copy of each parent record. I used the Customer.text = vCity. checking the Sync Parent checkbox will cause the Recordsets to stay in sync. The application doesn’t know what data it will be displaying or how many Recordset objects there are. to display the data. If this property is False (the default) on a parent Recordset. So. and Line_Item tables. The state of Massachusetts (excuse me. the order doesn’t change.Alternatively. This represents a considerable savings in network traffic and. it works.18 shows another sample application (included on this book’s CD-ROM) with which you can experiment with Shape language and parent and child Recordset objects. If you scroll the order. This can be a mite tricky as well. the Commonwealth of Massachusetts) has 351 cities and towns. the line item doesn’t change. you could reference vCity directly: text1. unlike with the SQL join example earlier in this section. Listing 9. The goal of the application is.

Fields(iCtr . Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.iStart).Value End If Next Exit Sub BumpIt: ' This is a dangerous trick! If Err. ReDim Preserve your array of Recordset objects. In the error-handling routine. I use a very similar technique to iterate through the Recordset objects displaying their fields. Iterate through the Field objects testing for a Null value. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. using the technique I showed earlier.Value) Then txtFields(iCtr) = "*NULL*" Else txtFields(iCtr) = _ rs(iRs). In the preceding example. make some assumptions about the names of those child Recordset objects. a mismatch error occurs and I increment the rs subscript. and. I should explain that I created an array of Recordset objects in the application.If IsNull(rs(iRs). When a child Recordset is encountered in the parent. a mismatch error will be generated.Fields(iCtr . . All rights reserved. If you examine the code listing on this book’s CD-ROM.Number = 13 Then iRs = iRs + 1 iStart = iCtr Resume ShowRS Else MsgBox Err. Copyright © 1996-2000 EarthWeb Inc. set the new Recordset to be the Field object that generated the error. A few code changes and you can generalize the routine that creates them as well.Description End If End Sub First. in fact. When you encounter a child Recordset. Read EarthWeb's privacy statement. you can see that I did.iStart).

testing. child. I have reformatted it. Fix any errors using the techniques described at the beginning of this section. indenting at each level (parent. My recommendation is to generate them in the DataEnvironment Designer and then copy and paste them into your code.To access the contents. To make it more understandable. though. The last hint I would like to leave you with is to treat the Shape statement like a nested If statement. it’s not so bad. Other Data Access Tools In Visual Basic 6 Throughout the first nine chapters of this book. Even here. and adding new items. if necessary. I tell my students the same thing when trying to write complex queries in Oracle or SQL Server. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- You can consult the VB documentation for other hints on creating Shape statements. click the chapter and section titles. you can do yourself a favor by starting small. and sub-child): Shape (Shape {Select * From customer} As cmdCustomer Append ( (Shape {Select * From orders} As cmdOrders Append ( {Select * From "coriolis". The sample application uses the following Shape statement to join three tables."line_item"} As cmdLineItem Relate ord_no To line_ord_no) As cmdLineItem) As cmdOrders Relate cust_no To ord_cust_no) As cmdOrders When you look at it this way. I have attempted to introduce as many of the tools and techniques to access data in a client/server environment as . The Shape language can get pretty overwhelming for us mere mortals.

VB3 was the first serious attempt at using Visual Basic as a client/server development tool. Each time I fire up this beta release of Visual Basic 6 in research for this book. I am going to bind a couple of textbox controls by adding members to the collection. To use the Binding object. I find something new and wonderful. but you can make it act as a data provider as well. The arguments that I have provided are: • The control that will act as the data consumer (in this case. you bind the BindingCollection to a data source. Visual Basic 6 continues the trend of an accelerated migration to an object-oriented and database-oriented development tool. The Bindings Collection And Binding Object Visual Basic 6 introduces the Bindings collection and the Binding object. VB4 was really just a refinement of that attempt. bc1 is a data consumer. Then. as shown here: Dim bc1 As BindingCollection Next. declare objects as being of type BindingCollection. As I have noted throughout this chapter. VB6 is a quantum leap over VB5. I discuss the class module as a data consumer and a data provider in the process of constructing business objects. the nature of VB’s extensibility means that one cannot cover every conceivable tool—most of VB’s intrinsic controls are data aware and there is a plethora of third-party components available as well. some of the edges are a little ragged. In the following example. there. In my opinion. Next. it doesn’t do a whole lot of good. I bind it to a Recordset: Set bc1. These objects provide a means to bind any data consumer (such as a textbox or class) to any data provider (such as a data control or Recordset). the discussion moves toward remote database development with an eye toward the World Wide Web and. I want to briefly overview some of the remaining tools that you should be familiar with.DataSource = rs At this point. VB5 was as much an improvement over VB4 as VB4 was over the very first release of Visual Basic 1. In fact. Text) • The field from the Recordset (emp_dept_no for txtDept and emp_ salary for txtSal) • A name for the object (dept for the first and salary for the second) . yet more tools are introduced. In Chapter 10. In Chapters 12 through 15. txtDept and txtSal) • The property of the control that will display the data (in this case. you have to declare a reference to the Microsoft Data Binding Collection Library. In this section. but those will be smoothed—hopefully by the time VB is sent into general release. As such.possible.

"emp_salary". Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.bc1. "emp_dept_no". Read EarthWeb's privacy statement.Add txtDept.Add txtSal. . "salary" At this point. "text". . "text". Copyright © 1996-2000 EarthWeb Inc. I will be using this behavior to advantage in the next section. and bc1 is bound to the Recordset. . All rights reserved. the textbox controls are now bound to bc1. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. "dept" bc1.

"Sex" I bound bc1 to the Active Data control and then created a new instance of fmtSex. you must first declare a reference to the Microsoft Standard Formatting Library. Because the data values can change. as shown in the following code. for each Format object that you want to create. FormatBindings.Add txtFields(3). "emp_gender". In the following examples. . I also need to bind the Format object to a BindingCollection object. You can use the Format event to alter the presentation of the data if necessary. opens an Active Data control on the Employee table.To access the contents. In the application’s Open event. I set its type to fmtCustom. click the chapter and section titles. I am going to declare a Format object to handle this. fmtPicture. Other options include fmtBoolean. Then. "text". and so on. To use Format objects. fmtCheckbox.Type = fmtCustom bc1.Object Set fmtSex = New StdDataFormat fmtSex. I want to display the employee’s gender as red if female or blue if male. In my example. _ fmtSex. To do so. I coded the following: Set bc1. See the VB Help file for more information. I then added the object to the BindingCollection. The Format object has a number of events. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Visual Basic Format Objects Format objects allow you to format and unformat data for display. (The example from the prior section is included in that project as well). so I declare a reference for that as well: Private bc1 As New BindingCollection Private WithEvents fmtSex As StdDataFormat The sample application on this book’s CD-ROM.DataSource = Adodc1. you must declare a variable of type StdDataFormat.

The application includes four different format objects and three BindingCollections.I need to reformat the data each time the value changes: Private Sub fmtSex_Format(ByVal DataValue As _ StdFormat. create a new project of type ActiveX control. If greater. I used four textboxes that will eventually manipulate data from the Line_Item table. For the example application. ItemDesc. Place fields as needed.ForeColor = vbRed Else txtFields(3).19 This application makes use of Format and DataBinding objects. Each textbox is exposed through the appropriate Property Get and Property Set statements. the Format object sets the Checkbox controls. which you can use to convert the data back into a form acceptable to the database. Figure 9. It compares each employee’s salary to the department average and company average.StdDataValue) If DataValue = "F" Then txtFields(3). the AXctlLineItem project is a user control compiled to an ActiveX control that is bound to the database. On this book’s CD-ROM. For instance. As you can see.ForeColor = vbBlue End If End Sub As you can see. Though you can’t tell in Figure 9.Text End Property Public Property Let ItemDesc(sItemDesc As String) txtFields(3). the employee shown makes more than the company average but not as much as her department’s average salary.19.19 shows the prior two sections in action. Figure 9. the following code manipulates a control property. there is a Changed event to handle situations where the data has changed. Data-Bound User Controls You can use the DataBindings collection to bind controls on a user control to a data source. which will eventually be mapped to the item_description field on the database: Public Property Get ItemDesc() As String ItemDesc = txtFields(3). There is also an Unformat event.Text = sItemDesc End Property . Finally. To create a data-bound user control. her gender is displayed as red. DataValue is a property of the object.

Repeat this for each of the four properties in the control and then compile it. to set the ItemDesc property: DataRepeater1. (Figure 9. find the RepeatedControlName property in the Properties dialog for the DataRepeater control. select Procedure Attributes from the Tools menu. For instance. and select a database field from the DataField box. Check the Property Is Data Bound box and also the Show Property In Data Bindings Collection At Run Time boxes. Next.To map the properties. The DataRepeater The DataRepeater control allows you to display multiple occurrences of a data bound object—such as the ActiveX control created in the prior section—in a format similar to a grid control. and then draw it on the form. the RepeatedControl property returns a reference to the control. Select each in turn. To programmatically access the properties and methods of your user control. For the DataSource property.20. Run the project and you should get a display similar to the one shown in Figure 9. Previous Table of Contents Next . You will use the control in conjunction with the DataRepeater control in the next section.RepeatedControl. and all ActiveX objects registered on your PC are displayed. Click the Advanced button and you will see where you can set object behaviors. The bottom area is for data binding. select the Active Data control. Make it big enough to handle multiple occurrences of the OCX you created in the prior section. To use it. add the Microsoft Data Repeater Control 6. Figure 9. Select the RepeaterBindings tab.ItemDesc = "Another Item" The current record is indicated by the CurrentRecord property. The next tab. Format.20 shows the running application—the application from this book’s CD-ROM is Data-Repeater.0 to your toolbox.20 The DataRepeater control is used to display multiple occurrences of the contained data bound controls. it will be repeated multiple times inside of your DataRepeater control. right-click on the control and select Properties. There is a drop-down list box listing all the properties of the ActiveX control that you chose to be added to the DataBindings collection in the last section. At the top is a drop-down window that displays the object’s properties. Next.) Add an Active Data control whose Source is “Select * From Line_Item”. Locate the control you created in the last section and select it. When you do. allows you to format individual fields. Click it. You can optionally specify a collection key in the next field.

Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved.

000 pages. The amazing thing about Visual Basic 6 is that. note how we began moving towards encapsulation of methods and properties. Also. XML. makes it impossible to access an item from the database without using its interface. congratulations! Take some time to explore and expand on some of the sample applications on this book’s CD-ROM. The user control in the last section. In Chapter 11. I’ll explore the concept of the business object and build on the technique of using classes as data objects. DHTML. and so on. click the chapter and section titles. even in 3. After that. In particular. take note of how the latter examples in this chapter take advantage of procedures written earlier. my co-author Kurt Cagle takes you into the exciting and scary realm of Web development. In Chapter 10. If you have come this far. the final Shape application uses the same navigation methodologies encapsulated into the deHierarchy that frmCustOrdDet used earlier in the chapter. I’ll concentrate on the database aspect of your client/server application. it is not my intention to do so.To access the contents. Previous Table of Contents Next . not every aspect can be covered in depth. Such techniques promote productivity and reliability of code (and is the focus of the next chapter). We have built a core of knowledge from Chapter 1 on and added to that very rapidly until getting into the relatively advanced concepts presented in this chapter. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Where To Go From Here We have covered a lot of ground in these first nine chapters. But. for instance. For instance.

Copyright © 1996-2000 EarthWeb Inc. . Read EarthWeb's privacy statement.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. All rights reserved.

click the chapter and section titles. Today.To access the contents. One has only to look at the delays in the release of SQL Server 7—which relies heavily on ADO. Instead. I recommend that you proceed slowly. Although I certainly don’t mean to imply that these technologies aren’t viable and even in use in some organizations. methods. but nobody is doing it. Throughout this book. a joke compared client/server development to sex: Everybody is talking about it. the buzz is about distributed objects. and so on. and maybe that is just as well. testing the reliability and viability of these techniques as they evolve. n-tier architecture. COM/DCOM. I have attempted to keep an eye on where most organizations and developers are technologically. I cannot recommend throwing the tried and true techniques that I have discussed so far in this book into the abyss of remote objects and the like. and distributed objects—to see that some of these new technologies are still evolving. Web-based applications. and properties • In-process and out-of-process ActiveX servers • Connecting to local and remote business objects Application development always seems to be 12 to 36 months behind technology. they still remain the exception and not the rule. In the early to mid 1990s. . while building a foundation for the architectures of tomorrow. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 10 Creating Business Objects With Visual Basic 6 Key Topics: • Object-oriented development • Creating Private and Public events. DCOM.

• Behavior—Methods and events of the object. My recommendation at this time. such as a customer record. Introducing The Business Object A business object encompasses data and rules that perform a business function. I lead you through the foundations of distributed components with an introduction to creating right-sized and right-located business objects. focus on the desktop—the presentation layer. distributed-architecture. • Interface—Both the user interface. In this chapter. In DCOM. any object in a COM or DCOM environment has three facets: • Data—Business information from the data source. DCOM (Distributed Component Object Model) focuses on the network and is the technology that enables objects running in separate processes—particularly those running on separate computers—to communicate with one another. Web-based applications. More to the point. Note that most of the examples in this chapter are adapted from applications or objects generated by different Visual Basic wizards (such as the Data Object Wizard) to which I then made modifications to illustrate various points. as well as variables used internally. let’s jump into the concept of the business . and so on are all parts of the same whole: Microsoft’s services architecture model. The components are ActiveX servers. In contrast. reliability. DCOM. COM. or data) and imparting them with the knowledge of how to communicate with one another. learn how to use the new tools) and as the technology matures and stabilizes. With that quick summary in mind. DCOM is the glue that binds all of these together. non-mission-critical applications as you get your feet wet (in other words. DCOM. is to roll out your deployments with small. if any. these connections are the object’s proxy and stub. and ActiveX controls in particular. DCOM. ActiveX can be likened to JavaBeans and DCOM can be likened to COBRA. business. For anyone who has done Java development. its very nature is the distribution of components—ActiveX objects—at appropriate places with the services model (user. COM (Component Object Model) is as much a development philosophy as it is a development methodology. COM-based development uses previously created components in an effort to promote reusability. COM in general. and ActiveX architecture really are and how they fit together.Should you investigate these technologies? Absolutely. regardless of the language used to develop them and regardless of their location on the network. which I introduced in Chapter 1. and a set of “connections” that expose the object to the outside world. as I will be discussing in this chapter. n-tier. Most of the remainder of this book is devoted to these new and exciting development methodologies. and interoperability. And ActiveX Summarized It is worth taking a moment to reflect on what the various pieces of the COM. if you decide to move forward.

Read EarthWeb's privacy statement. You may opt to expose Public methods. they are fully protected. Business Object Data To create a business object. privately declared data. This concept of an object is illustrated in Figure 10. you create the data that you need to manipulate. However. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. you do this by creating a class module.1 An illustration of a client (Object A) calling Object B (running in its own pro-cess)—perhaps to invoke a method of Object B. it becomes an object. allowing the manipulation of that data. This arrangement is called encapsulation. All rights reserved.object in component based development. and events are encapsulated by the business object. you then need to provide some sort of interface to the outside world to access these variables. so it is protected from unauthorized use. In VB. Within the class module. methods. When the class is instantiated. The following code declares some variables in a class module: Option Explicit Private Emp_No As Integer Private Emp_FName As String Private Emp_LName As String Private Emp_DOB As Date Public bClose As Boolean Because the first four variables are not publicly available to other modules. Figure 10. Copyright © 1996-2000 EarthWeb Inc. Any data that is declared Private cannot be seen by other modules. The last variable is declared Public and can thus be changed by any other object. . you first need to create its definition or class. but the manipulation will still be done by the class module itself.1. as well as methods and events. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

Let’s modify the code a little bit: Public Property Let FLName (first As String. If the object’s name were clsEmployee. those properties. methods. and events that are declared with the Public keyword compose the object’s interfaces to other objects. provide an interface that returns to the requesting object the employee’s name: Public Property Get EmpName () As String EmpName = Emp_FName & " " & Emp_LName End Property In this example. last As String) . click the chapter and section titles. methods. as shown: Public Property Let FLName (first As String. so it is part of the object’s interface.To access the contents. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Business Object Behavior You allow access to objects via properties. Together. for instance. You do this with a Property Let statement. the preceding code snippet doesn’t provide much in the way of data validation. You could. the property EmpName is declared as Public. use the Let or Set modifiers.EmpName EmpName is a read-only property because it was defined with the Get modifier. you would reference the property using simple dot notation: ' Display the customer txtEmpName. and events.Text = clsEmployee. last As String) Emp_FName = first Emp_LName = last End Property Of course. To create a property that can be written to. Perhaps you want to allow the update of the employee’s name but only under strict control.

Last <= 21. There is some overlap between methods and properties. Last <= 21. First <= 15. Of course.Raise vbObjectError + 512.If Len(first) = 0 Or Len(last) = 0 Then Err. Likewise. It is similar to a Function in that it returns a value to the calling object. in your Property Let procedure.Raise vbObjectError + 513." Else Emp_FName = first Emp_LName = last End If End Property The preceding code object edits the name lengths for validity and uses the Visual Basic error-handling facilities to flag any data violations. update the ErrStat variable to reflect success or . _ "First and last names cannot be blank" ElseIf Len(first) > 15 Or Len(last) > 21 Then Err. Create Public properties to expose them: ' General Declarations Section Private ErrStat As Integer Private ErrMsg (100 To 199) As String ' Class Initialization Procedure ErrMsg (100) = "First and last names cannot be blank" ErrMsg (101) = "Name too long. the object may also have privately declared methods. Business Object Methods Publicly declared methods are implemented as Subs or Functions and implement any services that the object needs to provide to the outside world. An Alternative To The Error Handler In Class Modules An alternative to using the error-handling facilities for Property Let and Property Get is to create a property whose sole purpose is error reporting. Consider that a Property Get exposes a portion of the object—such as a variable. a Property Let or Property Set is similar to a Sub in that it performs an action without returning a value to the calling object. create a private module-level variable named ErrStat and an array of error messages named ErrMsg. _ "Name too long. To do this. First <= 15. The calling object is not allowed to pass invalid values. which are used internally by the object and are then not part of the object’s interface." Public Property Get Status () As Variant Status (0) = ErrStat If ErrStat <> 0 Then Status (1)= ErrMsg(ErrStatus) End If ErrStat = 0 End Property Then.

Because the business object “owns” the employee data. it has the responsibility for updating that data.Update End Sub . if something that your object exposes is a noun (the employee’s name. If it is a verb (update employee record. it does make the resulting business object more portable and simulates ADO’s Error object. perhaps). Consider the EmpName property from the last section. as shown: Public Function EmpName () As String EmpName = Emp_FName & " " & Emp_LName End Function To an extent. last As String) If Len(first) = 0 Or Len(last) = 0 Then ErrStat = 100 ElseIf Len(first) > 15 Or Len(last) > 21 Then ErrStat = 105 Else ErrStat = 0 End Property This might not seem as straightforward as simply relying on VB’s error-handling system. my recommendation is that you expose data as properties if for no other reason than it is a more natural way for the calling object to reference the business object. you might create an UpdateEmp interface as shown next: Public Sub UpdateEmp () ' Put any data validation here. If it is to be an out-of-process server. it isn’t. and in fact. see “Relocating The Business Object” later in this chapter. However. Otherwise. If the method needs to return a value. it should be implemented as a method. In this case. how you build your class and your choices between properties and methods is largely a personal preference. it should be a Function. for instance). Your business object could be designed devoid of any publicly declared properties or methods. where the rules change. it could have been implemented as a Function.failure: Public Property Let FLName (first As String. it should be a Sub. COM imposes severe performance penalties when communicating across process boundaries. However. expose it as a property. Methods. However. And Performance One other consideration when choosing whether to expose an interface as a property or method is the design of the object. Assuming that a previously opened Recordset named arsEmp is being used to manipulate the data source. you are better off using properties as much as possible because properties incur much less of a performance hit than methods. In general. ars. TIP Properties.

All rights reserved. .Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc.

_ bStatus As Boolean) The Event declaration also specifies optional arguments.Recordset) Dim bSuccess As Boolean If adStatus = adStatusOK Then bSuccess = True End If RaiseEvent rsUpdateComplete(pError. click the chapter and section titles. _ ByVal pRecordset As ADODB.EventReasonEnum. . Perhaps you also want to pass back to the calling object information about the success or failure of the update. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Business Object Events Events provide the foundation of any object-oriented development effort. which the calling object will then have access to. To create the event.Error. VB provides the capability for your business object to expose events to which the calling object can react.2. _ ByVal pError As ADODB. bSuccess. adStatus _ As ADODB. To cause the event to occur. Assume you want to create an event to let the calling object know that the employee update completed. pRecordset) End Sub The calling object will then see that declared event just like any other event. use the Raise keyword: Private Sub arsEmp_RecordsetChangeComplete(ByVal adReason As _ ADODB. as shown in Figure 10.To access the contents. you declare it in the General section of the class module: Public Event EmpUpdateComplete (pError As Error.EventStatusEnum.

As with your class module. binary code that is language independent. and events: Dim empClsDemo as clsEmpDemo In this example. regardless of the development language. its events are exposed.2 Once you declare a reference to a class object. you create a reference to it in whatever module needs to access its properties. a class is the definition of an object. components are ActiveX Servers (either EXEs or DLLs) or ActiveX controls. the components’ exposed properties. it can be used by any language that understands ActiveX technology. Components typically consist of one or more objects. On the other hand. What you see in the dictionary is not a person. In Microsoft’s COM and DCOM models. potentially at any place on the network (instead of on the client machine). methods. you are adding a prebuilt component. Although an ActiveX control is not required to have a visible component. The ActiveX control is essentially an in-process server. clsEmpDemo is the name of a class module that you had previously created. To instantiate a class module. it is the definition of a person. empClsDemo is the name of an object that gets created from clsEmpDemo when declared. an object is an instance of a class. its portability is especially enhanced when you compile the class into an ActiveX component. you must make a reference to them (usually via the Components or References options from VB’s Project menu). Business Objects As Components In the object-oriented world. it typically is used that way. A component is prebuilt. out-of-process servers come at a distinct performance disadvantage: Because calls from one process to another must cross process boundaries. A dictionary definition of “person” might generically indicate that a person is a human with two legs. hair. It can then be used by any application. A component is not an object: Let’s make that clear. whereas an out-of-process server runs in its own memory space. The CommonDialog control is one of the more common exceptions to that rule. Because it is binary code. An in-process server runs within the same memory space as the application. performance can be severely impacted. An object becomes an object only after it is instantiated (created). An in-process server belongs to the application. Each approach has advantages and disadvantages. The biggest drawback of an ActiveX control versus an ActiveX DLL is that the control must be placed in some sort of . and so on. Although you can certainly create a class module and then reuse it from project to project as needed. In other words. The most significant advantage of an out-of-process server is that it can be shared among other processes. When the reference is made. I discuss the pros and cons of the different approaches as we go along. Components can be in-process or out-of-process servers. When you add the CommonDialog ActiveX control to your project. and events become available to your program. methods.Figure 10. This portability is an especially useful feature because many applications can share the same component.

container object—such as a form. Under a different scenario. An object must contain all the data that it needs to accomplish its mission (such as maintaining employee data). objects need to exhibit certain kinds of behaviors. For instance. you can borrow the interface provided by the Graphics class to create the Text and Draw classes: ' In the text class Implements Graphics . Encapsulation is key. Assume you create two classes—one to manipulate text files and one to draw images. Excel exposes functionality using the same interface to send a chart to a plotter: Chart. you could implement polymorphism using early binding.Print. You can’t use an ActiveX control within a standard module. Business Objects And Object-Oriented Behavior To support object-oriented development. Polymorphism is using the same interface for different objects. This means that the compiler cannot know which object is being referenced when the PrintMe method is invoked. and events to accomplish its goal. methods.Print sText End Sub ' In the draw class Public Sub PrintIt (Place As Form) Place. y1) -Step (x2. which I discuss in this section. The following lines of code implement a generic Graphics class: ' In the graphics class Public Sub PrintIt (Target As Form) End Sub Next.y2) End Sub A form module can then use the common interface in a polymorphic manner: Dm myClass As className myClass. for instance. Instead. It must take responsibility for its mission and not allow any other processes to directly affect its data. it must expose properties. Each might have a PrintIt method. Visual Basic class modules and their resulting objects support these behaviors. an MS Word document exposes functionality to send a document to the printer using the Print interface (or method).Line Step(x1. as shown next: ' In the text class Public Sub PrintIt (Place As Form) Dim sText As String ' Code to read the file Place. so it must resolve it at runtime instead of at compilation.PrintIt Me The previous example illustrates polymorphism using a process known as late binding.

y1)-Step(x2.Private Sub Graphics_PrintIt(Target As Form) Dim sText As String ' Code to read the file Target. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.y2) End Sub Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc. All rights reserved. .Line Step(x1. Read EarthWeb's privacy statement.Print sText End Sub ' In the draw class Implements Graphics Private Sub Graphics_PrintIt(Target As Form) Target.

which passes to the Text and Draw classes all of the interfaces of the Graphics class.To access the contents. This process of customization is called abstraction. Visual Basic does a fair job of simulating inheritance and multiple inheritance (inheriting from two or more objects to create a new object). perform type checking. you pass it the name of the class whose PrintIt method you want to use. as shown in the next example: Private Sub PrintOnForm (myObject As Graphics) myObject. and so on at compilation time. using techniques known as delegation and containment. Delegation allows you to delegate a function to another object instead of doing it yourself. You did that previously by changing the definition of the PrintIt method. click the chapter and section titles. object-specific interfaces. and customize it as needed. you might make one of them a multiline textbox and ignore that interface (the Multiline property) with the other two.) Further. For instance. You are probably already familiar with containment.PrintIt Me End Sub To use this code.) . For instance. as you did with Graphics. the Text class might have declared a reference to the Graphics class. Visual Basic is now able to verify the code. instead of using the Implements keyword. you can customize each class to add its own needed behaviors. Abstraction allows you to take advantage of common features in objects and ignore the differences. The Implements keyword is also used to apply Visual Basic’s admittedly weak implementation of inheritance. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The code uses the Implements keyword. It allows you to borrow from an existing class. if you place three textbox controls on a form. You could have also added other. You do that every time you place a control on a form. (Some call this laziness. The Text and Draw classes inherited all of the interfaces of the Graphics class. it states that an object can contain another object. (The flip side is that they are then required to implement all of those interfaces. The advantage comes when you seek to print something on the form.

I seek to exploit Visual Basic’s newfound ability to create data-aware classes.The next example modifies the PrintIt method of the Graphics class to draw a line on a form. The Text and the Draw classes each contain the Graphics class. Of necessity. and a class module. y1) -Step (x2. The Business Object In this section. The Text class overrides this behavior with its own routine.3 An MDI application using a data consumer class module as the data source of the employee maintenance forms. I create an initial model of an object to maintain employee records. It includes four forms. I convert the class into an ActiveX server and run it on a remote machine. although the ability to do early binding is now gone. The Draw class delegates to Graphics the responsibility to draw a line. if you want. a standard module. You can generate the application with the Application Wizard. In particular.y2) End Sub ' In the text class Private myGraphics As New Graphics Public Sub DoPrintIt (Target As Form) Dim sText As String ' Code to read the file Target.VBP. Then. any object can contain any number of other objects. Figure 10.3.PrintIt Target End Sub Obviously. but I have added more . This process is called aggregation. I first create a simple class module. Creating The Business Object The application that I create is on the enclosed CD-ROM as EmpCLS-Demo. connecting to it over the network.Line Step(x1.Print sText End Sub ' In the draw class Private myGraphics As New Graphics Public Sub DoPrintIt (Target As Form) myGraphics. the examples provided in the earlier section were oversimplified. ' Graphics class Public Sub PrintIt (Target As Form) Target. Any object can still call any of these objects in a polymorphic manner. which will act as the data source in the project shown running in Figure 10.

_ bSuccess As Boolean. When a DataMember is added to the DataMembers collection. (As shown in Figure 10. A data provider can provide different data streams.dsn=Coriolis VB Example.Open "select * from employee Order by emp_no". but the two events are declared as public (which is the default). _ acon. It declares a number of module-level variables as shown: Private WithEvents arsEmp As Recordset Private WithEvents acon As Connection Public Event MoveComplete() Public Event rsUpdateComplete(pError As Error.pwd=coriolis.) The class module is named clsEmpDemo. ' Connect to the database Set acon = New Connection acon.3.capabilities here not generated by the Application Wizard. It is here that you associate the actual data source (the Recordset) with the DataMember as shown: Private Sub Class_GetDataMember(DataMember As String. Connecting To The Data Source The class module normally has only two events: Initialize and Terminate. it is also somewhat less complex.CursorLocation = adUseClient acon. adLockOptimistic ' This gives a control something to bind to DataMembers.Add "EmpPrimary" A DataMember represents a data source for a data consumer." Set arsEmp = New Recordset arsEmp. it creates a qualifier to the DataSource property of a data-aware control. The Initialize event is shown next. the GetDataMember event is triggered." & _ "uid=coriolis. To bind to this class. a GetDataMember event is also defined. which are identified by the DataMember property.Open "PROVIDER=MSDASQL. such as a data-aware control. _ Data As Object) Select Case DataMember Case "EmpPrimary" Set Data = arsEmp . ars As Recordset) The variables are all declared as private. It performs a connection to the database and then adds an item to the DataMembers collection. adOpenStatic. data-aware controls need their DataSource property set to the class (clsEmpDemo) and their DataMember property to the string added by the class (EmpPrimary). In essence. Because I have defined the DataSourceBehavior property to be vbDataSource.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Copyright © 1996-2000 EarthWeb Inc. All rights reserved.EditMode <> adEditNone) End Property Public Property Get EditMode() As Long EditMode = arsEmp.EditMode End Property Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.End Select End Sub I will show you the mechanics of how this event is called when I show you how to “connect” your form to the clsEmpDemo object. Exposing The Business Object I provided a couple of publicly available properties so that the calling object can be aware of whether the Recordset is in edit mode and what the specific edit mode is: Public Property Get EditingRecord() As Boolean EditingRecord = (arsEmp. Read EarthWeb's privacy statement.

Private Sub arsEmp_WillChangeRecord(ByVal adReason _ As ADODB. as discussed in Chapter 2. For example. The user is prompted to save his or her changes.1 illustrates some basic data validation steps.EventStatusEnum. I evaluate the current EditMode.) Any data validation errors cause a message to be displayed. NOTE In my beta copy of Visual Basic. then I perform some basic validations.EventReasonEnum.1. as shown in Figure 10. for instance. _ ByVal cRecords As Long. (You can examine the code on the CD-ROM in the file clsEmpDemo. If a record is being changed. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Remote Data Validation The class contains all the code necessary to manipulate the data. adStatus As ADODB. Later in Listing 10. Space limitations preclude listing the entire module. click the chapter and section titles. The first is an evaluation of the reason that the event was triggered.) Listing 10. I do not bother to validate the data. the adRsnClose code was not being passed. The update is then canceled. if the user attempts to close the window before saving any changes. I developed an alternative workaround in the form code itself in the UnLoad event. listing all the problems.1 Data validation in the empCLSDemo object. which you can examine on the CD.cls. If the mode is delete.Recordset) ' This is where you put validation code Dim bCancel As Boolean Dim iEmpNo As Integer Dim iCtr As Integer Dim sMsg As String Dim arsEmpNo As Recordset . the WillChangeRecord event is called with an adReason of adRsnClose.To access the contents. Listing 10. (Some validating is done on the database via constraints.4. _ ByVal pRecordset As ADODB.

CancelUpdate Case vbCancel adStatus = adStatusCancel Exit Sub Case vbYes ' Need to validate data End Select ' Other reasons Case adRsnUpdate ' Some reasons omitted for space Case adRsnUndoUpdate End Select Select Case arsEmp.sMsg = "The following errors were encountered:" & vbCr ' Why did event trigger? Select Case adReason Case adRsnClose ' Prompt to save changes Select Case MsgBox("Save Changes before closing?". _ vbYesNoCancel + vbQuestion) Case vbNo arsEmp.EditMode Case adEditDelete ' No need to edit data we are deleting Exit Sub Case adEditNone ' No need to validate Exit Sub End Select ' Validate remainder of data With arsEmp If !emp_DOB > Now Then sMsg = sMsg & "Invalid date of birth" & vbCr bCancel = True End If If (!emp_hire_date < !emp_DOB) Or (!emp_hire_date > Now) Then sMsg = sMsg & "Invalid hire date" & vbCr bCancel = True End If If !emp_salary < 0 Then sMsg = sMsg & "Salary cannot be less than 0" & vbCr bCancel = True End If End With If bCancel Then MsgBox sMsg adStatus = adStatusCancel End If .

Because it is private. to display the data.End Sub Figure 10. bSuccess. the module creates publicly viewable events and raises them as necessary. you do not need to nor should you pass this type of information (specifically. pRecordset) End Sub NOTE For illustrative purposes. so the event procedure raises the publicly viewable MoveComplete event.Recordset) Dim bSuccess As Boolean If adStatus = adStatusOK Then bSuccess = True End If RaiseEvent rsUpdateComplete(pError.EventStatusEnum. Within the arsEmp_RecordsetChangeComplete event.EventReasonEnum. ByVal pError As ADODB. you must declare a reference to the module. any code that needs to handle these objects should exist within the class module itself and nowhere else. The form’s module-level declarations are shown next: . the Error and Recordset objects) back to the calling object.EventStatusEnum. Private Sub arsEmp_RecordsetChangeComplete(ByVal adReason As _ ADODB. ByVal pRecordset _ As ADODB. Exposing these objects outside of the class module defeats the purpose of encapsulation and ends up promoting code redundancy. ByVal pRecordset As _ ADODB. I show next the arsEmp_MoveComplete event raised by ADO within the class module.4 Data validation message from the employee class. Private Sub arsEmp_MoveComplete(ByVal adReason As _ ADODB. Accessing The Business Object To access the interfaces of the class module. _ adStatus As ADODB. frmEmpClsDemo. Normally.Recordset) RaiseEvent MoveComplete End Sub Similarly.EventReasonEnum. I added an event to the class module to allow calling objects to be aware of the completion of any update operations. ByVal pError As ADODB.Error. I raise the rsUpdateComplete event. Data Handling In The Business Object The basic data handling is typical of any ADO-based application except that the code lies encapsulated in the class module. _ adStatus As ADODB. To keep any calling objects apprised of what is going on. I used a form.Error. the form that is using the class module as a data source cannot know when a move is complete. I pass back some of the arguments received by the internal event.

. Read EarthWeb's privacy statement.Private Private Private Private Private Private WithEvents empCLSDemo As clsEmpDemo bChangedByCode As Boolean bBookMark As Variant bEditFlag As Boolean bAddNewFlag As Boolean bDataChanged As Boolean The class module is declared using the WithEvents clause.Caption = "Record: " & _ CStr(empCLSDemo. the events of the class then become available within the code editor.2.Description Next End If End Sub Private Sub empCLSDemo_MoveComplete() lblStatus.AbsolutePosition) End Sub Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.Number & vbCr & _ pError. Next. ars As ADODB.Error. which then enables the form to “see” any publicly declared events. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I show you the usage of two of those events: Private Sub empCLSDemo_rsUpdateComplete(pError _ As ADODB. bSuccess As Boolean.Recordset) Dim sMsg As String If bSuccess Then Else Dim vError As Error For Each vError In pError sMsg = "An error has occurred: " & vbCr & _ "Err Number: " & pError. Copyright © 1996-2000 EarthWeb Inc. As shown in Figure 10.

As noted earlier. When you click the Next button on the form. if there was an error.Caption = txtFields(1) & ". across process boundaries. Notice the reference to the AbsolutePosition property of the empCLSDemo object. An interesting problem that I had was in the empCLSDemo_MoveComplete event. click the chapter and section titles. later in this chapter. I show it here to illustrate the passing of objects from one module to another and. The empCLSDemo_MoveComplete event is a little more typical. I hoped that some issues would be resolved by the time the production release of Visual Basic 6 was shipped.To access the contents. it should be done in the class module itself. " & txtFields(2) Although the textbox controls displayed the correct information. I wanted to display the current employee’s name on the form’s caption: Me. I received the data from the previous record if I referenced their Text properties in this event. I examine the status (bSuccess) returned by the class and. I simply update the lblStatus control’s Caption property with the current record number. the following sequence of code is executed: 1. The reason for this discrepancy is interesting if you step through the code. I iterate through the Errors collection. I don’t actually encourage you to do this in the calling form—rather.AbsolutePosition End Property While writing this book. I had to expose the Recordset object’s AbsolutePosition property with a Property Get statement: Public Property Get AbsolutePosition() As Long AbsolutePosition = arsEmp. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- In the empCLSDemo_rsUpdateComplete event. The cmdNext_Click event on the form (which I show next) is . To “see” the current record number. Here.

7. Figure 10. the arsEmp_MoveComplete event is triggered. as shown in Figure 10. so go back arsEmp.Description End Sub 2. This event from the empCLSDemo object is shown next: Public Sub MoveNext() If Not arsEmp. the bound controls and the Recordset are still out of sync. . Once this is finished. as the form is notified that the move is complete. the Recordset has indeed moved to a new record. 4.MoveNext Exit Sub GoNextError: MsgBox Err. the class object’s MoveComplete event is raised. In fact. the two values are not yet in sync.5. but the textbox control bound to this Field still reflects the value from the prior record: Benson. The result is shown in Figure 10. In the arsEvent_MoveComplete. control finally returns to the MoveNext event. The emp_LName Field object’s value is Wesley. this is still the case. Figure 10. I invoke the MoveNext method of the empCLSDemo object: Private Sub cmdNext_Click() On Error GoTo GoNextError empCLSDemo.MoveLast End If End Sub 3.triggered. As soon as the MoveNext method is executed.6.MoveNext End If If arsEmp.EOF And arsEmp.5 The bound controls’ values are not in sync with the Recordset when the Recordset object’s Move-Complete event is triggered. Processing control returns to the form momentarily and where the AbsolutePosition property is accessed so that the record count can be displayed. The object’s MoveNext event is called while cmdNext_Click is still executing.6 Even when the form is “notified” that the move is completed.EOF Then arsEmp. As shown in Figure 10.RecordCount > 0 Then Beep ' Moved off the end. and as soon as it does. In that event. Visual Basic syncs up the values in the bound controls to the values in the Recordset.

" Then empName = "New Record" End If End Property The reason for the test to see if empName is equal to a comma is to check whether the application is currently processing a new record. What this process suggests. as shown next. In the form module. Public Property Get empName() empName = Trim(arsEmp("emp_lname")) & ". although the label control and the form’s caption have been updated.8 The textboxes are not yet updated immediately after the form’s MoveComplete event fires. . really. as shown in Figure 10.Caption = "Record: " & _ CStr(empCLSDemo. A better place to put the notification is in the MoveNext method. The textboxes have not yet been updated to reflect the current Recordset object’s information.Caption = empCLSDemo.7 The bound controls are finally in sync with the Recordset when control is returned to the MoveNext event. and MovePrevious methods. Figure 10.AbsolutePosition) ' Display the customer name on the caption Me.Figure 10.8. which returns a formatted string containing the last and first names of the employee in the current record of the Recordset. I single-stepped through the code in debug mode and took this screen shot immediately after the form’s MoveComplete event completed. MoveLast. (The notification would also have to be placed in the MoveFirst. is that the notification to the form that the move is complete is a little premature. that choice itself creates some problems because the code is somewhat redundant. " _ & arsEmp("emp_fname") If empName = ". Unfortunately.empName End Sub The lblStatus control and the form’s Caption property are updated to reflect the current record number and employee name even before the bound control’s are updated. I altered the event procedure that displays the current record number: Private Sub empCLSDemo_MoveComplete() lblStatus.) What I ended up doing to solve this problem is create a new publicly viewable property within the class module.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. and this menu provides a quick way to locate a specific instance.) This is.9 shows the application with some embellishment. the operator might open many instances of different forms.9 The application has a Window menu item. (Programmatically.Why go to all this trouble? Figure 10. allowing the operator to quickly locate a specific form among many. I added a Window menu that shows the four currently opened forms. similar to the way you probably negotiate the many open windows in your own Visual Basic IDE. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . In an MDI application. all of which are instances of the employee maintenance form. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. Figure 10. of course. you can update the form’s Tag property with the name of the employee as a way to distinguish different instances of each form. All rights reserved.

however.10 I set the control’s DataField property but left DataSource and DataMember blank. each control’s DataSource property is set equal to the empCLSDemo . The association of the controls to the data provider has to occur when the form is instantiated: Private Sub Form_Load() Set empCLSDemo = New clsEmpDemo Dim oText As TextBox ' Bind the textboxes to the data provider For Each oText In Me. As shown in Figure 10.To access the contents. click the chapter and section titles.Visible = True Next SetEdit False End Sub Figure 10. I set their DataField properties to the names of the columns in the database. In development mode.DataMember = "EmpPrimary" Set oText. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Binding Controls To The Business Object To bind the controls to the class module. I left the DataSource property blank.DataSource = empCLSDemo oText. Then.txtFields oText. The DataMember property is set to the value of the object added to the DataMembers collection in the empCLSDemo object’s Initialize event. Visual Basic has no way of knowing that the class module will be a data provider as it does when a Data control is placed directly on the form.10.

property syntax. It provides no buttons to scroll through records and so on. • Process boundary refers to the way that the operating system segregates separate processes. As I will discuss in more detail. These buttons all invoke methods of the empCLSDemo object. When that is done. Before moving further. you can minimize the number of cross-process calls. The SetEdit False line of code from the previous example calls a procedure that unlocks all but the employee ID textboxes for editing. . The goal of the services model is partitioning the application into three (and sometimes more) tiers. such as MoveNext and Update. and so on. For purposes of this discussion. Relocating The Business Object Class modules are powerful weapons in the Visual Basic developer’s arsenal.object. In a sense. a key strength is the ability to compile the class module into an ActiveX server component. the class module becomes a reusable data control—except that it has no visible components. However. such as the values of properties. where a process refers to an application. The advantages of this approach are numerous. DLL. This has advantages. preferring the term partition or tier. I discussed many of them in Chapter 1 in the discussion of the Microsoft services model. The business tier contains the business logic and typically handles communications with the database. you need to understand some basic concepts: • Persistence refers to whether an object’s state is saved between invocations. the component can literally exist almost anywhere on the network and serve as a data provider for multiple clients. The concept of process boundaries has implications in cross-process components. by calling methods that set multiple properties at once. by saving them to disk. by eliminating the need to set many properties and thus reducing the number of calls to the object. a process is more akin to a separate program. Microsoft actually avoids using the word layer. I added the command buttons that you can see in the figures showing the running application. (The word “layer” comes to mind when discussing tiers. It also disables some of the command buttons. • Stateless is a term often used in describing a remote object whose properties are set by calling methods of the object instead of the more traditional object. Objects that aren’t persistent—nonpersistent objects—have the advantage of being simpler to design and implement and are advantageous when there is no need to set properties. The data tier is the data source itself. such as Microsoft Word. Space limitations prevent me from exploring every facet of the object-oriented potential of the class module. particularly with remote objects. Persistent objects “remember” their settings.) The client tier is that piece of the application that runs on the client PC—typically the user interface.

The learning curve with Visual Modeler is fairly stiff. Microsoft bundles a tool called Visual Modeler. particularly for multitiered applications. Figure 10.11 The Employee Class Demo project reverse-engineered into Visual Modeler. methods. but it also involves network traffic. the result is a graphical model built using a subset of Unified Modeling Language (UML). Once the application is modeled. • An in-process component runs in the same address space as the application and is typically a DLL. It runs in its own process space. On the other hand. you can model an application from scratch or reverse-engineer an existing application. Keeping processes discrete promotes the stability of the operating system because the two programs cannot clobber each other with errant calls. • A cross-process component is an executable program that makes its services available to other programs. On the other hand. The component whose services are being utilized is called the server or. The operating system (Windows) goes to a lot of trouble to keep processes separate—running in their own address spaces. The model can be viewed as a logical (business) model or a physical (component) model. which shows all of the objects in your application and how they connect. two separate processes can communicate and share objects. a significant amount of overhead is required to ask the operating system to make calls to other processes. the component runs on an entirely separate CPU from the application that is using it. Using DCOM. and events of another component is called the client. • A remote component runs on another machine on the network. the application program or component that is calling or using the properties. which may offset—perhaps by a lot—the overhead incurred in communicating with it. Either way. more accurately. The tool is also integrated into Visual Studio. entire books can be written about its use. Calls to a cross-process component can be expensive in terms of computer resources. This model exacts a toll in performance because it is not only cross-process. . the benefit from learning the tool is worth the time invested. you can even generate Visual Basic or Visual C++ source code from the model. However.Modeling Your Application With the Enterprise edition of Visual Basic. Figure 10. Running a component as an in-process component saves a lot of overhead but means that the component cannot be shared with other processes. the ActiveX server.11 shows the Employee Class Demo application being modeled by Visual Modeler. With this tool. • With components.

For instance. Each thread lives in its own apartment. Early binding can reduce the overhead of making cross-procedure calls by 50 percent. when crossing process boundaries—the proxy on the client “gathers” together parameters to be passed to the out-of-process component and sends them to a stub on the server component. You set threading options in the Project Properties dialog box. • Minimize or eliminate late binding. See “Apartment-Model Threading in Visual Basic” in the Visual Basic Help file for some more details on . use Set to create an explicit reference to object_b: Set myVar = object_a. Nested object references are time-consuming for Visual Basic to resolve. Instead of coding object_a.property = value. • Marshalling is the method used to invoke the methods and properties of an out-of-process component. passing ByRef works against you.000-byte string). you are better off passing parameters ByVal than you are ByRef. but you can take steps to reduce their impact on performance: • If you need to set a number of properties at one time.Optimizing Cross-Process Calls As noted in the text. With out-of-process components—that is. assume object_a contains a reference to object_b. say. Counter-intuitively. a 2. you can utilize it directly: myvar. (NT runs all applications as separate threads. You can create an ActiveX server that has separate threads for each client communicating with it. oblivious to what is going on in other apartments. • Apartment model threading is illustrated by a house with separate apartments.object_b. it resides in its own apartment.) Threads are normally protected from each other. To force early binding. It is not possible to entirely eliminate cross-process calls.object_b. you can use the client’s stack space to make the calls. use explicit Set or Dim statements. its own copy of global data. With in-process components. With an in-process call.property = value. • Use the With…End With construct to minimize the number of times Visual Basic has to resolve nested objects. This setup is actually the default when creating ActiveX components. most VB developers use ByRef because it involves passing only a pointer to a value or object (as opposed to sending a copy of. consider creating a method where the properties are arguments to the method. For instance. Windows 98 runs 32-bit apps as separate threads within the Windows Virtual Machine. A thread is a separate line of communication within a process—almost like a process within a process. This means that each thread has. Even if the component has a single thread. Then. • Minimize the use of nested object notation. The other object needs to then make a call back to the client to get the value of the parameter. using cross-process calls to or between objects is inefficient. meaning that parameters sent ByRef cause the process boundaries to be crossed twice instead of once. however. for instance. when making cross-process boundary calls. • The concept of a thread is similar to the concept of a process.

options and trade-offs with different approaches. Read EarthWeb's privacy statement. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . All rights reserved. Copyright © 1996-2000 EarthWeb Inc.

and it means that the server application (the ActiveX EXE) must already be running for other processes to use objects from it. I specified ActiveX DLL. . the component can provide multiple objects—but only to the one client. The possible values are shown next: • Private means that no object may access the properties and methods of the class—which is useful only for other objects within the same component. Depending on the type of project you create. This is only appropriate for ActiveX EXEs. • PublicNotCreateable means that any other process can access the class but cannot actually create an instance of the class. • GlobalMultiUse is the same as MultiUse except that you do not have to explicitly declare an instance of the class. For an ActiveX DLL. I separated the clsEmpDemo. For an ActiveX EXE. the Instancing property becomes available. I created a new project. and when asked for project type.To access the contents. it happens automatically as soon as any method or property of the class is referenced. Instancing refers to how and under what conditions objects may be created from the class. click the chapter and section titles. Because this module will be an ActiveX component. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Creating The In-Process Component To illustrate the process of separating the user interface services from the business services of the Employee Class Demo project. the class module will have different properties available. • MultiUse means that multiple processes can create objects from one instance of the component.cls module from the rest of the Visual Basic project. objects can be supplied to multiple clients. I removed the default class module that Visual Basic creates and added the saved clsEmpDemo module. The DLL will run in the same space as the client application.

I compiled my project as AXClsEmpDemo.DLL component. I went to the Project References dialog and added the “Coriolis ActiveX DLL Emp Example” component that I created in the last section. the resulting DLL is registered as an ActiveX component. The possible values are NotPersistable and Persistable. I had to add a reference to it in my original form-based project. the project name is used). Because both SingleUse and GlobalSingleUse allow multiple instances of the same process on a computer. and RequiresNewTransaction. I actually created a new project of type Standard EXE and added the frmClsEmpDemo form to it. When you do. Notice in Figure 10.DLL. The only other changes to the application were slight modifications in the reference to the object (mainly because I renamed it when I created a component from it): Private WithEvents empCLSDemo As clsEmpDemoAX At this point. are NoTransactions. whereas in the object browser. if you are placing objects on MTS. I then saved that form as frmClsEmpDemoAX. RequiresTransactions. Notice also that the class looks like any other component in the browser because it is like any other component. you cannot use the values for an ActiveX DLL. which specifies the level of support the component provides for Microsoft Transaction Server (MTS). A new property is the MTSTransactionMode. Other possible values. The Persistable property sets whether the component can be persisted as discussed previously. I typed “Coriolis ActiveX DLL Emp Example” into the Project Description area of the Project Properties dialog box. the project description is used (and. Figure 10. you can run the application as before. if it’s not entered. Using The In-Process Component To use the AXClsEmpDemo.12 Referencing the in-process component in the application. If you need to debug it. You really don’t need to do anything else to the class project except compile it.• SingleUse allows any object to create objects from the class. Next. the project name is used. but each object created causes a new instance of the class to be created.12 that in the References dialog. you do not have access to the code internal to the component unless you first . I set the Instancing property to MultiUse. UsesTransactions. which you can use much like any other ActiveX component. • GlobalSingleUse is the same as SingleUse except that any reference to a property or method of the class causes the class to be instantiated without first explicitly creating it.

13 shows the running application. Copyright © 1996-2000 EarthWeb Inc. Figure 10. Figure 10. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. .start it in a separate instance of Visual Basic itself. All rights reserved. Read EarthWeb's privacy statement.13 This form is using an in-process component (ActiveX server) as its data source.

shown in Listing 10.To access the contents. I located and registered the module on an NT 4. and application partitioning.14 The Remote Server demo is running on a Windows 98 client connected to a Windows NT 4. take advantage of the server’s presumably greater resources. I had originally sought to use the OpenSchema method. I guide you through the process of creating remote objects hosted on the Internet (or your corporate intranet). shown running in Figure 10. Remote business objects offer the advantages of code reuse.0 server. Running behind the scenes is another application. they can be shared by multiple clients. Figure 10. The Instancing property is set to GlobalMultiUse so that any object need merely reference a method of the business object to create it. However.vbp. For purposes of this chapter. I created a Public Function.14. The remote server is adapted from the VBBusObj sample provided with MDAC and is included on the CD-ROM as VBBusObj. In my testing. encapsulation. Let’s examine the remote server first. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Creating The Remote Business Object In Chapters 12 through 15. I built a flexible data inquiry application. a remote data server.0 library. and more effectively manage connections to the database. The project’s only reference is to the Microsoft Active Data Objects Recordset 2. Visual Basic does not support . The principles of the remote business object are not much different from those for a business object running locally. Additionally. click the chapter and section titles. The guts of the application is a single class module responsible for communicating with the database. The purpose of the function is to return to the client the names of all of the columns in a table.0 server.2.

these are the only values you are allowed to specify. adCmdUnspecified ' Set object pointer for ADOR type recordset Set GetSchema = objADORs Exit Function ehGetRecordset: Err.Recordset ' This function returns the requested schema On Error GoTo ehGetRecordset ' ADO must be registered locally! Dim objADORs As New ADODB.2 The GetSchema function.Recordset objADORs. _ adLockBatchOptimistic. as I discussed earlier in the chapter in “Optimizing Cross-Process Calls. _ ByVal sName As String) As ADOR. and the only items passed from process to process are done so via methods.0 library. I discussed the two ADO libraries—the Microsoft ActiveX Data Objects Recordset 2.this method remotely. These arguments refer to the CursorType and Options properties. Err. Listing 10.) Notice the use of the Set command to set the function equal to the Recordset returned from the Open method. This function is similar in functionality to the GetSchema function. On a remote server. This eliminates a trip (call) to the server from the client.Source.Recordset. I set the MaxRecords property to 1. The ADOR comes from the Recordset -only library reference.Recordset objADORs. Notice the use of the adOpen-Unspecified and adCmdUnspecified arguments on the Open method. as shown in Listing 10.” An examination of the module will show that the object exposes no properties. I will show you how this function is used when I illustrate how to create the client.3 Function used to return a populated Recordset to the client. and I was forced to instead open a Recordset.Description End Function The function returns an object of type ADOR.Recordset ' This function returns an ADODB recordset object On Error GoTo ehGetRecordset ' ADO must be registered locally Dim objADORs As New ADODB.Open sName. Connect. all arguments are passed ByVal instead of ByRef. Public Function GetRecordset(ByVal Connect As String. The other main function in the remote server application is Get-Recordset.3.CursorLocation = adUseClientBatch .Raise Err. To minimize database and network traffic. _ ByVal SQL As String) As ADOR. (In Chapter 7.0 library provides only the Recordset and Connection objects as opposed to the Microsoft ActiveX Data Objects 2. adOpenUnspecified. Public Function GetSchema(ByVal Connect As String.MaxRecords = 1 objADORs. Notice that in both functions. which provides all ADO objects. Err.Number. Listing 10.

_ adLockBatchOptimistic. adCmdUnspecified ' Set object pointer for ADOR type recordset Set GetRecordset = objADORs Exit Function ehGetRecordset: Err.Description End Function The remote server provides a Test method so those clients can quickly ascertain whether they are establishing contact with the server: Public Function Test() As String Test = "You are being heard!" End Function Although not illustrated here. the remote server also has several other methods.objADORs. . Once compiled. You need to deploy it on the target server and register it there and then re-register it at the client machine so that the client can find it on the network. including one to return the machine name and one to execute action queries. All rights reserved. Copyright © 1996-2000 EarthWeb Inc.Open SQL. Err. it is registered as an ActiveX component. Err. Connect. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Number.Raise Err. Read EarthWeb's privacy statement. adOpenUnspecified.Source. The remote server application was built and compiled as an ActiveX EXE. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

0 library. • frmGeneral is a form that is built on-the-fly to display whatever data the user chooses. also included on the CD-ROM. you would have to dynamically alter the menu Caption properties to access other tables. Microsoft ActiveX Data Objects Recordset 2. • frmClsSrvEmp is a form that displays employee data. which contains most of the common code. The last one is the critical piece. a password. vbBusObj (which is the remote server component). click the chapter and section titles. The forms that display data have these module-level references: Private ds As New RDS. • mdiRemote is an MDI form that acts as a shell to the rest of the application. consists of four forms: • frmSrvLogIn is used to pass a connection string. The application references four libraries: OLE Automation. because the menu itself is hard-coded. you can leave the server address blank. NOTE The application allows you to connect to any database via any data provider. a user ID. and the Microsoft Remote Data Services 2.DataSpace Private bo As Object Private objadors As Object The ds object comes from the Remote Data Services library.0 library. If you are running the remote server on your local machine.To access the contents. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Using The Remote Business Object The RemoteSrvrClient application. The project has a single standard module. and a server address to the rest of the application. However. bo and objadors are both . enabling communications over the network.

MousePointer = vbHourglass BldForm f. The PreBuilt menu has only one choice.Caption f. Both lead to cascading menus. Listing 10. sCmd) With f .Visible = True . Public Sub BldForm(f As Form.txtFields(iIndex). It is shown in Listing 10. The table names are stored in the form’s Tag property for later use. meaning that they will be late bound. a Recordset is created using the GetSchema method I discussed earlier.lblField(iIndex). Most of the code is spent building the form. The other cascading menu lists all of the tables in the database by name.Name .Visible = True . passing it the name of the component and the name of the server.Tag Screen.MousePointer = vbDefault End Sub A new instance of form frmGeneral is created.VbBusObjCls". Notice that CreateObject is a method of the ds object. and a procedure. If a user clicks.Name Next . passing the form and the menu item’s Caption property as arguments. is then called. mnuDataRec(index).Caption = tname For iIndex = 0 To objadors.Tag = tname . Employee.txtFields(iIndex). The textbox is then made visible (the form is built with all of the textboxes invisible). for example. The DataField property of each textbox on the form is set to the name of each Field object returned in the Recordset.4.txtFields(iIndex).CreateObject("VbBusObj. the Customer menu choice. Once a reference is obtained by the server and stored in bo. When the application is running. the code shown next is invoked: Private Sub mnuDataRec_Click(index As Integer) Dim f As New frmGeneral Screen. It has two choices: PreBuilt and On The Fly.Fields(iIndex).Caption = objadors.Count . the form is resized to show only the used textbox controls.4 The procedure to dynamically generate a data form. sServer) Set objadors = bo. The procedure creates a basic SELECT statement based on the table name passed to it.1 . The latter contains the name of the table that will be accessed.Fields(iIndex).Fields. BldForm.Fields(iIndex).defined as generic objects. The BldForm procedure is in the standard module because the frmClsSrvEmp form also uses it.DataField = objadors.Text = objadors.lblField(iIndex). Finally.txtGetRecordset = "SELECT * FROM " & f. which creates a form hard-coded to display employee data. It then creates an instance of the remote server component using the CreateObject function. the user can select the Data menu.Name .GetSchema(sConnect. tname As String) Dim iIndex As Integer Dim sCmd As String sCmd = "Select * from " & tname Set bo = ds.

which is in the standard module. Me) Else Set objadors = GetRecordset(Tag. It is similar to the GetSchema method illustrated earlier. When the procedure completes. Listing 10.Text. although it limits the number of columns that can be displayed.Show End With End Sub Note that a more elegant solution is to create the textboxes as needed. Public Function GetRecordset(tname As String.6 The procedure to retrieve the Recordset from the remote server. The user can change the statement if he or she wants. the form is shown with all of the Text properties set equal to the names of the table’s columns.5 This procedure populates the form with data. Pressing the Run command button or any of the scroll buttons will cause the form to fill up with data.5. Me) End If For Each oText In Me.Height = (iIndex * 360) + 1850 .txtFields oText = "" Next If objadors. A textbox on the form is set equal to a basic SQL statement. objadors MousePointer = vbNormal Exit Sub ehcmdGetRecordset_Click: MousePointer = vbNormal MsgBox Err.6. such as SELECT * FROM CUSTOMER. I chose this approach for simplicity. which is done with the code shown in Listing 10.RecordCount > 0 Then bData = True Else bData = False End If ShowData Me.Description bData = False End Sub GetRecordset is shown in Listing 10.. Private Sub cmdGetRecordset_Click() Dim oText As TextBox ' Populate form with data from Recordset On Error GoTo ehcmdGetRecordset_Click MousePointer = vbHourglass If Trim(txtGetRecordset) <> "" Then Set objadors = GetRecordset(txtGetRecordset. The key line of code is the call to GetRecordset. f As Form) _ . Listing 10.

All rights reserved.Description bData = False End Function Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Trim(tname). sServer) Set objadors = bo.CreateObject(sObj. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.GetRecordset(sConnect.MousePointer = vbNormal MsgBox Err.As Recordset Dim sCmd As String On Error GoTo errHandler If InStr(1. sCmd) Set GetRecordset = objadors Exit Function errHandler: Screen. Copyright © 1996-2000 EarthWeb Inc. . Read EarthWeb's privacy statement. " ") = 0 Then sCmd = "Select * From " & tname Else sCmd = tname End If Set bo = ds.

and the form’s Caption property is updated to show the form’s current contents.DataField)) Then oText.DataField) End If If bOkay = False Then oText.Fields(oText. as shown in Listing 10. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- When control returns to the form. click the chapter and section titles. Public Sub ShowData(f As Form.Text = objadors. It essentially moves through each textbox in the txtFields array and compares its DataField property to get the Value of the corresponding Field object and displays it.To access the contents.RecordCount > 0 Then bData = True If bData = False Then Exit Sub On Error GoTo errHandler For Each oText In f.7 The ShowData procedure is called repeatedly to display data on the form passed. the ShowData method is invoked from the standard module.txtFields If IsNull(objadors. The lblStatus control is updated to show the record number. Listing 10. objadors As Recordset) Dim oText As TextBox Dim bOkay As Boolean bOkay = True If objadors. A test is performed to detect and handle the case where the value is Null.Text = "*Not Found!*" bOkay = True End If Next .7.Text = "" Else oText. and the error handler checks for the case where the DataField has no corresponding Field object.Fields(oText.

a call is first made to GetRecordset. objadors End Sub index As Integer.MoveNext End If Case 3 ' Move last objadors.MovePrevious End If Case 2 ' Move next If objadors.8.RecordCount < 1 Then Select Case index Case 0 ' Move first objadors.RecordCount Then objadors. If it is.Number = 3265 Then ' Field not found bOkay = False Resume Next Else MsgBox Err.txtFields(0). a call is made to the ScrollData procedure in the general module.Caption = f.Tag & " . The form has an array of CmdMove buttons.AbsolutePosition objadors. _ Exit Sub > 1 Then < _ .MoveLast End Select ShowData f.Text Exit Sub errHandler: If Err.MoveFirst Case 1 ' Move previous If objadors. Listing 10." & f. objadors As Recordset) If objadors.RecordCount f.f. The form checks whether the Recordset object is equal to Nothing.lblStatus = "Record " & _ objadors.8 This procedure scrolls through the Recordset.AbsolutePosition & _ " of " & _ objadors. The ScrollData Sub performs basic error checking.AbsolutePosition objadors. and then calls the ShowData method.Description End If End Sub The final code of interest is the mechanism to scroll through the records. moves through the referenced Recordset object. When a button is pressed. Public Sub scrolldata(f As Form. as shown in Listing 10.

IIS. Where To Go From Here What I have attempted to do in this chapter is introduce the business object. The remote server component in this chapter was adapted to some extent from the middle-tier component in the Selector directory. All rights reserved. deploy the same objects on your NT server just as well as you can deploy them on MTS. and provide some practical hints on improving component performance. I introduced a simple but illustrative remote server and client. Microsoft has included full-blown client and middle-tier (business-tier) applications in the MSADC directory (generally found under Program Files\Common Files\System\MSADC\Samples\Selector).All of the code in both the remote server and the client is built to minimize the amount of network traffic and also to minimize the number of out-of-process calls. as shown in this chapter. Read EarthWeb's privacy statement. . Chapters 12 through 15 expand and build on these concepts considerably in Internet. describe how to use the object in Visual Basic applications. You can. Internet-based components are not the only tools for building a distributed client/server application. and so on. which you can examine in depth. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. of course.or intranet-based applications.

the customer add fails. and the location of those objects.” Corruption of data involves one or both of two possibilities: inconsistent data. which will be the subject of the remainder of this book. This is accomplished through intelligent database design. we seek to maximize performance and reliability. In terms of the database. do no harm. which we will concentrate on in this chapter. This is done largely through the creation of reusable objects. The second situation might occur because two users change the same record at the same time. incorrect values stored on a record. In terms of component architecture. and sensible database handling techniques. such as an order without a valid customer. which I discussed in Chapters 2 and 3. In doing so. which I introduced in Chapter 10. click the chapter and section titles.” The analogy in client/server is to “First. I will introduce the concept of . for some reason. do not corrupt the data. One of the edicts of medicine is to “First. or. we seek to maximize performance and data integrity. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Chapter 11 Visual Basic 6 Advanced Database Topics Key Topics: • Data validation and integrity constraints • Data dictionary • Stored procedures and triggers • Generating primary keys • Transaction and concurrency management There are two keys to a successful client/server application: database techniques and component architecture.To access the contents. The first situation can happen if we update a database by adding a new order but. I will spend a good amount of time in this chapter discussing data integrity constraints and differing approaches for accomplishing it.

and client resources. Encoding is not encrypting as its name implies—rather. The same is true for many other types of data. this is the preferred method because it involves the least usage of network. Referential integrity involves the defining of a database integrity constraint. as shown next: . as seen next: St_ID MA MD ME St_Name Massachusetts Maryland Maine Such lookup tables then become a convenient means to validate data as well.the data dictionary. as seen in this example: ' Note that this would be a very inefficient method to ' validate. I will then lead you through the creation and use of stored procedures and triggers using data validation as a key objective. Data Validation Ensuring the integrity of your data is paramount. Storing the fully expanded values wastes space. You and I know that F means Female and CA means California. it is more typical to encode the values as F or M. This process expands the encoded value to its full description. it is the abbreviation of common values. we need to provide a facility to decode values as well. So. But. In general. such as state and provinces.Open "Select st_name from state where " & _ "st_ID = '" & txtState. and network traffic utilization. If your order entry application allows an order to be placed without a valid customer or an address to have an invalid state. you stand to lose a lot of money and business.text & "'". In this section.SetFocus End If Referential Integrity In Chapter 2. acon If arsState. data entry time. This is done via one or more lookup tables where we store in one column the encoded value and in another column the decoded value. You would normally already have a Recordset open Set arsState = New Recordset arsState.RecordCount = 0 then MsgBox "State Code Invalid!" txtState. Employees can be female or male. I will then spend the remainder of this chapter discussing the concepts of transaction management and concurrency as well as a couple other issues that I have found to be troublesome to client/server developers. Consider the Emp_Gender column on the Employee table. So. the computer doesn’t know that. I discussed the concept of the referential integrity mechanism and showed you how to create the DDL necessary to create it. I will walk you through some of the issues relating to data validation. Encoding And Decoding Certain types of data lend themselves to encoding. database.

as the case may be) is validated. cust_st) References State (st_ctry_id. If such an entry is made. There are a . That is all well and good where it is feasible. as shown next: Create Table State (St_Ctry_ID Char(3) Not Null. it is not for Canada. st_id) In this way. St_Name VarChar (21). Ctry_Name Char(30). Constraint PK_Ctry Primary Key (Ctry_ID) ) And you would add a constraint to the State table as such: Alter Table State Add Contrant fk_valid_ctry Foreign Key (st_ctry_id) References Country (ctry_id) You can see where we easily start getting a lot of tables involved. The State table validates the country via a foreign key constraint to the Country table. I will talk about that in a moment.Alter Table Customer Add Constraint fk_valid_state Foreign Key (cust_st) References State (st_id) This constraint prevents the entry of a state code that is not already on the State table. your constraint on the Customer table would look more like this: Alter Table Customer Add Constraint fk_valid_ctry_state Foreign Key (cust_ctry. St_ID Char(2) Not Null. But. a country code is recorded on the customer record? While MA might be a valid state code in the US. Constraint PK_Cntry_St Primary Key (St_Ctry_ID. You might consider having a separate Country table as well: Create Table Country (Ctry_ID Char(3) Not Null. for the time being. What if. though. If the customer happens to be from a country with no states (or provinces). which has the effect of dragging down database performance. Of course. then the country will not be listed on the State table. The Customer table verifies whether the country/state combination is valid via a foreign key constraint to the State table. the database generates an error and refuses to insert or update the record. So. the combination of country and state (or province. St_ID) ) Then. we also have the problem of those countries that don’t happen to have states. you might alter the State table to have a compound primary key. that does not mean that the country code entered into the State table is valid.

Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. All rights reserved. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement.number of solutions.

1. The database would attempt to find a row on the State table where st_ctry_id = “BER” and st_id is Null. The ending (simplified) CREATE statements look something like Listing 11. assume the customer is from Bermuda and that Bermuda’s ctry_id is BER. For example. But. the foreign key relationship is no longer conditional. Putting such a row on the State table for every country would be awkward. We cannot make cust_st nullable and leave cust_ctry as NOT NULL. DROP TABLE COUNTRY . which creates a conditional constraint. click the chapter and section titles. Because we have made the cust_ctry column nullable. That solves the problem of a customer legitimately not having a state or province (perhaps the customer is from Aruba or Bermuda).1 SQL CREATE statements with conditional referential integrity. With a value present. A conditional constraint is one where the data must be valid if present. But. By leaving cust_ctry as NOT NULL. we might create a second foreign key on the Customer table like this: Alter Table Customer Add Constraint FK_valid_cust_ctry Foreign Key (cust_ctry) References Country (ctry_ID) Again. we can still trick the database. Listing 11. valid. the database then validates the country against the Country table while not validating against the State table if the state field is not entered. in fact. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- You can make the cust_ctry and cust_st columns on the Customer table nullable. this is not enough. CREATE TABLE COUNTRY (CTRY_ID CHAR(3) NOT NULL. it does not help to enforce that the country is. the relationship is not automatically enforced.To access the contents. So. . We can add a constraint on the cust_ctry column to enforce that the length of the column must be greater than 0.

CONSTRAINT PK_CTRY_ID PRIMARY KEY (CTRY_ID) ). DROP TABLE STATE .'Canada') . 'USA'. ST_CTRY_ID) ). INSERT INTO STATE VALUES ('RI'. 'USA'. ALTER TABLE CUSTOMER ADD CONSTRAINT FK_VALID_ST FOREIGN KEY (CUST_ST. 'CAN'. 'Ontario') . CONSTRAINT PK_ST_ID PRIMARY KEY (ST_ID. INSERT INTO COUNTRY VALUES ('CAN'. ST_CTRY_ID CHAR (3) NOT NULL. ALTER TABLE STATE ADD CONSTRAINT FK_VALID_CTRY FOREIGN KEY (ST_CTRY_ID) REFERENCES COUNTRY (CTRY_ID) . DROP TABLE CUSTOMER .'United States') . . CONSTRAINT PK_CUST_NO PRIMARY KEY (CUST_NO) ) . INSERT INTO COUNTRY VALUES ('BER'. 'British Columbia') . INSERT INTO STATE VALUES ('BC'. INSERT INTO COUNTRY VALUES ('USA'. ST_NAME VARCHAR (21) NOT NULL. 'CAN'. CUST_LNAME CHAR (21). ST_CTRY_ID) . CUST_CTRY CHAR (3) DEFAULT 'USA' .CTRY_NAME VARCHAR (35) NOT NULL. 'Rhode Island') . CUST_FNAME CHAR (15). INSERT INTO STATE VALUES ('MA'. 'Massachusetts') .'Bermuda') . INSERT INTO STATE VALUES ('ON'. CREATE TABLE CUSTOMER (CUST_NO NUMERIC (9) DEFAULT AUTOINCREMENT. CUST_ST CHAR (2). CUST_CTRY) REFERENCES STATE (ST_ID. CREATE TABLE STATE (ST_ID CHAR(2) NOT NULL. CUST_TIMESTAMP DATE DEFAULT CURRENT TIMESTAMP.

'MA') . The SQL CREATE statement looks something like the following: CREATE TABLE Data_Dic (dd_type CHAR (6) NOT NULL. and dd_desc is the decoded value (Rhode Island or Bermuda). I will discuss those issues later in the chapter. The impact on the database is tremendous. dd_val is the encoded value. INSERT INTO CUSTOMER (CUST_LNAME. you could easily end up joining four. CUST_FNAME. CUST_CTRY) VALUES ('Smith'. If you are displaying data from a single table. INSERT INTO CUSTOMER (CUST_LNAME. INSERT INTO CUSTOMER (CUST_LNAME. six. 'BC'. such as state codes or country codes. . 'MA'. INSERT INTO CUSTOMER (CUST_LNAME. What I have done to get around this problem is to place all my validation data into a single lookup table with three columns: dd_type (the dd is for data dictionary) designates the type of lookup. The Centralized Data Dictionary Lookup Table Having too many discrete lookup tables begins to make your design look like an octopus with arms “hanging” off of each master table. CUST_FNAME. CUST_ST. 'Jane'. CUST_ST. dd_val CHAR (32) NOT NULL. such as RI for Rhode Island or BER for Bermuda. 'USA') . CUST_ST) VALUES ('Smith'. CUST_FNAME. 'BER') . I have specified an AutoIncrement default for the primary key and I have also added a TimeStamp column. CUST_ST. CUST_CTRY) VALUES ('Brown'.ALTER TABLE CUSTOMER ADD CONSTRAINT FK_VALID_CTRY FOREIGN KEY (CUST_CTRY) REFERENCES COUNTRY (CTRY_ID) . 'Barbara'. or more lookup tables as well. 'John'. 'CAN') . Notice in the SQL CREATE statement for the Customer table. 'Bob'. ALTER TABLE CUSTOMER MODIFY CUST_CTRY CHECK (CUST_CTRY > ' ') . CUST_CTRY) VALUES ('Brown'. NULL. CUST_FNAME.

dd_val AND cc. we have placed all of our validation into a single table eliminating the need to join many tables to perform simple reporting. To use the table in a customer listing. cust_lname As "Last". (We are back in the same boat as we were before in that the countries and states are not cross-referenced. but I will come back to that problem in a moment. something like the following: SELECT cust_no AS "Cust No". sc. CONSTRAINT PK_LookUp Primary Key (dd_type. including the decoded state and country values. cust_fname AS "First". cc. The results are as follows: Cust No ------1 2 3 4 First -----John Jane Barbara Bob Last -----Smith Smith Brown Brown State ---------------Massachusetts Massachusetts (NULL) British Columbia Country -----------United States United States Bermuda Canada Now.dd_desc As "State". dd_val) ) Some sample data in such a table is shown next: DD_Type ------CC CC CC SC SC SC VRT VRT VRT DD_Val -----BER CAN USA AZ MA RI CC SC VRT DD_Desc ----------------Bermuda Canada United States Arizona Massachusetts Rhode Island Country Code State Code Valid Record Type The key to the table’s usage is the VRT record.) Previous Table of Contents Next .dd_desc VARCHAR (64).dd_desc AS "Country" FROM customer.dd_type = 'SC' AND cust_ctry = cc.dd_val AND sc. data_dic sc WHERE cust_st *= sc. data_dic cc.dd_type = 'CC' The query retrieves customer information. This particular example uses Transact-SQL dialect to perform a left outer join. which specifies the valid record types and what they are used for. code an SQL SELECT statement.

. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. Copyright © 1996-2000 EarthWeb Inc. All rights reserved.

dBase developers will remember that you could validate by hard-coding a portion of the other table’s key—if SQL allowed this. of course. what is left to accomplish the validation? The obvious answer is to open record sets from VB to validate our data: Set arLookup A= New Recordset Set arCust = New Recordset ' acon is an active connection arLookup.To access the contents. cust_st) REFERENCES DATA_DIC (dd_type. so that you could validate cust_st against dd_val where dd_type = ‘SC’. how do we use the table for validation? It is no longer possible to have referential integrity constraints.EOF = True Then ' No records MsgBox "Invalid Country!" txtCountry. dd_val) The (‘SC’. acon If arLookup.text. So. because there is no unique key for the database to validate against.BOF = True and arLookup. click the chapter and section titles. it would look something like: ALTER TABLE CUSTOMER ADD CONSTRAINT FK_Val_State FOREIGN KEY ('SC'. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Now that we have a convenient place from which to decode values (and potentially to encode as well). The primary key of Data_Dic is dd_type and dd_val combined. cust_st) would be needed.Open "Select * from data_dic Where dd_type = " & _ "'CC' And dd_val = " & txtCountry.SetFocus Exit Sub Else ' proceed with update End If .

and perhaps other fields. Besides the obvious uses. As such. we have created a situation where each update involves potentially many queries to validate the data. Second. But. your company may have several divisions (or subsidiaries) that keep their general ledgers independently. stores data that is not static—prices can change. postal code. Keeping Common Data In Memory The typical application often validates against a common set of information. from loading specific subsets of the data into memory. Any data that is common to all divisions has a dd_div code of “ALL”. Why? The state lookup table stores the encoded state values (AZ for Arizona. and so on. one lends itself to pre-loading into memory. In one division. both because it will likely become very large and because it potentially may have some dynamic (non-static) data in it. currency exchange data. and so on. The common lookup table that I discussed in the prior section is an example of a table you probably don’t want to load into memory. and the other doesn’t. a better solution would be to open the Recordset as . Assume you have many different forms that validate state codes. Sometimes. I will show you two ways to get around that problem. calendars. on the other hand. If a table has many thousands of rows. you will bring client performance to a screeching halt. items can be added. the data is static. CA for California. such as division. That doesn’t preclude you. such as storing valid state and country codes. In the preceding example. First. In these cases. In other words. you might be better off loading the data into memory—perhaps as an array—and accessing it that way. and so on). values vary by an independent factor. It is a drain on resources to repeatedly request the same information from the database. For instance. we would also have to validate state. each time a client logs into an application. a tremendous amount of data is going to be pulled over the network. general ledger account types. which is data not subject to change. In the next two sections. Both of these types of data tend to be accessed a lot. Other Uses For The Data Dictionary Table You can use the data dictionary table for many purposes. Rather than opening a Recordset object in each one. account 1400 might be Fixed Assets while in another division it might be Accumulated Depreciation. you probably don’t want to load it into memory. because all of that data takes up valuable resources (RAM) and will almost certainly be swapped in and out to disk. Depending on the type and amount of data. however. the data cannot simply be stored in memory—the application needs to access the database to ensure it has the most current version available. so they represent good areas to explore for minimizing database and network traffic. thus defeating the whole purpose of minimizing network traffic. I have used it to store tax tables. Consider two common needs in an order-entry application—the state lookup table and the item lookup table. I have used a four-column table with the first column being dd_div.It would appear that even though we have saved the joining of many tables on data retrieval. The item lookup table.

Using triggers. you can have the database enforce your data validation rules.Public when the application opens: ' Assumes a standard module Public arState As Recordset Public arCon As Connection Sub Main ( ) ' Display a splash screen to keep them ' amused while loading data frmSplash. let the database perform the validation using triggers. using data validation for many of the examples. it is all done on the database. if a change is needed. All programs immediately gain the benefits of the changes. The Trigger As A Data Validation Tool The trigger is a special stored procedure that is automatically invoked by the RDBMS as a result of a predefined action. However. . Read EarthWeb's privacy statement. the change is done in one place—at the database. The best solution of all is to not perform the validation at the client—instead. The advantage to this approach is that it is more flexible than referential and check integrity constraints.Open "Select * From data_dic Where " & _ "dd_type = 'CC' Order By dd_val". Copyright © 1996-2000 EarthWeb Inc. Further. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. I will discuss stored procedures and triggers. and every program that accesses the database gains the advantage of the data validation rules already being defined. In the next section.Show ' Open the connection object here ' Now open the Recordset Set arState = New Recordset arState. such as UPDATE or DELETE. acon UnLoad frmSplash End Sub A better solution than loading up the Recordset and keeping it in memory would be to save its contents to an array and close the Recordset to free up database resources. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved. you would then have to write your own routines to search the array for the value(s) that you are looking for.

the design for the remote. click the chapter and section titles. such as data validation. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Stored Procedures And Triggers Throughout this book. your application will benefit from increased performance levels. Stored Procedures On Differing RDBMSs Unfortunately. You can think of a stored procedure as analogous to a Visual Basic general procedure where a trigger is analogous to an event procedure. such as a button click. the issue is perhaps even more critical. out-of-process server was very different than the design for a local. In the previous sections. you . in-process server. In Chapter 10. because the nature of client/server itself is the manipulation of remotely stored data. we stacked calls by passing property references as method arguments. we sent requests to the server asking if certain data (such as state codes) was valid. we discussed different aspects of data validation. In some of the examples. triggers are essentially stored procedures that occur automatically as the result of a predefined action.To access the contents. The event procedure also occurs as the result of a predefined event. Only after several roundtrips were we ready to send the update request to the database—hardly an efficient way of doing things. Whereas stored procedures have to be explicitly called. With the database. In that example (for the remote server). I repeatedly allude to the most important aspect of client/server development (outside of integrity of the data itself): minimizing network traffic. for instance. stored procedures and triggers are the area where the different dialects of SQL have significant differences. The database then had to send the answers back. Although they are similar. To the extent that you can minimize the number of times that data has to move between your application and the database server. Stored procedures are small programs that sit on the database performing specific tasks.

The equivalent Microsoft SQL Server stored procedure takes this syntax: CREATE PROCEDURE emp_raise (@deptno int. traditionally also based on T-SQL. For instance. There can even be differences between different versions of the same RDBMS—vendors tend to enrich the language as the products evolve. See your own database’s documentation for additional details. I will provide . the differences are outweighed by the similarities. you will have to create the stored procedure on your database while making any necessary changes in syntax. Oracle uses a dialect of SQL known as PL/SQL. @raise_pct real) AS BEGIN UPDATE employee SET emp_sal = emp_sal * (1 + raise_pct) WHERE emp_dept = deptno. Microsoft’s SQL Server. To use any of the examples I present here. we realize three distinct advantages: • Code reusability—All code modules use the same database procedures. • Precompilation—Stored procedures (and triggers) are precompiled on the server and so run more efficiently than does dynamic SQL. the differences between SQL Server and Oracle are small—mainly how parameters are declared. the following Oracle stored procedure is used to give employees a raise. END TIP Advantages To Stored Procedures By moving code to the database. raise_pct IN NUMBER) AS BEGIN UPDATE employee SET emp_sal = emp_sal * (1 + raise_pct) WHERE emp_dept = deptno. The code calls the function passing the department number and the percent of the raise—all employees in that department will be affected: CREATE PROCEDURE emp_raise (deptno IN NUMBER. END In this example. Still.cannot take an Oracle stored procedure to Microsoft SQL Server and expect it to run without some modifications. The larger differences show up in the body of the stored procedure—those lines between the BEGIN and END statements. has been moving away to its own dialect of SQL. • Minimization of network traffic—The server and client only have to communicate in the event of an error. Sybase uses Transact SQL (T-SQL). so network traffic is dramatically reduced. As discussed in Chapters 2 and 3.

Using The Stored Procedure In Visual Basic You can use the stored procedure within your VB project easily. END The Oracle equivalent is shown next: DROP PROCEDURE sp_lookup . The Lookup Stored Procedure To illustrate the creation and use of stored procedures.dd_val%TYPE. I will start with some modifications to the Data_Dic (data dictionary) table created earlier in the chapter. This book’s CD-ROM includes the text of the stored procedures (and triggers later in this chapter) that I use for examples. lu_desc OUT data_dic. Figure 11. END In the Oracle stored procedure. lu_val IN data_dic. OUT lu_desc CHAR(64)) BEGIN SELECT dd_desc INTO lu_desc FROM data_dic WHERE dd_type = lu_type AND dd_val = lu_val. it is not necessary to open a Recordset object.1 shows an application that opens the Customer table and displays the full text of the customer’s state and country. In an ADO environment where only one record is being returned. let’s create a simple stored procedure that we can call whenever we need to retrieve an un-encoded value from the data dictionary using SQL Anywhere syntax: CREATE PROCEDURE sp_lookup (IN lu_type CHAR (3). IN lu_val CHAR(32). I used a special notation for data types—%TYPE—referencing the data type of the underlying column on the Data_Dic column. First.dd_type%TYPE.dd_desc%TYPE ) AS BEGIN SELECT dd_desc INTO lu_desc FROM data_dic WHERE dd_type = lu_type AND dd_val = lu_val . The advantage of this is that if the data type changes—perhaps making a column larger—the stored procedure does not need to be revised. CREATE PROCEDURE sp_lookup (lu_type IN data_dic. While the application could have been done using a join between the Customer and Data_Dic tables (and would probably be a little more .some examples in different syntaxes as I go along.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.1 This application uses a stored procedure to retrieve values from the data dictionary. The ADO objects created in the application are shown next: Private Private Private Private WithEvents acon As Connection acmd As Command acmdDataDic As Command WithEvents ars As Recordset Figure 11. I chose to use the sp_lookup stored procedure to get the un-encoded values from the data dictionary.efficient). All rights reserved.

dsn=Coriolis VB Example.Connection) ' Connect complete .") End Sub The connection is established asynchronously. Note that I am using the stest user id in these examples for the sake of simplicity. .pwd=stest.MousePointer = vbDefault . the ConnectionComplete event occurs. acmdDataDic is created as a reference to the sp_lookup stored procedure: Private Sub acon_ConnectComplete(ByVal pError As _ ADODB. adCmdText Screen.ActiveConnection = acon Set ars = New Recordset Set acmdDataDic = New Command Set acmdDataDic.open record set Set acmd = New Command acmd.CommandText = "Select * from customer" acmd. Previous to that.EventStatusEnum.Error. the application works identically. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The application issues a connect to the database when the form opens. and the record set is opened.CommandText = "sp_lookup" acmdDataDic. click the chapter and section titles.Open ("PROVIDER=MSDASQL.To access the contents. _ ByVal pConnection As ADODB. adLockOptimistic." & _ "uid=stest. as shown next.ActiveConnection = acon acmdDataDic. adStatus As ADODB.CommandType = adCmdStoredProc acmdDataDic. adOpenDynamic.MousePointer = vbHourglass Set acon = New Connection acon. When complete.CommandTimeout = 15 ars. Private Sub Form_Load() Screen. If you choose to work with the coriolis user id.Open acmd.CursorLocation = adUseClient acon.

If I had opened the record set first. RecordCount is usually equal to -1. ByVal pError As ADODB. It would be a good idea to verify whether the RecordCount property is valid before displaying it. End Sub TIP Asynchronous Timing In the code listing. I can run into timing problems if the query completes before cmdDataDic is created. As you will see in a moment. Specifically. the MoveComplete event would trigger. I deliberately rearranged the order of creating objects in order to highlight the timing issues that can be a real thorn in the side of a developer who is moving from a synchronous data model. Also. This seemed to occur in the development environment while debugging and presented . ADO would almost certainly have waited for the execution to complete before taking a look at the stored procedure. ByVal pRecordset As _ ADODB. Working in an asynchronous environment is a bit more complex than working in a synchronous environment. I noted times when ADO became confused as to what the current record number (as returned by the AbsolutePosition property) was. Then. Notice also that I create the Command object for the stored procedure prior to opening the record set. taking precedence over the code remaining in the ConnectComplete event.RecordCount ShowRecs End Sub The RecordCount Property Note that not all data providers support the RecordCount property at all times. the MoveComplete event is triggered as shown: Private Sub ars_MoveComplete(ByVal adReason As _ ADODB. The MoveComplete event would then make a call to ShowRecs. you may want to avoid referencing this property to avoid the performance penalty inherent in unnecessarily returning the entire result set. When ars is opened.EventStatusEnum. ADO will go out and “look” at the stored procedure when the command type property is set. Moral: Create all your objects prior to executing or opening them. As soon as the CommandType property is set. ADO goes to the data provider and ascertains the stored procedure’s parameters.Recordset) txtRecord = "Record " & _ ars. it is not necessary to declare any Parameter objects. in my testing. without getting the stored procedure created prior to opening the record set. If you are returning more than a couple dozen records.AbsolutePosition & " of " & _ ars. which would not even as yet exist. consider that most data providers need to return the entire result set before they can populate the RecordCount property. As a final note. They are set in the same order as defined in the database—the two input parameters are first and the output parameter is last. _ adStatus As ADODB. which would invoke the stored procedure.EventReasonEnum.' Command object for the stored procedure.Error. If not supported.

as we did in Chapter 7. ddval As _ String) As String Dim arsDataDic As New Recordset GetDataDic = "" acmdDataDic. and then read the output parameter: Private Function GetDataDic(ddType As String. so those properties (Direction and Type) do not need to be set.Execute GetDataDic = acmdDataDic. Because ADO has already looked at the stored procedure. If you notice this happening in your application during production.Value Next ' Get state If IsNull(ars!cust_st) Then sSt = "" Else sSt = RTrim$(ars!cust_st) End If txtFields(3) = GetDataDic("CSR". it is not necessary to create Parameter objects or to append them to the acmdDataDic object’s Parameters collection.Parameters(2) . AbsolutePosition = -14). Since this is a non-record-returning query (only the one output value is being returned). _ RTrim$(ars!cust_ctry) & sSt) ' Get country value txtFields(4) = GetDataDic("CC". ADO can determine the direction and type of the parameters also. Note that because the cust_st column is allowed to be Null. execute the command. If you save a record location in a bookmark and the bookmark then seems invalid. which I found curious (because neither VB nor ADO seemed to really know what the current record was). Normally. Assign values to the input parameters. as shown next. _ ars!cust_ctry) End Sub Finally.Parameters(1) = ddval acmdDataDic. the GetDataDic procedure is very simple—much more so than calling a parameterized query.itself as record numbers below zero (that is. I have to handle that before calling the stored procedure: Private Sub ShowRecs() Dim iCtr As Integer Dim sSt As String For iCtr = 0 To 2 txtFields(iCtr) = ars. consider simply using a Find on the primary key for the current record. the workaround that I found is to perform a MoveFirst followed by a move back to the current record.Parameters(0) = ddType acmdDataDic. The ShowRecs procedure populates the first few textbox controls with the customer number and name and then calls the GetDataDic procedure to retrieve the state and country names. it is not necessary to open a Recordset.Fields(iCtr). I was able to first save the current record in a bookmark. to get yourself back to the current record.

Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. .End Function When ADO dynamically creates the Parameter objects. their Name properties are set to their names in the stored procedures. All rights reserved. In this example. the first parameter has a Name property of lu_type (the name of the corresponding column in the database). Copyright © 1996-2000 EarthWeb Inc.

dd_type. SELECT COUNT (data_desc) INTO data_count . So. The VRT records tell us what each record type is used for and also should restrict the records that are entered into the data dictionary to valid entries. the data dictionary requires a VRT record for each record type maintained. tr_dd_validate. To enforce this rule. a database trigger is much like a stored procedure except that where a stored procedure must be explicitly called. click the chapter and section titles. I should not be able to enter TX record types if there is no such thing as a TX record type. This is a sort of implied referential integrity constraint. a trigger is invoked automatically as the result of an action on the database. DECLARE data_count INTEGER . Recall that the data dictionary has a record type of VRT. let’s enhance the data validation aspects of the Customer table and data dictionary. /* Is record type valid? */ CALL sp_lookup ('VRT'.To access the contents. I created a trigger. DECLARE data_desc CHAR (64) . UPDATE ON data_dic REFERENCING NEW AS new_data FOR EACH ROW BEGIN DECLARE data_type CHAR (3) . new_data. data_desc) . In other words. To illustrate the use of triggers and expand on the concept of stored procedures. If data_count = 0 THEN RAISERROR 99999 'Invalid Record Type For Data Dictionary'. as shown next: CREATE TRIGGER tr_dd_validate BEFORE INSERT. for valid record types. DECLARE data_val CHAR (32) . Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- About Triggers As I mentioned earlier. .

before a country/state cross-reference record can be defined. UPDATE ON customer REFERENCING NEW AS new_cust FOR EACH ROW BEGIN DECLARE data_st CHAR (2) . this error is returned like any other database error. thus preventing any invalid record types from getting into the data dictionary. which. A few lines later. END IF. Assume you were adding a new country code (CC) record. What I did here was to create a special kind of record that handles country/state cross-references. and a holder variable in which to return the description of the record if found. data_val. CREATE TRIGGER tr_cust_validate BEFORE INSERT.RETURN .dd_type = 'CSR' THEN SET data_val = LEFT (new_data. you may recall.dd_val || ' '. DECLARE data_ctry CHAR (5) . I eliminated the SC record type. In other words. tr_cust_validate. SELECT COUNT (data_desc) INTO data_count . END IF. As soon as you (or your application) sends the new record to the database. the trigger is defined to fire automatically any time the data_dic table is updated or has a row inserted into it. It passes a record type of VRT. contained all of the state and province names. The text of the error along with the error code is passed back to the application. You can use any return code not already used by the database (check your database documentation for more details). /* If country state. To enforce this referential integrity. END As you can see. verify country */ IF new_data. . You can also use the REFERENCING OLD clause to create a reference to the existing data prior to its being updated (which I will do in another trigger momentarily). DECLARE data_count INTEGER . When you display errors. The CSR record contains values like CANBC for British Columbia. The trigger declares some work variables and then calls the sp_lookup stored procedure that we examined in the last section. The trigger enforces the rule that. CALL sp_lookup ('CC'. the country must already be defined in a CC record. the RAISERROR function is invoked if the record was not found. The 99999 is a user-defined error return code. DECLARE data_desc CHAR (64) . data_desc) . I can’t add “Montana” to the data dictionary until I first add “United States”. The third line of the trigger uses the REFERENCING NEW clause to create a reference to the new data being updated or inserted. The second part of the trigger handles CSR records. the new record type. IF data_count = 0 THEN RAISERROR 99999 'No Such Country Record Defined' . END IF . shown next: DROP TRIGGER tr_cust_validate . this trigger automatically checks to see if there is a corresponding VRT record. 3) . I created another trigger.

cust_ctry. If not./* Is country valid? */ IF new_cust. it validates the proper construction of the data dictionary’s CSR key. data_desc) . END IF .cust_st . CALL sp_lookup ('CSR'. if there is no state. Better yet. Also. END IF . IF data_count = 0 THEN RAISERROR 99999 'Invalid State:' || new_cust. SELECT COUNT (data_desc) INTO data_count . but.cust_st IS NULL THEN SET data_ctry = rtrim(new_cust. RETURN . at this point. SET data_ctry = rtrim(new_cust. But. CALL sp_lookup ('CSR'. the validation occurs automatically on the server.cust_ctry IS NULL THEN RAISERROR 99999 'Country can not be null!' .cust_ctry. data_ctry. tr_cust_validate verifies that the country on the customer record is valid. /* Is state valid? */ IF new_cust. END IF . much like an Exit Sub or Exit Function command in Visual Basic. RETURN . The syntax is a little less forgiving. As soon as SQL encounters the RAISERROR command. If data_count = 0 THEN RAISERROR 99999 'Missing CSR Record On Data Dictionary:' || data_ctry. the database would be corrupt.cust_ctry) || new_cust. . it is not all that much different than a Visual Basic program. it is pretty much impossible to enter a customer with an invalid country or state. IF data_count = 0 THEN RAISERROR 99999 'Invalid Country:' || new_cust. END IF . you might notice that the body of the trigger is pretty much the same as the body of a stored procedure. SELECT COUNT (data_desc) INTO data_count . new_cust. once you get used to it. RETURN . So. data_desc) . data_desc) . the update or insert is cancelled. SELECT COUNT (data_desc) INTO data_count .cust_ctry) . what’s to stop someone from deleting a record from the data dictionary that is being referenced? If someone were to delete a “USA” country code record while customers were on the database using that record. The trigger then validates the country/state combination. or.cust_st . it’s not bad. data_ctry. END IF . END As you walk through the code. an error is raised and a message is sent back to the application. The RETURN statement tells the trigger not to continue processing after the error. CALL sp_lookup ('CC'.

Read EarthWeb's privacy statement.Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. . All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc.

/* Is this a VRT record? */ IF old_data. CREATE TRIGGER tr_dd_validate_delete BEFORE DELETE ON data_dic REFERENCING OLD AS old_data FOR EACH ROW BEGIN DECLARE data_table CHAR (32) . I wrote a generic trigger to handle a wide variety of deletions from the data dictionary.To access the contents. for referenced table name. for referenced table column. and RTC. DECLARE data_desc CHAR (64) . If you want the generic validation routine to be active for a given record type. click the chapter and section titles. it should make sure that that the cust_ctry column on the Customer table does not reference that CC record. For instance. I would add two records to the data dictionary: dd_type RTC RTN dd_val CC CC dd_desc cust_ctry customer These records will tell our new trigger that if someone attempts to delete a CC record. DECLARE data_count INTEGER . if I wanted to prevent someone from deleting a country code (CC) record that was being used. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- To handle this. then you would add one of each of these two records for the given record type. I created two new record types: RTN. To support this.dd_type = 'VRT' THEN /* Don't let them delete a referenced record! */ SELECT COUNT(*) INTO data_count . Let’s look at the trigger: drop trigger tr_dd_validate_delete . What I wanted to do was to avoid having to write a trigger to handle each and every record type in the data dictionary. DECLARE data_column CHAR (32) .

of course).dd_val || char(39) . then a check is made to see if there are RTN and RTC records. END This trigger is declared to occur whenever an attempt is made to delete from the table. || . RETURN .dd_val . If so. The trigger first makes sure that no one deletes a VRT record that is being referenced by another record type. the database would issue the error message that you can see in Figure 11. END IF .dd_val ' present on ' || data_table || ' table ' . If the record type that is being deleted is not VRT.' || old_data. However.dd_type . this trigger uses the REFERENCING OLD clause to obtain a reference to data on the table. Because the trigger cannot know ahead of time what record type might be deleted. the meat of the trigger is the section that follows. END IF . END IF .dd_type . the dynamically generated statement should work just fine on most RDBMSs. whereas our earlier examples looked at inserts and updates. /* Get dependent column name */ SELECT dd_desc INTO data_column FROM data_dic WHERE dd_type = 'RTC' AND dd_val = old_data. The statement is run using the EXECUTE IMMEDIATE command. /* check for dependencies */ /* Must maintain RTN and RTC records for this to work! */ /* Get dependent table name */ SELECT dd_desc INTO data_table FROM data_dic WHERE dd_type = 'RTN' AND dd_val = old_data. it must dynamically create an SQL statement. /* Run it */ IF data_count > 0 THEN RAISERROR 99999 'Cannot Delete .FROM data_dic WHERE dd_type = old_data. But. the statement generated would check to see if there were any customers whose country was “USA”. I had some problems troubleshooting this trigger to make this dynamic statement generation portable across SQL platforms (test on your own database.2. /* Build and run query */ EXECUTE IMMEDIATE 'SELECT COUNT(*) INTO data_count FROM ' || data_table || ' WHERE ' || data_column || ' = ' || char(39) || old_data. as written. Also. If your application were to delete the USA country code record. IF data_count > 0 THEN RAISERROR 99999 'Cannot Delete Referenced VRT Record!' .

Figure 11. /* Close the cursor */ CLOSE c1 . If the table was large. it must first be declared. Because I had to first determine the existence and values of the RTN and RTC records. .2 showed an application from this book’s CD-ROM that maintains the data dictionary. cust_fname' .Figure 11. END LOOP custloop . as I did in the first trigger example. It is a low-tech solution. none of them portable enough across all the platforms to present here. leaving most of the validation work to the database.2 The trigger on the database prevents the deletion of a country record if existing customers reference that record. the record type is filled into the first column of the new row. data_fname . /* No more records? */ IF err_notfound THEN LEAVE custloop . My original intent was to open a cursor and fetch a single row rather than count all the records. While that worked just fine with Oracle. As a quick note. cust_fname ' || 'FROM customer ORDER BY cust_lname. I found that Transact-SQL insisted that all declarations be at the top of the body of the trigger. the statement would probably yield unacceptable performance.3 shows a new country being added. It performs a count of all the customers from that country. If the user adds a new record. DECLARE err_notfound EXCEPTION FOR SQLSTATE '02000' . I found different ways to work around the issue on different platforms. most of the workarounds that I devised involved calling stored procedures. DECLARE data_fname CHAR (15) . Feel free to expand upon it in your own applications. /* Open the cursor */ OPEN c1 . DECLARE c1 CURSOR FOR 'SELECT cust_lname. to open a cursor. Consult your database documentation for any specific details: DECLARE data_lname CHAR (21) . A generalized example of cursor usage is shown next. the statement generated is not particularly efficient. Unfortunately. Maintaining The Data Dictionary Figure 11. /* loop through it */ LOOP /* Fetch each record */ FETCH NEXT c1 INTO data_lname. The top two textboxes show the current type of records being displayed in the grid control.

Any time a customer record is maintained. I routinely have triggers do such chores as verify ZIP codes whenever customer.3 The Data Dictionary Maintenance application. as well as the old data values. or vendor addresses are maintained. All rights reserved. and type of change performed. Copyright © 1996-2000 EarthWeb Inc. date. . Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Often.Figure 11. Read EarthWeb's privacy statement. for instance. of course). Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. applications require an audit trail or transaction table reflecting who did what to whom. Uses For Triggers Your job as a client/server developer is to place as much processing on the database server as possible (without overrunning it. employee. you might want to have a trigger write out to another table the operator.

We didn’t have such things as auto-incrementing columns then. So. Cust_Lname CHAR (21) . For example. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Generating Primary Keys Every row on the database needs to have a primary key. Normally. Those tables that have more than one column are most often child tables whose key is composed. so we had to do it the old-fashioned way—painfully. I worked on large DB/2 databases with tables whose row counts sometimes numbered into the millions. numeric primary key is most often a matter of assigning numbers sequentially.To access the contents. Users. Although primary keys can be made up of any number of columns and those columns can be any data type. most tables will have a one-column numeric key. click the chapter and section titles. As simple as that sounds. . which were never quite perfect but somehow got the job done. in part. judged five-minute response times to be unacceptable.. Generating a unique. this was a large thorn in my side earlier in my career.. Fortunately. SQL Anywhere uses a convention similar to Access with the AUTOINCREMENT default (in Access. of their parent table(s) key(s). we developed clever little workarounds. AUTOINCREMENT is an actual . The general gist was to perform a SELECT MAX on the primary key column to find the highest used number and add one to it. In the mid-1980s. On the larger tables. the problem is not so bad today. you specify an option at table-create time. you specify the keyword IDENTITY when you define the column: CREATE TABLE CUSTOMER (Cust_No Int IDENTITY. being unreasonable souls. All database vendors provide some way to generate a sequential number for a primary key (or whatever other purpose you deem). this sometimes took several minutes. with Sybase and Microsoft SQL Server.

Because the object is not connected to the Customer table in any way. the INSERT fails. To add a row to the Customer table using the SEQUENCE object. For whatever reason. it uses an independent database object. the equivalent would be shown as: (Cust_No Int IDENTITY (100.. assume that you do an INSERT and the next customer number is 220. If you issue a ROLLBACK. In other words. NEXTVAL is used to get the next available number. waiting to be used. the next number will also be restored. the CURRENTVAL in your database session becomes 220.. 10). SEQUENCE: CREATE SEQUENCE seq_Cust CACHE 200 STARTWITH 100 INCREMENT BY 10 The Oracle SEQUENCE maintains a certain number of new numbers. The Oracle SEQUENCE allows you to specify a starting value as well as an increment value. You can tune the cycling behavior in Oracle by specifying NOCYCLE (do not start all over again when the numbers are used up) and the MAXVALUE or NOMAXVALUE clauses. you have to explicitly reference it. the user will not get 220—that person will get whatever number was generated when he or she invoked NEXTVAL. cycle back to the beginning when all the numbers are used up. The number of items cached is determined by the CACHE qualifier (the default is 15). if you have 50 users adding an average of 1 customer per minute. the database doesn’t know that you are using it to generate customer numbers: . in memory. .. Oracle’s SEQUENCE has two methods: CURRENTVAL and NEXTVAL. . the numbers are created automatically whenever you add a new row to a table. however. If another users makes a reference to CURRENTVAL. Except for Oracle.data type—its underlying data type is LONG): CREATE TABLE CUSTOMER (Cust_No Int DEFAULT AUTOINCREMENT. a cache size of 250 is reasonable. For instance. CURRENTVAL is a reference to the number currently being used in the current database session. The next insert will be number 221 (depending on whether you alter the default increment of 1). if you make a reference to NEXTVAL and get the number 220. Instead. For example. except for Oracle. If there is an error. None of the RDBMSs. With SQL Server and Sybase. Oracle does not have an equivalent facility (to increment a primary key) specifically bound to a column. the number does not get reused. My recommendation is to have enough cache to last about five minutes. Cust_LName CHAR(21)..

. I have periodically stressed the importance of reducing to a minimum the amount of data that is retrieved from the database. . Amazon sends them to you 100 at a time. or if you anticipate that the value of those keys will be very large.INSERT INTO CUSTOMER VALUES (seq_Cust. ord_date. Previous Table of Contents Next . SYSDATE.. If you anticipate generating a very large number of keys. I recommend using a data type of DECIMAL (38) (SQL Server). Think of when you go out to Amazon. Let’s assume that you have a customer maintenance screen.NEXTVAL. This allows for whole numbers with up to 38 digits. or a similar data type. This helps in the performance of the network. The lure of presenting all of those customers in a list box (or similar) so that the user can choose which he or she wants to maintain is enticing to even the most seasoned veteran. the client. telephone number. that the first three columns on the Orders table are ord_no. the most common problem I see in beginning and even intermediate client/server development is the temptation to bring an entire table down from the server to the client. The server doesn’t send you the entire list of 2 million books—you’d probably sue if they did! Instead. say.NEXTVAL. you can simply reference the CURRVAL method of the SEQUENCE. Do the same for your users. of course.) Although this is a bit more work than you have to do with. Result Set Size Through the last several chapters. you want to add an order for that customer. seq_cust. ) The preceding example assumes. Find the ways that users locate customers: last name. NUMERIC (38) (Oracle).com to do some book shopping. and ord_cust_no. SQL Server. Don’t do it! Depending on the size of the records. you enter search criteria... it also offers somewhat more flexibility. I have used the INT data type in my examples so far. If there are more than 100 books that match your search criteria. Nevertheless. don’t bring down more than a few dozen to a few hundred records. Place proper indexes on those columns and then bring back a screenfull or a few screenfulls of records for the users to scroll through. Perhaps the name of your favorite author or a subject area. 'Smith'. For the ord_cust_no field.CURRVAL . or whatever else is natural to your users and your organization. You find the one you want and select it. as shown next: ' seq_ord is an existing sequence INSERT INTO ORDERS VALUES (seq_ord. and the database server. Assume that after you add a new customer.

Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Read EarthWeb's privacy statement.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

Transactions allow you to handle this situation with a little more grace. Managing transactions through your VB program is more work than simply letting the database do it for you implicitly. The term LUW is synonymous with a transaction—a transaction is a logical unit of work.To access the contents. click the chapter and section titles. The customer would get his or her 10 screwdrivers. When you log onto a database server and start updating records. imagine that the two inserts worked but that the inventory update failed. Imagine that your application is adding a new order. It is possible to work outside the scope of explicit transactions. all your work is then committed (made permanent). The customer orders 10 screwdrivers. Normally. you implicitly begin a transaction. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Nature Of Transactions The database measures activity (updates. The data has been corrupted. When you log off. This pseudocode illustrates the correct way to handle the order: BeginTrans Insert new order If insert worked then Insert new line item If insert worked then Update inventory If update worked then . The application generates these changes to the database: • Inserts a new order • Inserts a new line item • Updates the inventory Now. but your inventory would reflect 10 more in stock than there actually are. and inserts) in what are known as LUWs (Logical Units of Work). the transaction is ended. deletes.

CommitTrans Else RollbackTrans End If Else RollbackTrans End If Else RollbackTrans End If By verifying that each action on the database was successful. Assume your application uses pessimistic record locking. it is immediately locked—the lock isn’t released until the record is updated. This is an expensive operation (in terms of resource usage on the computer) and quickly leads to performance degradation. Inasmuch as resources are finite. Ill-behaved applications that don’t quickly release locks on data can lead to a condition known as lock escalation and even another condition known as deadlock. Either way. we have created an all-or-nothing situation. Transactions And Performance While a transaction is active. each user starts a transaction and then gets up to take a coffee break. When your application locks a row. Because each lock requires a certain amount of memory on the server. we ended the transaction (a transaction is always ended with a CommitTrans or RollbackTrans). each maintaining records. We verified that there were no errors and then committed the work. Each time a record is edited. we then rolled back any changes. no other application can access that row. Resources on the server will be quickly overrun. Obviously. Consider an application with 10. the poor not-so-innocent developer. the database will run out of resources and crash. Thus. we want to keep our transactions as short as possible. too many active locks can adversely impact performance when the server runs short of resources. or it will simply start terminating transactions and rolling back changes. you are occupying resources on the server. will be very unpopular. transactions often need to lock rows of data. Recall the term logical unit of work. The two inserts and the update together constitute a unit of work that we have logically grouped together. or it will refuse to allow users to log on. Even worse is the deadlock situation (sometimes called a deadly embrace) where two . Other applications have to wait for your application to release the lock. The beginning and end of a transaction have implications in terms of database performance. You. If it is doing row-level locking. it makes sense that you want to begin and end your transaction as quickly as possible. If you have a few hundred users.000 users. Likewise. One after another. it will attempt to “consolidate” the locks by escalating them. Sooner or later. Depending on how the database does locking. other records on the same data page on the server may also be locked. You may also get into a lock-escalation situation. When the database begins to run short on resources. We started by explicitly beginning a transaction. it may escalate them to page-level locking or even table-level locking. the database may be asked to maintain several hundred or more locks simultaneously. this can adversely impact performance as well. If there was an error.

Locking. If the second update fails. Transactions. we want to undo all changes so that we don’t leave the books out of balance. Application A is locked out until application B releases the lock on the account.processes completely block the other with no hope for resolution. Consider an application that maintains a general ledger. There are two updates. this transaction might look like this: Debit Cash $100 If error then Display error ' Undo any changes Rollback Exit Sub Else Credit Accounts Receivable $100 If error then Display error ' Undo all changes including debit to cash Rollback Exit Sub Else ' Make the changes permanent and end the transaction Commit Work End If End If Again. application B cannot release the lock until application A releases the lock on the customer. An entry is placed to debit Cash for $100 and to credit Accounts Receivable $100. But. And Data Integrity The nature of the transaction is defined by the concept of data integrity. Using pseudocode. as can be seen in the example. Previous Table of Contents Next . (This can be done manually or through a timeout value. Application B is updating Smith’s account (and places a lock on it) and now wants to update Smith. There is the problem of data concurrency.) A facet of transaction management that is even more crucial than performance is the integrity of the data itself. Assume application A first updates Smith (placing a lock on him) and then wants to update his account. The only way to solve this unfortunate situation is for the DBA to terminate one of the transactions. and the transaction is not complete until both updates have been made and verified. But there is more to data integrity than making sure that all records are updated. transactions are an all-or-nothing proposition.

Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved. Read EarthWeb's privacy statement. .

Since the records aren’t locked. At best. The balance record is loaded into that machine’s memory. The balance record is loaded into the second machine’s memory. wait! The ATM that your spouse is using still thinks there is $500 in the account. Concurrency control seeks to solve this problem by somehow notifying a second process trying to update a record that the record has been changed. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Concurrency A few pages back. computes the new balance of $200. and the database is updated to reflect the fact that you are broke. That sounds like a 100 percent rate of return in a single day. Being somewhat more frugal than you. click the chapter and section titles. So. your spouse goes to a second ATM and asks to see the balance. your spouse withdraws only $300. At that moment. The machine says $500. the ATM that your spouse was visiting should have been alerted that the $500 balance was updated by another user. you started the day with $500. That ATM also reports a $500 balance. neither machine is aware of the other. is to use optimistic locking—where the rows aren’t locked until they are actually being updated. of course. Assuming your bankcard doesn’t get eaten. In other words. The record in the first machine now reflects the new balance of $0 (about what I am used to). just as premature locking is bad for performance (don’t they make a drug for that problem now?). it should then have not given out . But. However. You press a lot of keys and swear a little bit. but it’s not too good for the bank. withdrew $800. I discussed the problems of lock escalations with the use of pessimistic locking.To access the contents. it is great for data integrity. the machine gives you $500. The answer. and updates the bank record. That’s not too bad for a struggling VB developer. Consider the following scenario: You go to a bank machine (ATM) and look up your checking balance. The ATM dutifully deducts $300 from $500. and still have $200 left.

Obviously. which negatively impacts performance at the client.0 performs dynamic row-level locking. not all databases are created equally. transaction-oriented environment. if the nature of the updates is that they are random (occurring all over the table instead of being concentrated in just a few pages) or if the transaction volume is not that high. the locking level could be an issue. SQL Server 7. I showed you how you can be notified if a record that has been retrieved from the database has since been altered. then. For some. This notice to a transaction that the underlying data has changed can also impact—you guessed it—performance. when you lock a row on a Sybase database. performs what is known as row-level locking whereas Sybase performs page-level locking. Microsoft SQL Server 6. server. On the other hand. I used some examples of transaction management and concurrency handling in illustrating the use of DAO. the chance of another application being locked out is 20 times greater than if only one row is being locked.) Oracle. the nature of the locking mechanism might not be that critical. • Ensure that consistency of data is maintained. By definition. In a very high-volume. RDBMSs And Row Locking When it comes to record locking. which is to say that it uses an algorithm to determine whether to lock an individual row only or also the rows before and after. by appropriate record locking and update query tuning. you might be better off with the former. When you lock a row on an Oracle database. Of more importance might be the duration of the transaction. and network levels. 6. In Chapters 5.any money.0 performed page-level locking. At worst. it might not even matter. The overall goals are: • Ensure that all related updates of the database are handled as an integrated whole. to automate the process of determining whether the underlying record has been changed involves frequent communication with the database server. If a page-level locking database takes 1/100 of a second to update a row and a row-level locking database takes 1/10 of a second to update a row. if a database locks 20 rows in addition to the one being updated.5 performed pseudo-row-level locking. every other row on the same page of data is also locked. whereby the row immediately before and after the row to be updated was also locked. Version 6. RDO. If a record is small. all of these issues—database resources and concurrency handling—are part of the overall issue of transaction management. only that row is locked. . You accomplish these goals by ensuring that your transaction is both complete and of as short a duration as possible. On the other hand. and ADO. (Databases organize rows into pages. a page might contain many rows. it should at least have computed a balance of negative $300. and 7. As one might speculate.

. For an application with a small number of users. adLockReadOnly. Copyright © 1996-2000 EarthWeb Inc. Pessimistic Locking Is the glass half-full or half-empty? Pessimistic locking implies preparing for the worst in terms of ensuring that the underlying data does not change unexpectedly. or adLockBatchOptimistic. All rights reserved. rendering the issue of locking level moot. The locking itself is set with the LockType property. adLockOptimistic. how to determine if the underlying data has changed. you will be able to safely detect and accommodate the change. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. then the issues that face you are whether to perform batch processing. Read EarthWeb's privacy statement. Use adLockPessimistic. Assuming that you are going to use an optimistic locking model. Because the database is ultimately used to do locking. or that if they do. Optimistic locking takes the view that either no one will change the underlying data. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. is not truly a database lock—it merely means that the record set is not updateable. and what to do about it if data has changed. you are pretty much guaranteeing a poor performance model. For a larger application. It locks a record as soon as it is edited and does not release the lock until the record has been updated. The safest—and easiest—tactic is to simply perform pessimistic locking. The default. pessimistic locking is not available unless you use a server-side cursor model (CursorLocation = adUseServer). this may well suffice.Optimistic Vs.

Examine the Errors collection to determine if there was a problem. use the UpdateBatch method of the record set.UpdateBatch adAffectAll Next. To update records in batch mode. click the chapter and section titles. records whose underlying data has changed. because you are waiting before sending updates to the server (instead of sending them as soon as changes are made)." arsEmp. even those that do not meet the current Filter criteria. the update is performed. The disadvantage is that. The MarshallOptions property is used to send only modified records back (this really only has implications when communicating with a middle tier or perhaps a Web server). Use the Filter and Status properties (as I showed you in Chapter 7) to find any records with conflicts—that is. The adAffectAll argument specifies that all records. I also show the value of the field as it . The Filter property is set to only “see” those records for which there was a conflict.MarshallOptions = adMarshallModifiedOnly arsEmp. You can iterate through the Fields collection of a record set to see exactly what values changed.Filter = adFilterPendingRecords MsgBox "There are " & arsEmp. I iterate through the Fields collection of each one comparing the UnderlyingValue property (that is. should be updated to the database: arsEmp. the value of the field as it currently exists on the database) to the OriginalValue field (the value of the field when it was retrieved from the database).To access the contents. there is a higher possibility of the underlying data being changed. The following example shows the UpdateBatch method being used to send all cached changes to the database. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The advantage of batch processing is that it lessens the workload on the server and ultimately reduces network traffic because there are less roundtrip communications between server and client. The Filter property is then set to show an example of how to determine how many changes are pending. Next.Recordcount & _ " changes pending.Filter = adFilterNone arsEmp. I will show you how to iterate through all records for which there were conflicts and determine what fields on the underlying records were changed.

and Bill’s job title. This may be incompatible with some approaches to batch updating. you changed Cindy’s job title to Manager and changed John’s manager to be Cindy. Transactions seek to group mutually depending database updates into a single unit of work so that. If all the updates succeed.MoveNext Loop End With TIP Dirty Data You will occasionally run into database theory texts that talk about data being dirty or clean. Assume that the . you might have to adopt a different strategy.UnderlyingValue End If Next . the answer is probably no. If. When a record has Field objects with UnderlyingValue properties that are different than their OriginalValue properties. if they don’t.MoveFirst Do Until .Filter = adFilterConflictingRecords .Fields If vField. fine.EOF For Each vField in . But. Records added since the record set was created will not be reflected.OriginalValue <> vField. updating various employees on the database. dirty data is data held in memory that no longer reflects what is actually stored on the database. and you will want to think through the consequences of your choices. You change John’s home address. if one fails. perhaps. Consider that you are. then an error is generated." & vbcr & _ "Field: " & vField.Name & vbcr & _ "Value when retrieved: " & _ vField.exists in the database (because your application might have changed it as well): Dim vField As Field With arsEmp . Cindy’s salary. on the other hand. the data is said to be dirty. So.UnderlyingValue Then MsgBox "Conflict Detected. You can quickly set the record set to reflect all changes made using the Resync method. they all fail. All jokes aside (and many come to mind).OriginalValue & vbcr & _ "Current Value: " & vField.Value & vbcr & _ "Changed Value: " & vField. If a record has been deleted. This is not the same as re-executing the command that created the record set. you probably want to Commit the changes to the database even though not all were successful. The field values will be updated to reflect changes made only to those records already in the record set. Transaction Scope And Batch Updating There is a basic dichotomy between the goals of batch updating and transaction management. You then issue an UpdateBatch method. should you perform a Rollback? Is Cindy’s salary in any way connected to John’s home address? Generally.

I would also perform an UpdateBatch whenever activity to any given order is complete. Ain’t life grand? The reason I discuss this is to point out how carefully you will want to consider whether or not to use batch updates. because you now have John assigned to a manager who doesn’t exist. you might lose any efficiencies that the batch processing was supposed to provide. such as Orders and Line_Item. they may not really constitute a logical unit of work. When To Use Batch Updating My advice is to use batch updating mainly when the underlying database is not likely to cause dirty data problems. you increase the likelihood of conflicts when you go to perform your batch update. In other words. in fact. . then you might want to use batch updating on it as well as a convenience to logically group together the updates to Orders and Line_Item. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. they tend to cluster together as a transaction when. This can cause aggravation for both you and your users. don’t batch together updates against multiple orders. Copyright © 1996-2000 EarthWeb Inc. As you can see. However. All rights reserved. Dirty Data And Batch Updating Another reason to pause before making a decision to perform batch updating is the likelihood of dirty data. If the underlying database has a lot of activity against it. You do not want that change to be made permanent. if the application ends up spending time dealing with the record conflicts.update to Cindy failed but the update to John succeeded. Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. If you have a record set that maintains related tables. and.

I don’t make that stuff up. then the update would fail. They had three categories of dead: Possibly Dead.000 to $55. and server have to work harder. a member called complaining that he had been declared “Confirmed Dead” and he vigorously protested the classification.000: • Primary key—In RDO. . national professional organization who shall remain nameless to prevent lawsuits. • Updated columns—In RDO.000 to $50.000. if another user changed the employee’s status to “DEAD”.To access the contents. because the generated update statements are so long. the client. This method detects any collision between changes you have made and changes that another user has made. you use the UpdateCriteria property (see Chapter 6). While there. if another user had changed the salary from $40. In RDO. network. based on the nature of what was changed. concurrency management. No. However. the update will fail. However. click the chapter and section titles. In other words.) UPDATE employee SET emp_salary = 50000 WHERE emp_no = 100 AND emp_salary = 40000 • All columns—This option is the safest of all. There are several ways to format the WHERE clause in an update. This is the loosest control in that it will not cause any conflicts to be detected unless the original record itself was actually deleted. UPDATE employee SET emp_salary = 50000 WHERE emp_no = 100. Reported Dead. You can then determine. ultimately. this is the rdKey option (UpdateCriteria = rdKey). this is the rdKeyAndModified option. (I consulted for a large. whether to force the update anyway. and Confirmed Dead. because it guarantees that if any change has been made to the underlying database. the change would still succeed. Assume that you have changed employee 100’s salary from $40. The nature of your data dictates whether that is okay. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- How Does ADO Handle Concurrency? When Is Concurrency Violated? DAO and RDO allow you to fine-tune your SQL WHERE clause on updates so that you have control over conflict detection and.

.: Enterprise Database Connectivity. Where To Go From Here In this chapter. All SQL activities are written to the log file that you specify. Previous Table of Contents Next . N. For SQL Server development. is just as safe as all columns because the row’s timestamp column is modified any time the row is modified. Wiley & Sons 1993. Note that this places a tremendous burden on the ODBC manager. and select the ODBC Administrator applet. • Primary key and timestamp—This option. I also like Bill Vaughn’s VB/SQL Server tome (Vaughn. rdKeyAndTimestamp in RDO. Select the Tracing tab. Thus. ISBN: 0-47157-802-9 While neither is Visual Basic or RDBMS specific. Chapter 6 for RDO. and Chapter 7 for ADO.: Hitchhiker’s Guide To Visual Basic & SQL Server. William R. I have the fifth edition. to you. It requires that a TIMESTAMP column be defined for the table and that the column be included in the result set.UPDATE employee SET emp_salary = 50000 WHERE emp_no = 100 AND emp_lname = 'Brown' AND emp_fname = 'Barbara' AND . I have introduced and refined various intermediate to advanced database subjects. Unfortunately. so you should use this option only when needed. and select the Start Tracing Now button. Perhaps the capability to tune the WHERE clause will be added in a future release of ADO. refer to Chapter 5 for DAO. which you can then open in WordPad. When done. but an updated edition should be available by the time you read this. Richard D. 7. ISBN: 1-57231-567-9). Microsoft has not yet built into ADO similar WHERE clause tuning techniques. each discusses strategies and concepts in the enterprise client/server model. 1997.. ISBN: 1-55860-190-2 • Hackathorn. Morgan Kaufmann Publishers 1993. and Andreas Reuter: Transaction Processing: Concepts and Techniques.5. For details of specific syntax. I also attempted to recap discussions of transaction management and concurrency handling procedures discussed in Chapters 5.. I highly recommend learning and using stored procedures and triggers as a matter of course rather than relying on client-side code. Go to the Control Panel. To detect concurrency problems. concurrency is said to be violated under ADO when any underlying value has changed—even if. 9. select Stop Tracing Now. Microsoft Press. but it is much less resource intensive. it is not important. TIP To See The ADO Statements Generated You can observe the statements that ADO sends to an ODBC data provider by turning on the SQL Trace facilities. it uses all columns in the WHERE clause. which is current through Visual Basic 5 and SQL Server 6. and 10. UPDATE employee SET emp_salary = 50000 WHERE emp_no = 100 AND emp_timestamp = . J.. A couple of texts that I like that you may want to consider are: • Gray. 6. You will want to pick up a text that is specific to your RDBMS.

All rights reserved. Copyright © 1996-2000 EarthWeb Inc. . Read EarthWeb's privacy statement. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Part III Visual Basic 6 And The Internet Chapter 12 The ABCs Of XML Key Topics: • Regaining context with XML • Understanding the XML ActiveX control • Describing your documents with DTDs • Building XML applications The Extensible Markup Language (XML) has gone from being one of thousands of fairly obscure acronyms to one of the hot test uses of the letter X outside of Sculley and Mulder’s paranoia. Blocks of text were contained within paragraph tags. it’s important to know that HTML was originally designed as a contextual scheme for classifying documents. with each paragraph serving a distinct unit of thought. A lot of this has to do with the realization by companies such as Microsoft that one of the biggest problems with information transfer today comes from the difficulty in specifying context. and <EM> the emphasis within text. you could . <H1> was the primary header. Regaining Context With XML To understand why specifying context is a problem. click the chapter and section titles. In theory.To access the contents. <H2> the secondary.

One or two such tags were probably fairly harmless.understand the context of the page by sticking to the notion that a tag’s appearance was less important than its meaning. this is mind-boggling because it makes the presentation of data highly fluid. which is more a coding convention than a language per se. Designers became far more interested in the markup aspect of HTML. other tags such as <FONT> appeared. Web developers aren’t going to be out of a job any time soon). you can use Dynamic HTML (DHTML) behaviors to display data in forms as diverse as a table and a pie chart by simply switching the descriptor for a given element. although it is certainly possible to use traditional database methods to output structured data. Indeed. but the data format can be read universally. Web developers can provide a context upon which to hang the presentation layer while simultaneously creating a data format that is completely portable because it carries its context within itself. this concept became immaterial once people wanted to do more with Web pages than display articles about quantum effects within high-energy particle collisions. Of course. Because a network with billions of documents that contain little-to-no contextual information will eventually become impenetrable. This portability is one of the reasons that an XML-based “world” makes so much sense: As long as your XML document is properly formed. such calls are fairly expensive to make frequently. such as the egregious <BLINK>. a structure more reminiscent of programming classes than SQL output. A <BLINK> tag contains no contextual information (save perhaps that the designer is a twit). Web developers invented all kinds of tags for pulling off specialized functions. then the same data can be shown in a wide variety of formats. By adopting XML. Style sheets separate the presentation layer from the data in a document. you might need to wrap the XML parser’s API set in containing classes for a more complex application (hey. an approach that is consistent with a completely text-based browser such as Lynx. Internet Explorer 5 takes this notion literally: Beyond just changing the color of an element. To be sure. Because any header tag could be replaced with a properly designed FONT tag. the W3C has worked to create two complementary technologies—Cascading Style Sheets (CSS) for presentation and XML for page context. This feature becomes crucial for applications that may not necessarily be connected to a server at all times and can even be facilitated by utilities that convert SQL record sets into XML code for offline storage on a client’s machine. Anyone who’s ever had to display a data form in Visual Basic in more than one mode can appreciate how difficult that is to do with traditional development tools. and they are even more . If you can create a structure for representing the data that is separate from how that information is displayed. In and of itself. as the data layer. but as the faint call for a more graphically oriented page turned into a roar. any XML parser can read it. As the browser wars heated up. A second advantage in using XML comes from the rich structure that such a document can contain. the underlying structure and meaning of a given page disappeared into a sea of FONT tags. An XML document is hierarchical. with some interesting consequences.

Copyright © 1996-2000 EarthWeb Inc. This is the approach that I take in this chapter. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. All rights reserved. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.difficult to update. . With XML. the process is much easier—so easy in fact that it is often more convenient to keep data in an XML object than attempt to map it to external classes for processing. Read EarthWeb's privacy statement.

</CITY> </STATE> <STATE ID ="Washington"> <CITY ID ="Seattle"> <SKIES VALUE="RAIN"/> . but for most of the uses where Visual Basic programmers or Web developers need XML. </CITY> <CITY ID ="Sacramento"> <SKIES VALUE="SUNNY"/> <HI C="36" F="97"/> <LOW C="13" F="64"/> Sunny and hot. <?xml version="1. and you are dreading the need to learn dozens if not hundreds of new tags. the syntax is straightforward. put your mind at ease. The example in Listing 12.A basic weather report for select West Coast locations --> <WEATHERREPORT> <STATE NAME="California"> <CITY ID ="Los Angeles"> <SKIES VALUE="PARTLYSUNNY"/> <HI C="31" F="87"/> <LOW C="18" F="65"/> Partly cloudy. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Structuring XML If you are contemplating moving to XML from HTML.1 An XML weather report.To access the contents. XML is just a convention for writing out data. The only tags that you need to learn are those you create yourself. The reason is simple: For the most part.0"?> <!-. and it structurally resembles HTML quite closely. Like its antecedent SGML. XML can get fairly complex. and attributes. Listing 12. click the chapter and section titles.1 provides most of the features of a “simple” XML file. terms.

0"?> identifies the document as an XML document through the preprocessor tag <?. </CITY> <CITY ID="Redmond"> <SKIES VALUE="RAIN"/> <HI C="10" F="50"/> <LOW C="5" F="41"/> Rain.This is an <!-. In more sophisticated XML documents. follow the rules of XML) without being valid. it can be used to store data. especially with respect to Microsoft’s parsers. this tag may also provide a link to a Document Type Definition. </CITY> </STATE> </WEATHERREPORT> In Listing 12. If this format isn’t explicitly defined. the document can be well formed (that is. mixed with showers. comments should be an integral part of any page. it is not possible to nest comments in XML.<HI C="12" F="54"/> <LOW C="9" F="49"/> Raining on and off throughout the day.. the closing comment tag of any interior comment will terminate the comment body in its entirety. actually works on the assumption that there is no explicit definition of the data.1. As in HTML. Much of the use of XML as a data-storage mechanism.embedded --> comment --> will fail to parse properly. . the statement <!-. describing structures. As with HTML. </CITY> <CITY ID ="Olympia"> <SKIES VALUE="CLOUDY"/> <HI C="11" F="49"/> <LOW C="8" F="47"/> 30% chance of rain toward evening. In other words. as long as the document follows the rules of XML.This is a comment --> Comments can extend across multiple lines because XML structures ignore white space in much the same way that HTML structures do. However. the first line. and anything else that will help other people understand what you intended to do with your XML document. <?xml version="1. the syntax for XML comments is straightforward: <!-. DTDs will be covered in much greater depth in the section “Describing Your Data: The DTD” later in this chapter.?>. NOTE The preprocessor tags give information to the parser concerning the document’s validity—whether the XML structure contained therein obeys a predefined format.. specialized variables. an external file that makes the structure in an XML document more explicit.

LOW. An attribute helps define a node more clearly in exactly the same way that attributes in HTML clarify the role of the tag. For example. One useful way of thinking about this structure is to associate each leaf with a property and each branch with either a class or a collection of classes. An HTML example illustrates this. Figure 12. the dimensions of the image (HEIGHT=“120” WEIGHT=“90”). the Olympia.) These nodes may contain other branches or. in Listing 12. and some associated text. CITY. a branch off the main trunk. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Copyright © 1996-2000 EarthWeb Inc. the Washington node corresponds to the STATE class. In all but the simplest XML documents (that is. but in the data structure displayed in the figure. An XML document likewise has a single containing tag. The leaf nodes terminate the tree at that point. a HI and LOW property. In a traditional text document.com/images/mypic.”). Each State in turn contains one or more City nodes. although there are no restrictions about what you call it.1 can actually be useful in getting a better handle on XML data structures. it is one of the things that makes XML such a promising technology.1. Read EarthWeb's privacy statement. Washington. and even what events the element supports (ONMOUSEOVER=“HiliteMe(). All rights reserved. The image tag (<IMG>) typically comes with several attributes that define the name or identifier for the image (ID=“myPic”). For example.In a typical HTML document. This relationship between classes and XML nodes is hardly accidental. node has a SKIES property.mysite. and indeed. The Olympia node corresponds to the CITY class. the Washington State node contains the City nodes corresponding to Seattle. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. the child nodes correspond to major headers. and there is never more than one such element per document. each child of Weather Report is a State node. . These tags acts as a container for everything else within the document. there may be one or more attributes. Olympia. in much the same way that the foundation of a tree (or a family tree) is its root. the root node has a collection of child nodes. as in this case.jpg”). This family tree metaphor in Figure 12.1 The weather report XML data structure resembles a family tree. leaf nodes. The outermost element in an XML document is usually referred to as the root element or node. in addition to the tag name for that node (such as STATE. one that has only a root). a given node cannot simultaneously be both branch and leaf. and so on). and the whole document is in turn a collection of STATE classes. Within each node. the entire page is contained within the <HTML> </HTML> tags. (For example. the document container is the <WEATHERREPORT> tag. the source URL of the image (SRC=“http://www. and Redmond.

none are strictly required. The one primary difference in structure between XML and HTML concerns strictness. click the chapter and section titles. it’s worth looking at the corresponding <IMG> tag in HTML. or if you attempt to put a closing tag after a self-terminating tag. XML closes its tags exactly the same way that HTML does: <TAG> is terminated with </TAG>. or none at all. any given tag must have a closing tag. the parser will fail. for example. although if a formal DTD is provided with a given XML document. (It is possible to specify different formats with the appropriate parser. and attributes such as BORDER may appear comparatively rarely. points to the location of a graphical file to be used for the image. except that you can define what attributes are associated with a given tag. such as the one in the following code snippet. An element doesn’t need any given attribute.To access the contents. the HI and LOW tags have two attributes each—the C for Celsius and F for Fahrenheit. a tag doesn’t need any specific attributes defined. Thus. Additionally. such attributes as WIDTH and HEIGHT may or may not be provided. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- An XML tag is not that different. In the simplest form of XML documents. dozens. although <IMG> usually contains a SRC attribute. and although some attributes are more convenient (for example. NOTE If you have an opening tag with no closing tag within your XML document. but this falls beyond the scope of this book. An XML tag likewise could have one attribute. The SRC attribute of an <IMG> tag. Here again. an attribute serves to define a characteristic of a tag or provides a link to additional data about the tag.) As a general rule of thumb. Although most contemporary HTML authoring programs are moving toward . an ID tag is extremely useful in an XML document). it is possible to have default values for given attributes. and any other tag defined between an opening and closing tag must also be closed between the two. In other words. all attributes’ values are given as strings. XML treats every element as a container.

jpg”></IMG>. The text for <WARNING>. one stresses XML as a document markup language. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. and the other sees XML as a convenient database format. This in turn means that any XML element has a text property that consists of all the text of its subnodes. is “This is a test. so you don’t have to include the end tag. Copyright © 1996-2000 EarthWeb Inc. However. because many nodes in an XML structure don’t have text associated with them. this is only a test.1: <SKIES VALUE="RAIN"/> Text is treated in a slightly different way by XML than it is by HTML. . Because you can use XML to describe documents. An advantage of this is that a browser that doesn’t support an XML parser can still output the text of the document. the expression <WARNING>This is a <HILITE>test</HILITE>. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the <IMG> tag in HTML is typically treated as a single element with no closing tag. Read EarthWeb's privacy statement.</INTERNAL_TEXT> </WARNING> where <INTERNAL_TEXT> is a node that contains default text for the document. XML writes the same tag as <IMG SRC=“mydata.</WARNING> is actually broken up internally as <WARNING> <INTERNAL_TEXT>This is a </INTERNAL_TEXT> <HILITE>test</HILITE> <INTERNAL_TEXT>. with the terminating slash moved to the end. All rights reserved. In this case.XML-like code. this is only a test.” whereas the text for <HILITE> is just “test”. HTML does include certain elements that are invalid in XML. the text in each block is actually treated by the parser as belonging to distinct nodes. it is perfectly possible to have a block of text with embedded XML elements. For example. You can see an example of this in Listing 12. although it loses any relevant formatting. XML also includes a shorthand notation. For example. XML supporters tend to fall into two camps. for example. <IMG/>. this is only a test.

Record the name of the element as its tag name. another child is defined for the parent node). 4. Let this process continue until all nodes have been added into this structure. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Parsing XML I’ve bandied about the term “parsing” throughout the last section without really defining it. If the next tag found is not a closing tag. but . backtracks down a branch. to get information about the document not contained within the XML tree itself. 5. Read the prolog. click the chapter and section titles. this means that the parser program performs the following steps: 1. Read the first tagged element of the XML structure. In short. the node is defined. For this tag. Like many computer expressions. 6.To access the contents. 3. the parent node is also closed) or a new node (in which case. jump to Step 3. and repeats the process until all leaves are hit (see Figure 12. Move to the following node and determine whether it is a closing node (in which case. more specifically. Programming this process is perhaps not as immediately obvious as iterating through a linear list. If the next tag found is a closing tag. read the next tag and define it as a child of the current node. An XML parser is usually built as a recursive descent parser. 2. “to parse” has a wide variety of meanings depending on the context.” I should explain that mouthful in simpler English. adds all the leaves for a given branch. In essence. going up a branch until it hits a leaf.2). the parser walks a tree. or preprocessor instructions. For XML parsers. to parse means “to import the document into a dynamic data structure that can be traversed recursively. Read through the rest of the element to determine which properties the given node supports and then assign these into attribute-value pairs.

0 API in depth as they are referenced from Visual Basic. Internet Explorer 5. you can make a compelling argument that IE5 isn’t an HTML browser at all. Fortunately. XML appears all over the place in IE5: • XML can extend the presentation markup in the HTML document stream. although supporting all the features of XML 1. • XML can be embedded within HTML documents as data stores or referenced via external files. and property information in XML format. saves and retrieves session. but which has only limited utility in Visual Basic. but rather an XML browser that can coincidentally parse HTML as well. and Microsoft also supports a Java-based parser. walks up each branch until it reaches a leaf. which can be useful in Web pages outside of Microsoft’s Internet Explorer. you should go the former route. quite powerful. Microsoft has been a prime mover to get XML into the marketplace.0 adds considerably to the amount of work involved. • XML forms the foundation of dynamic properties and behaviors.0 because it has applications both in DHTML and Visual Basic. • The Client Capabilities. moves to the next leaf. Writing a simple XML parser is not a terribly complicated undertaking. Internet Explorer 4. Because it’s worth understanding how the library objects work on their own before incorporating XML into DHTML applications.2 The parser starts at the root node. form. Figure 12. as I discuss in detail in the next section. NOTE: To directly manipulate XML documents. the next several sections discuss the Microsoft XML parser 2. Each offers benefits and drawbacks.0 makes extensive use of XML. Visual Basic programmers can access and manipulate XML data either by using the IE5 Document Object Model (frequently referenced as the DOM) or by using the Microsoft XML library. and more than a little counterintuitive. The MS XML library is fairly extensive. and it has built a number of reasonably powerful XML parsers that automate the process of reading and traversing XML documents.0 includes a more primitive C++-based XML parser that must be included as an ActiveX control.programming recursive walks is not all that much harder either. This subject is covered in some detail in Chapter 14. Indeed. you should use the XML library. you need to include the XML . This book concentrates on the XML parser that is part of Internet Explorer 5. if you are working with an HTML document with embedded XML. whereas if you want to deal purely with XML files. and then backtracks to the last branch and takes the other fork. IE5’s successor to cookies. although in general. Because of the pervasiveness of XML in Internet Explorer 5.

Read EarthWeb's privacy statement. IDOMNodes. select References from the VB project menu. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. there are only a handful of objects to worry about in the library—the DOMDocument. IDOMNodeLists. Leveraging The MS XML API Any time you deal with database structures. . Copyright © 1996-2000 EarthWeb Inc. Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. the improvements from earlier versions are noticeable.0 of the Microsoft XML parser. All rights reserved. The XML API is much like that.0 (MSXML. version 2. and yet never quite as complete as you’d like.library in your Visual Basic project. but you still need to put some effort into getting anything useful out of them. not a 2. Still. Find and check Microsoft XML. you’re going to find the API to be complex. To do this.0 version of XML itself.DLL) to add it to the associated references and then press OK. and IDOMError classes. sometimes cumbersome. Note that this is version 2.

the DOMDocument acts as the primary interface to the XML library.To access the contents. Note here that there’s no specific mention of XML in any of the class names—yet another indication that Microsoft sees XML as the foundation of HTML development in the future. and even determine when things have gone wrong. refers to the Document Object Model. you can load and save XML documents. Table 12. or relocate nodes within the tree. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- The Documents Of DOM DOM. The methods and properties of the DOMDocument are summarized in Tables 12. Of all the classes. click the chapter and section titles. navigate to specific nodes in the XML tree. with detailed descriptions following.2.1 and 12. remove.1 Methods of the DOMDocument object. of course. add. Method Name Description Abort CreateNode GetAttribute GetTypedAttribute InsertNode Load LoadXML NodeFromID RemoveAttribute RemoveNode Aborts an asynchronous download Creates a new node Retrieves a root node’s attribute by name Retrieves a root node’s attribute as a typed value Positions a node into the tree Loads an XML document from a file Loads an XML document from a string Retrieves a node with the given ID Removes an attribute from the node Removes the node from the XML tree . the term that Microsoft has applied to the architecture of Internet Explorer 5 pages. From this class.

then Async is true A list of attributes within a given IDOMNodeList node IDOMNodeList A collection of the children of the current node Variant The data type of the node IDOMNode The definition of the node within the DTD or schema DocumentNameSpaces IDOMNodeList A collection of namespaces for the document DocumentNode IDOMNode The document’s root node DocumentType IDOMNode Information from the prolog’s !DOCTYPE node LastError IDOMError The last error that occurred NameSpace NodeName NodeType IDOMNode The definition for the namespace on the node String The name of the node’s tag XMLNodeType The type of node (text. Property Name Type Description Async Attributes ChildNodes DataType Definition Boolean If XML file can load asynchronously. processing instruction (PI).ReplaceNode SaveNode SetAttribute SetTypedAttribute Replaces one node with another Returns an XML string of the current document Sets the value of a named attribute to a string Sets the value of a named attribute to a specific type Table 12. node. and so on) The value of a node. as a typed Variant constant String The value or text of a node IDOMNode The node to which the current node belongs String Returns the name of the node without its namespace qualifier Gets the load state of the XML Long document Boolean Indicates whether a definition exists for the node in the DTD The read-only URL of the XML String document NodeTypedValue NodeValue ParentNode QualifiedNodeName ReadyState Specified URL . comment.2 Properties of the DOMDocument. prolog.

. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited.Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Read EarthWeb's privacy statement. All rights reserved.

2 prompts the user for an XML file to load and then loads it.Filename = "*. prompt for one If Filename = "" Then With Screen. you need to load it into the data structure. Listing 12. Listing 12.ActiveForm. generating an error if the document couldn’t load properly.DialogTitle = "Select an XML File to Load" On Error GoTo CancelLoad . The DOMDocument provides three ways to do this: loading the document from a file.2 The LoadXMLFile function returns an instance of the DOMDocument. ' Declare a public variable in form or module ' to hold XML structure Public DOMDoc as DOMDocument Public Function LoadXMLFile(Optional Filename As String) _ As DOMDocument Dim CurReason As String Set LoadXMLFile = Nothing ' If no filename is supplied. or converting a string into a document.CancelError = True .xml)|*. loading the document asynchronously from a URL.CommonDialog1 .Filter = "XML Files (*. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Loading A Document Before you can work with an XML document. Of the three.ShowOpen On Error GoTo 0 Filename = . click the chapter and section titles.Filename End With .To access the contents.xml" . loading a document from a file is far and away the easiest.xml" .

Option Explicit Public DOMDoc As DOMDocument Public Node As IDOMNode Public NodeList As IDOMNodeList . as long as a reference to the active form can be obtained. The advantage is that you can make your code much more portable. In today’s wired world. it is just as likely that the source of your file will come from the Internet as it will from a local directory. it doesn’t raise any events. sometimes you will want to download the file asynchronously. Listing 12. making it necessary to set up a timer or make a SetTimer API call to determine whether the document is done loading. Especially if you are creating XML structures by hand. Reason:" _ + XMLDoc. The code in Listing 12. which contains the full XML structure. it is loaded into the parser. Although XML files are usually fairly compact.3 Loading an XML file asynchronously.reason <> "" Then MsgBox "XML Document unable to load. you will be able to create the required control. The LastError property will retrieve a description of the last error that occurred.End If ' Initialize the document object Set XMLDoc = New DOMDocument ' Load the document. As a consequence.3 demonstrates one way of making an asynchronous load.lastError. LastError is an IDOMError class that is covered later in this chapter. (Indeed.reason Else Set LoadXMLFile = XMLDoc End If Exit Function CancelLoad: On Error GoTo 0 End Function The LoadXMLFile function calls upon the Common Dialog box to show an open box. it conforms to XML logic—then an instance of the new DOMDocument is returned. Although the DOMDocument object does support this. an XML document with thousands (or even tens of thousands) of nodes is not altogether rare. If the XML file is well formed—that is. Visual Basic 6 also includes a new capability that lets you add a control to a form at design time—without putting a base control on the form first. You should place this code within a form because it relies on the form as a container for the timer. most of the code in the function is involved in setting up the dialog. it can be notoriously difficult to get an XML document to parse. ' Load Syntax: Sub load(bstrUrl As String) XMLDoc.lastError. On the other hand.) When an XML file is located.Load Filename ' Check to see if error occurred ("" indicates no error) If XMLDoc. including the exact location of the error in the XML file that the parser aborted.

xml") End Sub The code involving the DOMDocument object is not all that different from the initial call. Do you wish to" & _ "continue?".Name dtCount = 0 End If End If End If End Sub Public Sub AsynchXMLLoad(URL As String) Static Ct As Integer Set DownloadTimer = Me.Enabled = True DOMDoc.Remove DownloadTimer.Name dtCount = 0 If DOMDoc. vbYesNo) If Response = vbNo Then DownloadTimer.reason <> "" Then MsgBox (DOMDoc.Load (URL) End Sub Private Sub Form_Load() Set DOMDoc = New DOMDocument AsynchXMLLoad ("c:\bin\EmbeddedXML.lastError.Enabled = False Me.Controls. which indicates that the DOMDoc can continue loading in the background while .lastError.Remove DownloadTimer.Controls.Add("VB. DownloadTimer.Timer".Controls.reason) Exit Sub End If Else If dtCount Mod 20 = 0 Then Response = MsgBox("Load is taking longer" & _ "than expected. to perform an asynchronous load. you need to set the Async property of the object to true.async = True DOMDoc.Interval = 1000 DownloadTimer.readyState = 4 Then ' A readystate of 4 indicates that the download ' is done or it failed.Public WithEvents DownloadTimer As Timer Private Sub DownloadTimer_Timer() Static dtCount As Integer Dim Response As Integer dtCount = dtCount + 1 If DOMDoc. _ "CTimer" + CStr(Ct)) Ct = Ct + 1 DownloadTimer.Enabled = False Me.

To do this. This is a new feature of Visual Basic 6. the download has either completed or has raised an error that can be checked. you need to check the readyState property of the DOMDocument. To ascertain whether either of these two states has occurred. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. . the Controls collection now supports two new methods: add and remove: Function add(ControlIdentifier as String. it makes more sense to create it when needed and then destroy it when the task is handled. Until the download is complete. Read EarthWeb's privacy statement. All rights reserved. in earlier versions of VB. This is exactly the same property as the readyState associated with the Internet Explorer browser upon downloads. When this property is set to 4. _ ControlName as String. Because the only reason to have the timer in place is to help handle downloads. the program checks a timer that has been added at runtime. Setting Async to false forces the program to halt until the file is completely downloaded or an error occurs. Copyright © 1996-2000 EarthWeb Inc.other activities take place. you would specifically have to create the timer at runtime. _ Optional Container as Object) as Object Sub remove(ControlName as string) Previous Table of Contents Next Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions.

it will continue until either the file does finish or 20 seconds have passed. such as <B><I>This is a test</B></I>. is the form or other container that owns the control. Other than the extended code involved in querying the download. However.Work-Book” or “VB. but it actually comes from necessity. The user is then prompted about whether he or she wants to extend the download period or terminate the file retrieval. Loading from a string is just about as straightforward. you are the one defining that structure. displaying an error message if the file wasn’t found or failed to parse. If you inadvertently switch the order of closing format tags. this can come as a bit of a shock. For people accustomed to the fairly generous ways that most browsers accept bad HTML. although it is covered in Chapter 14. The parser knows only the rules that XML provides and can’t second-guess the creator of . In Listing 12. the program intercepts the event when the timer does fire and calls the DownloadTimer_Timer() event handler. If the file is still downloading.To access the contents. ControlName is the Name property of the new control. the browser’s parser knows enough to switch them back internally. click the chapter and section titles.2. This in turn checks to see if the file has finished downloading. and then set to fire once a second. which is optional.ClassID. In both cases.Timer”. the parser can usually make a pretty good guess about the intent of the code because an already established structure is in place. the timer control was added. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- ControlIdentifier is the pair ProgID. such as “Excel. with XML. there is no real difference between LoadXMLFile and AsyncXMLLoad. Troubleshooting Your XML Document The IE5 XML parser is unforgiving of errors in the documents it parses. supplied a unique name. In HTML. and Container. When you declare a variable called DownloadTimer as a Timer variable with events. the XML parser handles the hard part of converting the file into an internal document.

gif”/>This is my picture</IMAGE> will generate an error because of the terminating back slash in the IMAGE tag. it encompasses all other nodes. the closing bracket should include a question mark as well: ?>. In general. and establish a convention for your tags and attributes as all uppercase or lowercase. so <MYTAG></mytag> will generate an error. but avoid WYSISIG editors. Finally. Embedding HTML in an XML document is discussed later in this chapter in the section “Describing Your Data: The DTD. disable curly quotes. but <IMAGE REF= “myImage. This differs from most modern strains of HTML. Previous Table of Contents Next . You make the rules. a standalone tag cannot enclose any text. the rule book of the document—then you need to follow all the naming and data conventions of that document as well.” • Finally. • Any standalone tag must be terminated with a slash. nor have a closing tag.gif”> is not unless a corresponding </IMAGE> tag exists. You might accidentally create bad code in several places: • In the prolog. you should probably write an XML file in an editor specifically designed for creating HTML. assume the worst. there can be only one root node in an XML document. This will generate an error in XML. • Attribute values must be surrounded by quotes. you have to live by them.gif”/> is valid. Without this. For example <IMAGE REF=“myImage. it usually serves as a convenient identifier for the root. <IMAGE REF=“myImage. but to do this. In addition to this. • In the word processor used to create the XML. the tag begins with <?xml—no spaces and all lowercase. you need to set the data type of the node through a DTD structure. In other words. The version number appears next. Although this root node doesn’t need to have the name <DOCUMENT>. The IE5 parser in particular is case-sensitive. where such expressions as <IMG SRC=myImage. • Similarly. I’d recommend an application such as Visual InterDev. • Some XML parsers are case sensitive. again in lowercase: version=“1. Allaire’s Home Page (my personal favorite). but others are not. the XML parser will attempt to interpret HTML as if it were XML with all kinds of headaches as a consequence. • You can embed HTML text into XML documents. they have a tendency to alter erroneous tags. and certain formats for XML tags look wrong to these editors. if you do provide a DTD—in essence.gif> are valid. outside of the prolog.0”.the XML document. or HoTMetaL.

All rights reserved. .Products | Contact Us | About Us | Privacy | Ad Info | Home Use of this site is subject to certain Terms & Conditions. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Copyright © 1996-2000 EarthWeb Inc. Read EarthWeb's privacy statement.

A basic weather report for select West Coast locations --> <!-. The key to accessing this tree lies in getting a handle on the root node of the tree.0"?> <!-. If the document has no prolog or XML header (it doesn’t necessarily need one. <!-.Root ChildNode 0. the DOMDocument returns a reference to that very root.Root Node for the Document.Root ChildNode 1. then the start of the data section could be one of several nodes.To access the contents.4 shows the weather report document with special nodes indicated. Listing 12.node is documentNode --> <WEATHERREPORT> <STATE NAME="California"> <CITY ID ="Los Angeles"> <SKIES VALUE="PARTLYSUNNY"/> <HI C="31" F="87"/> <LOW C="18" F="65"/> Partly cloudy. For example. the information is stored in a fairly complex data tree in memory.4 An annotated XML weather report. However. Listing 12. nodeName is XML --> <?xml version="1. if the prolog is included or there are any comments outside of the data set. </CITY> <CITY ID ="Sacramento"> <SKIES VALUE="SUNNY"/> . by the way). although it is not necessarily the root of the data tree. has no name or tag --> <!-. click the chapter and section titles. Fortunately. Visual Basic 6 Client/Server Programming Gold Book Go! Keyword Brief Full Advanced Search Search Tips (Publisher: The Coriolis Group) Author(s): Michael MacDonald and Kurt Cagle ISBN: 1576102823 Publication Date: 10/01/98 Search this book: Go! Previous Table of Contents Next ----------- Navigating An XML Document Once you load an XML document.Root ChildNode 2. The documentNode property of the DOMDocument always contains the start of the data set—that part of the XML document that actually holds the data. nodeName is WEATHERREPORT --> <!-. then the DOMDocument object contains the root of the data set. nodeName is ! --> <!-.

the second node item(1). an instance of an IDOMNodeList. length will return the number of children that the node supports.item(2) The item() function returns an IDOMNode object. length refers to the number of items in a given collection in Java or JavaScript. </CITY> <CITY ID="Redmond"> <SKIES VALUE="RAIN"/> <HI C="10" F="50"/> <LOW C="5" F="41"/> Rain. the first node is item(0). The IDOMNodeList provides much of the navigation capability within the XML structure and can be used to retrieve specific nodes. Each node has a childNodes property. However. Instead.<HI C="36" F="97"/> <LOW C="13" F="64"/> Sunny and hot. it should be pointed out that the IDOMNodeList is not a collection in the traditional Visual Basic sense. you need to use the childNodes collection. it relies on the item(n) function. and so forth. (This also gives a hint of how Java is influencing even Internet Explorer. you can’t use the New operator to create a standalone IDOMNode. although with some clever programming. </CITY> </STATE> <STATE ID ="Washington"> <CITY ID ="Seattle"> <SKIES VALUE="RAIN"/> <HI C="12" F="54"/> <LOW C="9" F="49"/> Raining on and off throughout the day. The IDOMNodeList methods are outlined in Table 12.3. and the document node. and the methods and properties for the IDOMNode object are listed in Tables 12.childNodes. where n is the zero-based index of the members of the collection. Neither IDOMNodes nor IDOMNodeLists are directly createable in Visual Basic. </CITY> </STATE> </WEATHERREPORT> In this case. for that matter) as a collection does.5. a comment. mixed with showers. it’s possible to create an IDOMNode surrogate that will (as shown later in this chapter). IDOMNodes don’t raise any events. Thus. </CITY> <CITY ID ="Olympia"> <SKIES VALUE="CLOUDY"/> <HI C="11" F="49"/> <LOW C="8" F="47"/> 30% chance of rain toward evening.4 and 12. . Similarly. the documentNode is the same as the third child (index of 2) of the root node: DOMDoc. For either the DOMDocument or most DOMNodes. then. The length property can confirm this. It doesn’t support For Each style enumeration. For the weather report. the root node has three children—the prolog tag. and it doesn’t have a default index (or a key.) To actually retrieve the node.documentNode=DOMDoc. which has a subset of the same methods and properties as the DOMDocument object.

All rights reserved.3 Methods and properties of the IDOMNodeList.5 Properties of the IDOMNode. prolog.4 Methods of the IDOMNode object. Description Retrieves a root node’s attribute by name Positions a node in the tree Removes an attribute from the node Removes the node from the XML tree Replaces one node with another Sets the value of a named attribute to a string Table 12. Copyright © 1996-2000 EarthWeb Inc. Reproduction whole or in part in any form or medium without express written permission of EarthWeb is prohibited. comment. Type Description IDOMNo