Implement all types of queries when filtering results using PreOperation RetrieveMultiple

Category: Design, Performance, Security, Supportability

Impact potential: Medium

Symptoms

RetrieveMultiple calls from different application display different results.

  • For example: same views in legacy applications show different results in new applications.

Guidance

Note

The Retrieve and RetrieveMultiple messages are typically the most commonly used messages. Plug-ins for these messages can significantly impact system performance. Generally, you should avoid using plug-ins for these messages if the requirements can be achieved some other way. More information: Limit the registration of plug-ins for Retrieve and RetrieveMultiple messages

Plug-ins registered on the RetrieveMultiple message are typically intended to filter the results returned by queries for an entity. There are two strategies to do this using a plug-in registered on either the PostOperation or PreOperation stages.

PostOperation filtering

In the PostOperation stage, evaluate the records returned in the OutputParameters BusinessEntityCollection Entities property and remove entities that should not be returned.

This approach will potentially change the expected number of records returned in each page of results and can result in inconsistent experiences when the data is displayed in an application.

PreOperation filtering

In the PreOperation stage, evaluate the InputParameters Query property and adjust the query to filter what will be returned before it is executed.

When using this approach you must implement the appropriate filtering for the different possible types of queries, most importantly: FetchExpression and QueryExpression. If you implement just one of these, different applications that use the other type of query will not apply your changes.

Although the QueryExpressionToFetchXml and FetchXmlToQueryExpression messages provide the capability to convert one query type to another, because of the performance impact of including additional calls within RetrieveMultiple, we recommend that you do not use these messages in this context. Rather, implement your filtering using the equivalent logic in both.

There is a third type of query that can also be used with RetrieveMultiple: QueryByAttribute. This type of query does not provide for complex filtering and it isn't possible to include more complex filtering logic within a plug-in. Fortunately, this type of query is not frequently used. Depending on the sensitivity of the filtering you add, you may choose to reject queries of this type by throwing an InvalidPluginExecutionException.

Example

See Sample: Modify query in PreOperation stage for an example of the strategy we recommend.

Problematic patterns

If a plug-in is written to change the records returned in a specific application which uses just one type of query used by that application, either FetchExpression or QueryExpression, the results may not be consistent in other applications or if the application changes the type of query used. Plug-ins should be written to provide the same result regardless of the application.

Additional information

When using the Web API, GET requests on a collection are converted to QueryExpression unless the query uses FetchXml as described in Retrieve and execute predefined queries. In that case the queries use FetchExpression.

The legacy web client for model-driven apps is being replaced by Unified Interface. Unified Interface uses the FetchXml defined in the SavedQuery.FetchXml or UserQuery.FetchXml properties. For better performance, Unified Interface does not convert the FetchXml data to a QueryExpression before executing these queries as the legacy web client did. Therefore, queries that were modified in plug-in code for the legacy web client which used QueryExpression will not apply the same changes now that the query to support views is being passed using FetchExpression unless the plug-in code is written to apply same logic to FetchExpression queries.

See also

Sample: Modify query in PreOperation stage
Query data using the Organization service
Use FetchXML to construct a query
Build queries with QueryExpression
Limit the registration of plug-ins for Retrieve and RetrieveMultiple messages
Unified Interface Community