Laboratory/Develop

Introduction to Using ADO 2.5 with Microsoft Exchange 2000

theking 2008. 4. 21. 08:23

출처 : Microsoft.com

http://msdn.microsoft.com/archive/default.asp

 

ADO Technical Articles

 

Introduction to Using ADO 2.5 with Microsoft Exchange 2000

Thomas Rizzo
Microsoft Developer Network

November 2000

Summary:This article explains how to use ADO 2.5 and Microsoft® Exchange 2000 to access the hierarchical data found in the Web Storage System. (17 printed pages)

Contents

Introduction
ADO 2.5
Understanding Schema
Connecting to the Web Storage System
Understanding the Web Storage System
Content Management
Finding Content
Using Transactions
Caveats
Conclusion
For More Information

Introduction

Microsoft® Exchange Server has historically been great at handling mass storage of unstructured data. However, access to that data has been limited to using either Collaboration Data Objects (CDO) version 1.21 or earlier, or Microsoft Outlook®. A fundamental piece of Microsoft's Universal Data Access (UDA) strategy is the OLE DB exposure of heterogeneous data into rowsets that can be accessed by data consumers using ActiveX® Data Objects (ADO).

Exchange 2000 Server blends the UDA strategy with the introduction of the OLE DB provider for Exchange 2000. ADO 2.5 includesRecordandStreamobjects that can be used to access the data exposed by this data provider.

Exchange 2000 Server data is stored in the Web Storage System, a soon-to-be-common data store for various Microsoft products. Exchange 2000 Server is the first of these products to use the Web Storage System as its data repository.

ADO 2.5

URL Addressability

ADO 2.5 introduces the use of Uniform Resource Locators (URLs) as an alternative to connection strings and command text. Because everything in the Web Storage System is URL-addressable, you can use ADO to access any resource in the Web Storage System— including folders, messages, appointments and documents— by simply passing the item's URL in your ADO call.

Record Object

TheRecordobject is new with ADO 2.5. You can use theRecordobject to access any item in the Web Storage System. You have full access to the item's set of properties and its associate stream. For example, the following code can be used to access an item located in the inbox of the user whose alias is userx on server myserver:

Set Rec = CreateObject("ADODB.Record")strURL = "http://myserver/exchange/userx/inbox/item"Rec.Open strURL

Stream Object

TheStreamobject, also new with ADO 2.5, is used to access the binary stream of bytes or text that comprise a file or message, such as a file attachment. In hierarchical data stores such as the Web Storage System, a record might have a default binary stream of bits associated with it that contains the contents of the message. AStreamobject can be used to manipulate the fields that contain these streams of data. The following code shows one way to set an object reference to a stream:

Set S1 = CreateObject("ADODB.Stream")Set S1 = Rec.Fields(adDefaultStream)

Understanding Schema

The Web Storage System Schema

The Web Storage System provides a means to define schema information for resources. By using the schema capabilities of the Web Storage System, you can make schema information about your application discoverable to schema-aware applications such as the Web Storage System SQL query processor.

Schema information is not as rigidly enforced in the Web Storage System as it is in a relational database system such as Microsoft SQL Server™. Instead, schema information in the Web Storage System is used primarily to provide a mechanism for schema-aware applications to discover the names of content classes and associated properties used for items in a particular application. Using schemas promotes interoperability and reuse.

Web Storage System schema information is defined using property and content class definitions. Typically, these definitions reside as items in a designated schema folder. The following illustration depicts a typical application scenario using the Web Storage System.

사용자 삽입 이미지

Figure 1. The schema folder

InFigure 1, the schema folder is a subfolder of the application folder. Property and content class definitions are contained in the schema folder. You can organize the hierarchy of application and schema folders in any order, but you should keep the arrangement as simple as possible to avoid management and debugging complexities.

Property Definitions

Property definitions are items created to contain schema information about properties and are typically in a designated schema folder. To create a property definition, you must create an item to contain the definition, assign it a name, a data type, and specify its content class asurn:content-classes:propertydef, as in the following example:

