Add an API IEnumerable<T> IQueryManager.GetCustom<T> (IQuery query, Func<IQueryResultRow, T> rowConversion) that allows queries to be executed that return a collection of arbitrary values rather than DomainObjects. A new QueryType "Custom" is added to identify queries that can be passed to GetCustom<T>. Custom queries cannot be used to perform eager fetching.
To create a custom query, use QueryFactory.CreateCustomQuery or define a custom query in the query configuration (e.g., Queries.xml), as illustrated by the following example:
The rowConversion delegate passed into IQueryManager.GetCustom<T>() is used to convert the values returned by the storage provider (in storage-specific format; e.g., enum values might be represented as integers) to the data type requested by the user. Use IQueryResultRow.GetRawValue (int position), GetConvertedValue<T> (int position), and GetConvertedValue (int position, Type type) to extract the values as needed. Here is an example:
The GetCustom method is implemented within the QueryManager class by calling a new StorageProvider API IEnumerable<IQueryResultRow> ExecuteCustomQuery (IQuery query). Note that with the RdbmsProvider implementation, a database connection and transaction may remain open while iterating the result of IQueryManager.GetCustom<T> (...). To free resources eagerly, call ToList(), ToArray() or a similar method on the enumerable, as illustrated in the example above.
Together with IQueryManager.GetCustom, a new notification method IEnumerable<T> IClientTransactionExtension.FilterCustomQueryResult (ClientTransaction clientTransaction, IQuery query, IEnumerable<T> results) is also added. The QueryManager implementation automatically invokes that notification method, allowing ClientTransactionExtensions to filter the query result before it is returned to the caller.
Note that for now, the SecurityClientTransactionExtension will not implement any filtering for custom queries.