View tasks using the Query object in TEWS will return the first result repeatedly

Document ID : KB000049836
Last Modified Date : 14/02/2018
Show Technical Document Details

Description:

Query type object in TEWS is designed to provide details of a single object. The 'Filter' element might be misleading suggesting it can return multiple objects however it will return the same object repeatedly. You should use the Search type object to be able to retrieve your results, and then find more details on each of them using the Query object.

Solution:

When you enable a View type task for web services (for example: View User task) you should see two new interfaces created the next time you generate your wsdl xml. These are the Search and the Query interfaces:

<taskName>Query
<taskName>Search
For example:
<wsdl:ViewUserQuery>
<wsdl:ViewUserSearch>

The purpose of the Search interface is to allow you to execute a query and return a number of results. The purpose of the Query interface is to allow you to get more specific details about a specific result.

Let's see an example of using the Search interface to perform a query that returns all of the users (the query is LastName = *):

<wsdl:ViewUserSearch>
 <wsdl:Filter index="0">
 <wsdl:Field>%LAST_NAME%</wsdl:Field>
 <wsdl:Op>EQUALS</wsdl:Op>
 <wsdl:Value>*</wsdl:Value>
 </wsdl:Filter>
 </wsdl:ViewUserSearch>
This will return:
<ViewUserSearchResult>
 <ImsStatus version="6.0">
 <transactionId>13d43c1e-0acb2ee1-3f587ed9-c3174ae</transactionId>
 </ImsStatus>
 <ResultItem>
 <OID>uid=imuser,ou=Administration,ou=Corporate,o=DEMOCORP,c=AU</OID>
 <_PCT_ORG_MEMBERSHIP_NAME_PCT_>
 <DISPLAY_NAME>Organization Name</DISPLAY_NAME>
 <ATTR_NAME>%ORG_MEMBERSHIP_NAME%</ATTR_NAME>
 <ATTR_VALUE>Corporate</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_ORG_MEMBERSHIP_NAME_PCT_>
 <_PCT_LAST_NAME_PCT_>
 <DISPLAY_NAME>Last Name</DISPLAY_NAME>
 <ATTR_NAME>%LAST_NAME%</ATTR_NAME>
 <ATTR_VALUE>imuser</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_LAST_NAME_PCT_>
 <_PCT_USER_ID_PCT_>
 <DISPLAY_NAME>User ID</DISPLAY_NAME>
 <ATTR_NAME>%USER_ID%</ATTR_NAME>
 <ATTR_VALUE>imuser</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_USER_ID_PCT_>
 <_PCT_FIRST_NAME_PCT_>
 <DISPLAY_NAME>First Name</DISPLAY_NAME>
 <ATTR_NAME>%FIRST_NAME%</ATTR_NAME>
 <ATTR_VALUE>imuser</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_FIRST_NAME_PCT_>
 </ResultItem>
 <ResultItem>
 <OID>uid=MyUser1,ou=people,ou=Administration,ou=Corporate,o=DEMOCORP,c=AU</OID>
 <_PCT_ORG_MEMBERSHIP_NAME_PCT_>
 <DISPLAY_NAME>Organization Name</DISPLAY_NAME>
 <ATTR_NAME>%ORG_MEMBERSHIP_NAME%</ATTR_NAME>
 <ATTR_VALUE>Administration</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_ORG_MEMBERSHIP_NAME_PCT_>
 <_PCT_LAST_NAME_PCT_>
 <DISPLAY_NAME>Last Name</DISPLAY_NAME>
 <ATTR_NAME>%LAST_NAME%</ATTR_NAME>
 <ATTR_VALUE>MyUser1</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_LAST_NAME_PCT_>
 <_PCT_USER_ID_PCT_>
 <DISPLAY_NAME>User ID</DISPLAY_NAME>
 <ATTR_NAME>%USER_ID%</ATTR_NAME>
 <ATTR_VALUE>MyUser1</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_USER_ID_PCT_>
 <_PCT_FIRST_NAME_PCT_>
 <DISPLAY_NAME>First Name</DISPLAY_NAME>
 <ATTR_NAME>%FIRST_NAME%</ATTR_NAME>
 <ATTR_VALUE>MyUser1</ATTR_VALUE>
 <ATTR_PERMISSION>ReadWrite</ATTR_PERMISSION>
 </_PCT_FIRST_NAME_PCT_>
 </ResultItem>
 ...
 ...
 ...
 more results
 ...
 ...
 ...
 </ViewUserSearchResult>