Rec.Open strURL & "title",,adModeReadWrite, adCreateNonCollectionSet Flds = Rec.FieldsWith Flds    .Item("DAV:contentclass") = "urn:content-classes:propertydef"    .Item("urn:schemas-microsoft-com:xml-data#name")  = "urn:schemas-microsoft-com-book:title"    .Item("urn:schemas-microsoft-com:datatypes#type") = "string"    .Item("urn:schemas-microsoft-com:exch-data:ismultivalued") = False    .Item("urn:schemas-microsoft-com:exch-data:isindexed")     = True    .Item("urn:schemas-microsoft-com:exch-data:isreadonly")    = False    .Update  End With  Rec.Close

Content Class Definitions

Content classes provide a link between the raw data and the schema. Every resource in an Exchange store has a content class. Every content class has a schema that is used to parse the resource. A content class definition, an item typically residing in a designated schema folder, contains several properties that allow you to specify:

  • The name of the content class.
  • Each property that belongs to the content class.
  • The existing content class (or classes) from which to inherit default properties.
  • In the case of a folder content class, the content classes of the expected folder items.

You can also add custom properties to attribute to your content class. An example of extending a content class is extending theurn:content-classes:personcontent class for a custom contact management application.

Attributing Content Classes to Folders and Items

You specify the content class for an item by using theDAV:contentclassproperty. All properties listed as elements in the content class specified for a given item are incorporated into the schema for that item. For those properties to be returned in a SQL search of all properties in the item's folder, you must list the content class among the expected content classes in theurn:schemas-microsoft-com:exch-data:expected-content classproperty of the folder's content class definition.

Schema Scope

The application folder, which contains the items for which you create property definitions, has aschema-collection-ref(SCR) property set to the URL of the schema folder. The SCR property defines where the parser begins searching for schema information. The folder's multi-valuebaseschemaproperty contains same-store folder URLs that specify other locations for content class and property definitions.

Connecting to the Web Storage System

Connections

As stated earlier, you can use ADO to access any resource in the Web Storage System. The first step in accessing a resource in the Web Storage System is to connect— implicitly or explicitly— to the Web Storage System itself as a data source. You have two choices when selecting a URL scheme: the FILE: type URL and the HTTP: type URL.

Implicit Connections

The OLE DB provider for Exchange 2000 registers the FILE: OLE DB URL namespace with the OLE DB root binder. Therefore, when connecting to the Web Storage System by using the FILE: type URL, the ADO connection is implicit, meaning you need not explicitly specify the provider when accessing resources in the Web Storage System.

The following example accesses an item from user userx's inbox:

Set Rec = CreateObject("ADODB.Record")strURL = "file://./backofficestorage/myserver.com/MBX/userx/inbox/item.txt"Rec.Open strURL

Explicit Connection

When you access resources in the Web Storage System by using the HTTP: URL scheme, you follow the same rules as if you were accessing the item over a network. The URL scheme is as follows:

http://servername/virtual-directory/virtual-path

  • Exchange.The default virtual directory name for all private stores.
  • Public.The virtual directory name for the top public folder in the default public folder hierarchy.

When you use HTTP URLs to access the Web Storage System, you must explicitly specify the OLE DB provider for the Exchange 2000 binder when binding the item. This is accomplished by setting theProviderproperty of the ADOConnectionobject to "ExOLEDB.DataSource" and passing theConnectionobject as a parameter in theOpenmethod of theRecordobject. For example, the following code accesses the same item previously accessed using the FILE: URL scheme, this time using the HTTP: URL scheme:

Set Conn = CreateObject("ADODB.Connection")Set Rec = CreateObject("ADODB.Record")Conn.Provider = "ExOLEDB.DataSource"strFolderURL = "http://myserver/exchange/userx/inbox"Conn.Open strFolderURLRec.Open strFolderURL & "/item.txt", Conn

Understanding the Web Storage System

Hierarchical and Relational Data Stores

A relational data store typically consists of a database, which contains tables that contain records that contain fields. The data is structured, and the schema is very rigid in terms of the types of data it allows in the database. Examples of relational data stores are mainframe ISAM/VSAM databases and SQL Server databases. Data from tables in relational stores can be expressed as rowsets by using either Open Database Connectivity (ODBC) or OLE DB providers. Rows in the rowsets represent records.

Business information often demands more flexibility in storing data. Hierarchical data stores fulfill this demand by allowing the schema to be less rigid. Hierarchical stores, like those designed for e-mail, binary and text files, graphical and geographical data, and other custom business objects, are more flexible in allowing ad hoc and unstructured data. This is so because the schema is flexible enough to allow certain properties to be required or not required, depending on how the properties are defined.

