Show/Hide Toolbars

TMS Aurelius Documentation

Navigation: Queries > Retrieving Results

Fetching Objects Using Cursor

Scroll Prev Top Next More

Alternatively to retrieve an object list, you can get results by using a cursor. With this approach, Aurelius executes a query in the database and returns a cursor for you to fetch objects on demand. In this case, the query will remain open until you destroy the cursor. While this approach has the advantage to keeping a database connection alive, it takes advantage of fetch-on-demand features of the underlying component set you are using, allowing you to get initial results without having to fetch all the objects returned. You don't even need to fetch all results, you can close the cursor before it. Cursor can also be used in TAureliusDataset to make it more responsive to visual controls like DB Grids.

 

To obtain a cursor, use the Open method:

 

var

  MyCriteria: TCriteria<TCustomer>;

  Cursor: ICriteriaCursor<TCustomer>;

  FetchedCustomer: TCustomer;

begin

  MyCriteria := ObjectManager1.Find<TCustomer>;

  // <snip> Build the query

  // Retrieve results

  Cursor := MyCriteria.Open;

  while Cursor.Next do

  begin

    FetchedCustomer := Cursor.Fetch;

    // Do something with FetchedCustomer

  end;

  // No need to destroy cursor

 

The Open method returns an ICriteriaCursor (or ICriteriaCursor<T>) interface which is destroyed automatically by reference counting. The underlying

TCriteria object (MyCriteria variable in the example above) is automatically destroyed when cursor is destroyed. Since ICriteriaCursor<T> implemented GetEnumerator you can also iterate through the returned entities directly:

 

 

var

  MyCriteria: TCriteria<TCustomer>;

  FetchedCustomer: TCustomer;

begin

  MyCriteria := ObjectManager1.Find<TCustomer>;

  // <snip> Build the query

  // Retrieve results

  for FetchedCustomer in MyCriteria.Open do

  begin

    // Do something with FetchedCustomer

  end;

 

The ICriteriaCursor and ICriteriaCursor<T> interfaces are declared as following.

 

  ICriteriaCursor = interface
    function Next: boolean;
    function Fetch: TObject;
    function BaseClass: TClass;
    function ResultClass: TClass;
  end;
 
  ICriteriaCursor<T: class> = interface(ICriteriaCursor)
    function Get: T;
    function GetEnumerator: TEnumerator<T>;
  end;

 

Next method increases cursor position. If result is true, then the new position is valid and there is an object to fetch. If result is false, there are no more objects to be fetched, and cursor must be destroyed. It's important to note that when the cursor is open, it remains in an undefined position. You must call Next method first, before fetching any object. If the very Next call returns false, it means the cursor has no records.

 

Fetch method is used to retrieve the object in the current cursor position. If Next was never called, or if the result of last Next call was false, Fetch will return unpredictable values. Never call Fetch in such situation.

 

Get<T> method is just a strong-typed version of Fetch method.

 

BaseClass method returns the base class used in the criteria query. In the example above, base class would be TCustomer.

 

ResultClass method returns the class of the returned objects. Usually it's the same as BaseClass, unless in specific cases like when you are using projections, for example. In this case ResultClass will be TCriteriaResult.