OERI Query Manipulation - Wiki - OpenEdge Architecture - Progress Community

OERI Query Manipulation

In the Presentation Layer, developers create (and modify) queries against a Model. This allows the client (UI, usually the Presenter or View) to filter, sort and otherwise manipulate the data contained in the Model without necessarily having an impact on how that data was populated. This separation of queries (and data) is an important element of the OERA. It is also necessary for the client to be able to pass query definitions from the client to the server in order to populate the client data set.

The reference components provide a mechanism for this in two parts: a query definition mechanism, which allows for the storage of the query definition, and a query manipulation mechanism.

QueryInterfaces.PNG

QueryDefinition and IQueryDefinition

The QueryDefinition object contains meta-data about a single query: buffers, joins (between those buffers), filters (non-buffer), sorting and the like. It allows the use of named buffers. The QueryDefinition does not perform any operations on the query itself (such as open, close or reposition); these actions are left to the Query object.

This object exists mainly because having an object allows us to extend or modify the kinds of data associated with a query without having to change any of the parameters. This is similar to the intent of using EventArgs. We can also change the implementation of the (say) buffers without any external changes (to use objects instead of strings, for instance).

The QueryDefinition object implements the IQueryDefinition interface. The QueryDefinition class and IQueryDefinition interface can be found in the OpenEdge.Core.System package.

The QueryDefinition object implements OpenEdge.Base.Interfaces.ISerializable, and so can be serialized to and from a LONGCHAR, which can be passed across session boundaries (ie an AppServer) if need be.

The IQueryDefinition object defines a single event to allow objects that use it to react to any changes in the definition.

Event NameSignatureDescription
QueryDefinitionChanged void (IQueryDefinition, QueryDefinitionEventArgs) Fires whenever any of the the query definition elements change. Note that the QueryDefinition doesn't do anything based on whether it's changed or not, it merely reports the fact to its Subscribers.

Query and IQuery

The Query object contains a single QueryDefinition object, which it uses to define the query. The Query object creates and operates on an ABL query. The Query object has a number of properties that are restricted to having a PUBLIC GET, and a restricted set (protected or private accessors). These properties are either derived from the ABL query or are set via the constructor (or derived therein).

Property NameTypeDescription
QueryHandle Handle The query handle is exposed since it is used by a ProBindingSource.
QueryDefinition OpenEdge.Core.System.IQueryDefinition A Query only has one QueryDefinition associated with it. Once it's created, we can manipulate to our hearts' content, but the object instance stays the same. Note that the Query object subscribes to the QueryDefinitionChanged event.
NumRows integer Number of result rows; derived from the underlying query
CurrentPosition integer The current ordinal position; derived from the underlying query
RowPosition OpenEdge.Core.System.RowPositionEnum Relative position of current row
TableOwner OpenEdge.Core.System.ITableOwner Defines where the Query object can call to get a handle to the tables which will be used to create buffers for the query

The Query methods are mostly wrappers around corresponding ABL query methods. The following lists some more specialized Query methods:

Method NameTypeDescription
GetBufferTableName(char:BufferName) character Returns the physical table name of the query buffer
GetCurrentTableKey character Returns the current key (expression) that corresponds to a particular buffer
GetCurrentRowKey character extent Returns the current row key as an array with an extent for each buffer in the query. It is not defined as a property because it is used as a whole, typically passed into other APIs that needs the full key. More info at OERI Query Result Row Identification

The Query object has two constructors.

ArgumentsDescription
handle:QueryHandle, IQueryDefinition If an ABL query has already been created, the handle of the query should be passed in together with the QueryDefinition. In this case, the buffers associated with the query are considered fixed. In addition, when the Query object is destroyed, the QueryHandle is left alone.
ITableOwner, ITableDefinition The ITableOwner argument defines where the Query object can call to get a handle to the tables which will be used to create buffers for the query.

Query Result Row Identification

Rows in a query can be uniquely identified by means of a Row Key Array, as described here.

Issues

RowKey array order

The fact that the CurrentRowKey array order is defined by the actual buffer order in the query makes the key volatile. The buffer order of a query can change. It is thus not unlikely that there are cases that  uses the key to reposition that might allow the buffer orders to change after the get and before the reposition. The key is currently used to set position for an appending batch, but in that case the buffer order cannot change between the requests.

One solution to this problem is to flatten the RowKey into a single character field. This can be done without loosing any information by adding table qualifiers to the field references. The drawback is that some parsing is required, but it is consistent with how field references are managed elsewhere, for example in databinding where qualifed fields are used when the query/resultlist have multiple buffers.

ITableOwner

The ITableOwner interface is implemented by the class that defines a table handle from which to create buffers for the query.

Comments
  • Hi Peter,I compared the documentation with the current (1.0.3) implementation of the IQueryDefinition and IQuery interface classes. In the Classview there is a method in the IQuery class called ReopenQuery (void) but in code there are Reopen methods with a LOGICAL return-value. Might be a little confusing while reading the documentation. Kind regards,Marko

  • We haven't been good with keeping our UML diagrams in sync with the code. The AutoDox2 doc might be more useful for inspecting classes but is of course not hugely useful for examining the relationships between them. Getting (and keeping) the doc up-to-date is an important part of this project but we've not got there quite yet, sorry.