Like relational data stores, hierarchical stores can express data by using an OLE DB provider. ADO can be used in programs to access, or consume, the data provided by the OLE DB provider. ADO 2.5 contains new objects, theRecordandStreamobjects, which are designed specifically for accessing hierarchical data. TheRecordobject can be used to access resources like folders and items, and theStreamobject can be used to access the binary bits of data that comprise a file or message.

Finding Folders and Items

Information within the Web Storage System is distributed throughout a number of databases for both private and public stores. These databases in turn contain a number of related tables. For instance, the Folders table keeps track of folders while another table represents items within a folder.

ARecordsetobject represents each of these tables, and aRecordobject represents an individual record, such as a folder or item. Because the Web Storage System is based on a hierarchical database, folders and items can be bothRecordsandRecordsets. By using a combination of URLs and ADO objects, you can access and control the contents of the Web Storage System.

Navigating a Folder Hierarchy

The following example (assuming Conn is a valid connection object to the Web Storage System) uses aRecordsetobject to represent a folder and an SQL query to enumerate its direct (or child) subfolders:

strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""strQuery = strQuery & " FROM SCOPE('shallow traversal of """ &URL& """')" strQuery = strQuery & " WHERE ""DAV:isfolder"" = True AND "strQuery = strQuery & """DAV:ishidden"" = False"Set Rs = CreateObject("ADODB.Recordset")Rs.Open strQuery, Conn

The URL in the preceding example could be any folder URL. The resulting recordset contains records, each representing a subfolder. For example, a public folder named Test is located in the root of the public folder system. Therefore, its URL is http://myserver/public/Test. Test also contains two subfolders, First and Second. Using Test's URL in the preceding example creates a recordset containing two records, which represent these two subfolders and to which you can assign ADORecordobject references.

For example:

Set Rec1 = CreateObject("ADODB.Record")Set Rec2 = CreateObject("ADODB.Record")Rec1.Open Rs   'Subfolder "First"Rs.MoveNextRec2.Open Rs   'Subfolder "Second"

Once you have aRecordobject reference to a subfolder, you can use the "DAV:href" field, which contains the folder's absolute URL, along with the preceding SQL query to enumerate its subfolders, just as you did in the previous examples. For purposes of modularity and reuse, you can encapsulate the query example into a function and call it recursively to enumerate an entire folder structure.

Searching for Folders

You can use the ideas we just discussed, along with the tree traversal algorithm of your choice, to search for a folder in the default public store hierarchy ("All Public Folders") installed by Microsoft Exchange 2000 Server for use by MAPI clients. To search for a folder in a private store or in a public store other than the default public store, you can use the following query:

strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""strQuery = strQuery & " FROM SCOPE('deeptraversal of """ & URL & """')" strQuery = strQuery & " WHERE ""DAV:isfolder"" = True AND "strQuery = strQuery & """DAV:ishidden"" = False"Set Rs = CreateObject("ADODB.Recordset")Rs.Open strQuery, Conn

Notice that a deep traversal was specified, which extends the search scope to include any and all subfolders. Later in this article, we will discuss using deep and shallow traversals to search for resources in the Web Storage System, as well as refining the search results by using aWHEREclause.

Listing Items in a folder

You can use a query similar to the previous examples to enumerate the items contained in a folder.

For example:

strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""strQuery = strQuery & " FROM SCOPE('shallow traversal of """ & URL & """')" strQuery = strQuery & " WHERE ""DAV:isfolder"" =FalseAND "strQuery = strQuery & """DAV:ishidden"" = False"Set Rs = CreateObject("ADODB.Recordset")Rs.Open strQuery, Conn

Notice the DAV:isfolder = False condition, which tells the query processor to return only nonfolder items in the folder being searched. You can loop through the recordset to display the properties of the items.

For example:

Do While Not (Rs.BOF Or Rs.EOF)  Debug.Print Rs.Fields("DAV:displayname")  Rs.MoveNextLoop

Restricting the List

You can refine the list of items or folders returned in search results by adding conditions to theWHEREclause. For example, if you want to find only documents (not messages) in a particular folder, you could insert a line of code into the previous example:

strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""strQuery = strQuery & " FROM SCOPE('shallow traversal of """ & URL & """')" strQuery = strQuery & " WHERE ""DAV:isfolder"" = False AND "strQuery = strQuery & """DAV:ishidden"" = False AND "strQuery = strQuery & """DAV:contentclass"" = 'urn:content-classes:document'"Set Rs = CreateObject("ADODB.Recordset")Rs.Open strQuery, ConnDo While Not (Rs.BOF Or Rs.EOF)  Debug.Print Rs.Fields("DAV:displayname")  Rs.MoveNextLoop

Similarly, if you want to find only documents in a particular private or nondefault public folder hierarchy, you could use a deep traversal:

strQuery = "SELECT ""DAV:displayname"", ""DAV:contentclass"", ""DAV:href"""strQuery = strQuery & " FROM SCOPE('deeptraversal of """ & URL & """')" strQuery = strQuery & " WHERE ""DAV:isfolder"" = False AND "strQuery = strQuery & """DAV:ishidden"" = False AND "strQuery = strQuery & """DAV:contentclass"" = 'urn:content-classes:document'"Set Rs = CreateObject("ADODB.Recordset")Rs.Open strQuery, ConnDo While Not (Rs.BOF Or Rs.EOF)  Debug.Print Rs.Fields("DAV:displayname")  Rs.MoveNextLoop

Content Management

Creating Items

The following example creates a new public folder named TestFolder, assuming that one does not already exist:

'Reference MS ADO 2.5 LibrarystrUrl = "http://myserver/public"Set Conn = CreateObject("ADODB.Connection")Conn.Provider = "ExOLEDB.DataSource"Conn.Open strUrlSet Rec = CreateObject("ADODB.Record")Rec.Open strUrl & "/TestFolder", Conn, adModeReadWrite, adCreateCollection

TheadCreateCollectionconstant from the ADO 2.5 Library specifies the creation of a folder. The appropriate properties, such asDAV:isfolder (=True)andDAV:contentclass (="urn:content-classes:folder"), are set accordingly.

The following example creates a new message item in the public folder TestFolder:

strUrl = "http://myserver/public/TestFolder"Set Conn = CreateObject("ADODB.Connection")Conn.Provider = "ExOLEDB.DataSource"Conn.Open strUrlSet Rec = CreateObject("ADODB.Record")Rec.Open strUrl & "/test.EML", Conn, adModeReadWrite, adCreateNonCollection

TheadCreateNonCollectionconstant from the ADO 2.5 Library specifies the creation of a message item. You can use theFieldscollection of theRecordobject to update property values according to the schema of the item created. You can also add custom fields, for example:

Rec.Fields("DAV:displayname") = "no longer a test"Rec.Fields("test") = "This is a test"Rec.Fields.Update

The example just shown updates theDAV:displaynameproperty and adds the custom property "test" to theFieldscollection.

Changing Items

The following example shows how to update fields on items in a folder by looping through a recordset:

Set Rs = CreateObject("ADODB.Recordset")Set Rec = CreateObject("ADODB.Record")i = 1Do While Not (Rs.BOF Or Rs.EOF)    Rec.Open Rs    With Rec.Fields("urn:schemas:httpmail:subject")        .Value = .Value & " - " & i        Rec.Fields.Update    End With    Rs.MoveNext    Rec.Close    i = i + 1Loop

Finding Content

Building a Query

Searches on the Web Storage System are performed according to Microsoft Distributed Authoring Search Language (MS-DASL) specifications and are implemented by using an SQL query grammar called DAV:sql. These SQL queries return ADORecordorRecordsetobjects of Web Storage System property information. HTTP/1.1, or Distributed Authoring and Versioning (WebDAV), converts the SQL queries into XML elements and methods for conducting the search.

The SELECT Statement

You can use aSELECTstatement to return the values of properties for items within a particular folder or folders within a store. TheSELECTstatement has the following syntax:

SELECT * | select-listFROM SCOPE(resource-list) [WHERE search-condition][order-by-clause]

To request specific properties, surround each property name with double quotes and separate each property name with a comma. For example:

SELECT "DAV:href", "DAV:displayname" ...

Defining the Scope of a Query

TheFROMclause, as in relational SQL statements, is used to indicate the scope of the search. Unlike querying a table in a relational database, in the Web Storage System you issue a query on a folder scope specified by a folder URL and a depth.

Specifying a Search Scope with Deep and Shallow Traversals