The example above shows you how the query returns a SearchResult object that is specific to the task you executed ( in this case ViewUserSearchResult ). The SearchResult consist of iterated ResultItem elements that each has some of the data of the object. In this example above you see we get the First Name, Last Name , User ID and organization of each of the returned users. We do not , however, get more information such as roles, group memberships etc...

If we wanted to get more information about each user we can use the Query interface ( <wsdl:ViewUserQuery> ). Here is an example of doing that. This example is showing how to retrieve the data of a user whose last name = myuser2:

<wsdl:ViewUserQuery>
 <wsdl:ViewUserSearch>
 <wsdl:Filter index="0">
 <wsdl:Field>%LAST_NAME%</wsdl:Field>
 <wsdl:Op>EQUALS</wsdl:Op>
 <wsdl:Value>myuser2</wsdl:Value>
 </wsdl:Filter>
 </wsdl:ViewUserSearch>
 <!--Optional:-->
 </wsdl:ViewUserQuery>
 The result of this query is:
 <ViewUserQueryResult>
 <ImsStatus version="6.0">
 <transactionId>23e5064a-51070b52-9f90fcaf-038d43</transactionId>
 </ImsStatus>
 <ViewUserAdminRolesTab>
 <UserMemberAdminRoles>
 <currentvalue index="0">
 <Name>Self Manager</Name>
 <UniqueName>12</UniqueName>
 </currentvalue>
 </UserMemberAdminRoles>
 </ViewUserAdminRolesTab>
 <ViewUserProfileTab>
 <_BAR_enable_BAR_>true</_BAR_enable_BAR_>
 <_PCT_EMAIL_PCT_/>
 <_PCT_ENABLED_STATE_PCT_>0</_PCT_ENABLED_STATE_PCT_>
 <_PCT_FIRST_NAME_PCT_>MyUser2</_PCT_FIRST_NAME_PCT_>
 <_PCT_FULL_NAME_PCT_>MyUser2 MyUser2</_PCT_FULL_NAME_PCT_>
 <_PCT_IDENTITY_POLICY_PCT_/>
 <_PCT_LAST_NAME_PCT_>MyUser2</_PCT_LAST_NAME_PCT_>
 <_PCT_ORG_MEMBERSHIP_NAME_PCT_>Administration</_PCT_ORG_MEMBERSHIP_NAME_PCT_>
 <_PCT_ORG_MEMBERSHIP_PCT_>ou=Administration,ou=Corporate,o=DEMOCORP,c=AU</_PCT_ORG_MEMBERSHIP_PCT_>
 <_PCT_PASSWORD_DATA_PCT_/>
 <_PCT_PASSWORD_HINT_PCT_>q1?a1|q2?a2|q3?a3|q4?a4|q5?a5</_PCT_PASSWORD_HINT_PCT_>
 <_PCT_PASSWORD_PCT_>{SHA}ithXKgs/xMs6/Buq68l6LK5Y64w=</_PCT_PASSWORD_PCT_>
 <_PCT_USER_ID_PCT_>MyUser2</_PCT_USER_ID_PCT_>
 <departmentNumber/>
 <employeeNumber/>
 <employeeType/>
 <facsimileTelephoneNumber/>
 <l/>
 <manager/>
 <mobile/>
 <pager/>
 <postalAddress/>
 <postalCode/>
 <roomNumber/>
 <st/>
 <telephoneNumber/>
 <title>f:2</title>
 </ViewUserProfileTab>
 </ViewUserQueryResult>

Notice the returned object is a QueryResult ( unlike the SearchResult earlier ). More importantly, notice how there is no <ResultItem> tag that is returned. This is because the Query interface is designed to return one element and so the details of that element immediately follow the QueryResult object.

The confusing part is coming when you're trying to use the Query interface to execute a query that returns numerous results. Due to the 'Filter' element shown in the above example you can run the following query on the Query interface. You might think or want this query to return all the users, similar to how it's done on the Search interface.

<wsdl:ViewUserQuery>
 <wsdl:ViewUserSearch>
 <wsdl:Filter index="0">
 <wsdl:Field>%LAST_NAME%</wsdl:Field>
 <wsdl:Op>EQUALS</wsdl:Op>
 <wsdl:Value>*</wsdl:Value>
 </wsdl:Filter>
 </wsdl:ViewUserSearch>
 <!--Optional:-->
 </wsdl:ViewUserQuery>

However, this will be your result:

<soapenv:Envelope xsi:schemaLocation="http://schemas.xmlsoap.org/soap/envelope/ http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns="http://tews6/wsdl" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<soapenv:Body> <ViewUserQueryResult> <ImsStatus version="6.0"> <transactionId>e1f4e95a-1ff3f509-bd34ef90-2c576c</transactionId> </ImsStatus> <ViewUserAdminRolesTab> <UserAdminAdminRoles> <currentvalue index="0"> <Name>Email Manager</Name> <UniqueName>25</UniqueName> </currentvalue> </UserMemberAdminRoles> </ViewUserAdminRolesTab> <ViewUserProfileTab> <_BAR_enable_BAR_>true</_BAR_enable_BAR_> <_PCT_EMAIL_PCT_/> <_PCT_ENABLED_STATE_PCT_/> <_PCT_FIRST_NAME_PCT_>imuser</_PCT_FIRST_NAME_PCT_> <_PCT_FULL_NAME_PCT_>imuser</_PCT_FULL_NAME_PCT_> <_PCT_IDENTITY_POLICY_PCT_/> <_PCT_LAST_NAME_PCT_>imuser</_PCT_LAST_NAME_PCT_> <_PCT_ORG_MEMBERSHIP_NAME_PCT_>Corporate</_PCT_ORG_MEMBERSHIP_NAME_PCT_> <_PCT_ORG_MEMBERSHIP_PCT_>ou=Corporate,o=DEMOCORP,c=AU</_PCT_ORG_MEMBERSHIP_PCT_> <_PCT_PASSWORD_DATA_PCT_/> <_PCT_PASSWORD_HINT_PCT_/> <_PCT_PASSWORD_PCT_>{SHA}xGSvgXKHNDMFy9ZJPFk4hWld9TE=</_PCT_PASSWORD_PCT_> <_PCT_USER_ID_PCT_>imuser</_PCT_USER_ID_PCT_> <departmentNumber/> <employeeNumber/> <employeeType/> <facsimileTelephoneNumber/> <l/> <manager/> <mobile/> <pager/> <postalAddress/> <postalCode/> <roomNumber/> <st/> <telephoneNumber/> <title/> </ViewUserProfileTab> <ViewUserAdminRolesTab> <UserAdminAdminRoles> <currentvalue index="0"> <Name>Email Manager</Name> <UniqueName>25</UniqueName> </currentvalue> </UserMemberAdminRoles> </ViewUserAdminRolesTab> <ViewUserProfileTab> <_BAR_enable_BAR_>true</_BAR_enable_BAR_> <_PCT_EMAIL_PCT_/> <_PCT_ENABLED_STATE_PCT_/> <_PCT_FIRST_NAME_PCT_>imuser</_PCT_FIRST_NAME_PCT_> <_PCT_FULL_NAME_PCT_>imuser</_PCT_FULL_NAME_PCT_> <_PCT_IDENTITY_POLICY_PCT_/> <_PCT_LAST_NAME_PCT_>imuser</_PCT_LAST_NAME_PCT_> <_PCT_ORG_MEMBERSHIP_NAME_PCT_>Corporate</_PCT_ORG_MEMBERSHIP_NAME_PCT_> <_PCT_ORG_MEMBERSHIP_PCT_>ou=Corporate,o=DEMOCORP,c=AU</_PCT_ORG_MEMBERSHIP_PCT_> <_PCT_PASSWORD_DATA_PCT_/> <_PCT_PASSWORD_HINT_PCT_/> <_PCT_PASSWORD_PCT_>{SHA}xGSvgXKHNDMFy9ZJPFk4hWld9TE=</_PCT_PASSWORD_PCT_> <_PCT_USER_ID_PCT_>imuser</_PCT_USER_ID_PCT_> <departmentNumber/> <employeeNumber/> <employeeType/> <facsimileTelephoneNumber/> <l/> <manager/> <mobile/> <pager/> <postalAddress/> <postalCode/> <roomNumber/> <st/> <telephoneNumber/> <title/> </ViewUserProfileTab> ... ... ... more results of the same 'imuser' !! ... ... ... </ViewUserQueryResult> </soapenv:Body> </soapenv:Envelope>

Notice how in this example you are retrieving the same user repeatedly. This is because the query you specified in your Filter object is actually running but there is no Result Set to load the results into. As you see the QueryResult has no ResultItem objects. It can only load the first result of the query that was executed. The actual result of all of that is that the first result is added again and again.

Conclusion:

You need to work both with the Search and Query interfaces to perform a query that returns a number of results and examine many details of each result. You cannot shortcut this by using only one of the two interfaces as seen and explained above. The way to do that correctly would be to use the Search interface to execute your Filter. This will return a SearchResult with numerous ResultItem objects with initial information about each returned object. Then, you shall iterate over your SearchResult and perform another query using the Query interface to retrieve more specific results for each object.