You define a search scope by using the SCOPE SQL element. Within the SCOPE element, you define the depths and URLs for the folders to be searched. You can specify a shallow traversal to search only in the specified folder, or a deep traversal to search a folder and all of its subfolders. For shallow searches, you specify 'shallow traversal of'; for deep searches, you specify 'deep traversal of'. After specifying the depth, you specify the URL for each folder. The syntax for this statement is as follows:

SCOPE('shallow traversal of "URL1"', ['shallow traversal of "URL2"'])

–or–

SCOPE('deep traversal of "URL1"', ['deep traversal of "URL2"'])

To find all immediate subfolders of a particular folder, for example, execute the following SQL statement:

SELECT ""DAV:href"", ""DAV:displayname""   FROM SCOPE('shallow traversal of "URL"')   WHERE ""DAV:isfolder"" = True and ""DAV:ishidden"" = False

The traversal is shallow, so the contents of its subfolders are not searched. To expand the search scope to include all subfolders, execute the following SQL statement:

SELECT ""DAV:href"", ""DAV:displayname""   FROM SCOPE('shallow traversal of "URL"')   WHERE ""DAV:isfolder"" = True and ""DAV:ishidden"" = False

The WHERE Clause

TheWHEREkeyword can be used in an SQL query to create a conditional clause that must be met for records to be returned. To chain conditions together, use theANDandORkeywords. Use parentheses to group conditions into a single logical condition. Use the following syntax:

WHEREcondition

Condition can be a single logical condition or a set of logical conditions that evaluate to either a TRUE or a FALSE result.

Several predicates can be used in aWHEREclause, including the following:

  • LIKE
  • FORMSOF
  • CONTAINS
  • ORDER BY
  • FREETEXT
  • GROUP BY

Note that LIKE, CONTAINS, and FREETEXT can only be used when content indexing is enabled on a particular store.

Matching Characters Using LIKE

You can use the LIKE predicate as part of a generalWHEREclause condition to perform character matches. LIKE performs a character-by-character comparison of the specified property value and the supplied characters. For example:

WHERE "urn:schemas:httpmail:sendername" LIKE "Jones"

Matching Words Using CONTAINS

The CONTAINS predicate matches words and phrases exactly as specified. The following example searches for all messages containing a specified phrase from a particular sender, assuming that Conn is a validConnectionobject and strURL is a valid folder URL:

strQuery = "SELECT ""DAV:displayname"""strQuery = strQuery & " FROM """ & strURL & """"strQuery = strQuery & " WHERE CONTAINS(*, ' ""some phrase"" ')"strQuery = strQuery & " AND CONTAINS(""urn:schemas:httpmail:sendername"","strQuery = strQuery & " ' ""userx"" ')"Rs.Open strQuery, Conn

Matching Words Using FREETEXT

For a broader search, you can use the FREETEXT predicate as part of aWHEREclause. FREETEXT loosely matches any item having one or more of the words specified. For example, the following query matches any item containing Columbia, Seattle, or Montreal (non-case sensitive):

strQuery = "SELECT ""DAV:displayname"""strQuery = strQuery & " FROM """ & strURL & """"strQuery = strQuery & " WHERE FREETEXT(*, ' ""Columbia Seattle Montreal"" ')"Rs.Open strQuery, Conn

Finding Word Variations Using FORMSOF

You can use FORMSOF as part of aWHEREclause to find word variations, such as "expect," "expecting," and "expectation." FORMSOF is typically used within a CONTAINS or FREETEXT predicate, as in the following example:

strQuery = "SELECT ""DAV:displayname"" FROM """ & strURL & """"strQuery = strQuery & " WHERE CONTAINS('FORMSOF(INFLECTIONAL,""expect"") ')"Rs.Open strQuery, Conn

Sorting Query Results by Using ORDER BY

TheORDER BYclause sorts the returned recordset in ascending or descending order, according to one or more properties specified. The following example finds all messages from a particular sender and sorts them by the date received, in ascending order:

strQuery = "SELECT ""DAV:displayname"",""urn:schemas:httpmail:datereceived"""strQuery = strQuery & ", ""urn:schemas:httpmail:sendername"" FROM "strQuery = strQuery & """" & strURL & """ WHERE " & _       "CONTAINS(""urn:schemas:httpmail:sendername"", ' ""Userx"" ') "strQuery = strQuery & "ORDER BY ""urn:schemas:httpmail:datereceived"" ASC"Rs.Open strQuery, Conn

Getting Item Counts by Using GROUP BY

The GROUP BY predicate organizes the returned recordset according to one or more of the properties specified in theSELECTstatement.

The following example totals the messages with and without attachments:

strQuery = "SELECT ""DAV:visiblecount"", ""urn:schemas:httpmail:importance"""strQuery = strQuery & " FROM """ & strURL & """ GROUP BY"strQuery = strQuery & " ""urn:schemas:httpmail:importance"""Rs.Open strQuery, Conn

When using GROUP BY, you can return the number of occurrences of each group in the returned recordset by including theDAV:visiblecountproperty in theSELECTstatement.

Using Transactions

Queries often involve large sets of data and typically require many calls to a data store. You can use transactions, or grouped operations, to query and update items in the Web Storage System so that your data requests are wrapped into one grouped operation. This is also useful when you want to perform "all or none" scenarios. For example, if you want to create two items that are dependent on one another, you may want to cancel the creation of the second item if the first item's creation attempt fails.

There are three ADO methods of theConnectionobject available to facilitate grouped operations:

  • BeginTrans. Begins a new transaction.
  • CommitTrans. Saves any changes made during the current transaction, and ends the current transaction.
  • RollbackTrans. Cancels any changes made during the current transaction, and ends the current transaction.

The following example updates theSubjectfield in each of the items in a folder:

Sub Main()  Set Rs = CreateObject("ADODB.Recordset")Conn.BeginTransSet Rec = CreateObject("ADODB.Record")  Do While Not (Rs.BOF Or Rs.EOF)    Rec.Open Rs    With Rec.Fields("urn:schemas:httpmail:subject")      If .Value = "test" ThenConn.RollbackTransRec.Close        Rs.Close        Conn.Close        Debug.Print "Transaction Rolled Back"        Exit Sub      End If      Debug.Print "BEFORE UPDATE: " & .Value      .Value = .Value & " - updated by transaction"      Rec.Fields.Update      Debug.Print "AFTER UPDATE: " & .Value    End With    Rs.MoveNext    Rec.Close  LoopConn.CommitTransEnd Sub

If the Subject of one of the items equals "test," the entire grouped operation is canceled. If you use the Immediate window in Microsoft Visual Basic® to observe the output of theDebug.Printcommands, you will notice that the value of theSubjectfield seems to update with the new value as the operations occur. However, the updates are actually performed on a copy of the data. If the changes are not committed to the store by using theCommitTransmethod, the changes are dropped and the data in the store is not updated. You can verify this behavior by observing the items using Microsoft Outlook or Internet Explorer before, during, and after the grouped operation.

Caveats

Please note that the OLE DB provider for Exchange 2000 Server does not support nested transactions. Therefore, you cannot begin a transaction while another transaction is open, and the return value of "level," indicating the nesting level of the transaction, does not apply. The provider does not support full transaction isolation but allows only a read-committed (cursor stability) isolation level.

Because connections are bound to a single store within the Web Storage System, you cannot perform grouped operations across multiple stores.

SELECT *

Because Exchange 2000 offers so many properties that you can query, avoid using SELECT * in your queries unless absolutely necessary. Using SELECT * creates a recordset of all the schema-defined properties (or columns) in a given collection. Building this broad recordset requires unnecessary server processing unless you use all of the columns. Instead, include in your query string only the columns you wish to process.

Searching Multiple Stores

EachSELECTcommand is executed within the context of an OLE DB session (ADO connection) that implicitly defines the store (public or mailbox) and the folder tree being searched. Therefore, you cannot use one SQL command to search across multiple stores.

MAPI Folder Trees

Only shallow traversal of a single folder is supported in the public store installed by Microsoft Exchange 2000 Server for MAPI clients. However, you can perform deep traversals of private stores and any other public folder hierarchies.

Using Deep and Shallow Traversals

When specifying multiple folders in your SCOPE element, you must use the same depth for each folder. You cannot mix deep and shallow searches within the same SQL command.

Conclusion

ADO 2.5, along with OLE DB, provides a familiar "look and feel" to the Exchange data store. Prior to the release of Exchange 2000 Server, you were forced to use unfamiliar technologies to access Exchange data. Now you can use the same technology you are accustomed to using for accessing more traditional data stores to access the hierarchical data found in the Web Storage System.

For More Information

For more information, see the following: