Dynamic Order


since .1561

Dynamic Order allows to dynamically change the ORDER BY clause of SELECT statement that goes to the database server.

For example, it is possible to specify sorting like

ORDER BY 
  field1 ASC,
  field2 DESC

Previously, this could only be achieved by hard-coding the parameters in the SQL statement. This was a problem in the case when each call required a different set of data. The advantage of Dynamic Order lies in its flexibility without sacrificing security. It allows to dynamically compose any ORDER BY clause when needed.

Security

Since the table's SQL query is being dynamically changed based on client application request, security can be a concern. Data arriving at the server needs to be well structured in order to allow the server to check/validate the Dynamic Order clause and prevent any attempt of SQL injection or other unauthorized SQL access techniques.

Dynamic Order fields are sent to the server as a semicolon-separated list. As a result the Data Abstract server can validate such requests. For example it is not possible to refer to a field that are not exposed in the server Schema.

Note, that Dynamic Order is activated by default.

If you want to disable it, set the Service's AllowDynamicOrder property to False (True by default).

How it works

Server-side

If you are using AutoSQL mode, no changes on server-side are required

for Manual SQL mode, update your SQL and add ORDERBY macro like

SELECT ...
FROM ...
WHERE {WHERE}
{ORDERBY}

Client-side

The TableRequestInfo structure is used for customizing the GetData process. We decided to extend this structure and provide a new one called TableRequestInfoV7. Most platforms allow to set Dynamic Order via correspondent property of table.

Note: for specifing DESC mode we use ! prefix like !Field.

The following are some examples of using the Dynamic Order feature.

 

TableRequestInfoV7 ri = new TableRequestInfoV7();
ri.SetDynamicSelect( new string[]
                  {"EmployeeID", "FirstName", "Title", "Birthdate", "HireDate"});
//ri.SetWhereClause(lCondition.ToXmlNode());                  
ri.SetOrderBy(new string[] { "Title", "!FirstName"});
remoteDataAdapter.Fill(newDataset, "Employees", ri);

 


TableRequestInfoV7 requestInfo = new TableRequestInfoV7();

String[] arrayOfColumnNames =
      new String[] { "EmployeeID", "FirstName", "Title", "Birthdate", "HireDate" };
requestInfo.setDynamicSelect(new StringArray(arrayOfColumnNames));
remoteDataAdapter.setDynamicSelect(true);

DataTable table = new DataTable("Employees");
table.addDynamicOrder("Title");
table.addDynamicOrder("FirstName", false);
remoteDataAdapter.fill(table, requestInfo);

 

var dynamicSelect = ["EmployeeID", "FirstName", "Title", "Birthdate", "HireDate"];
  var includeSchema = true;
  var maxRecords = -1;      // Load all records
  var userFilter = "";      // No filter
  var parameters = [];      // No additional parameters
  // it's ok for using TableRequestInfoV5. DA/JS will convert it to V7 if needed
  var request = RemObjects.DataAbstract.Util.createRequestInfoV5(includeSchema, maxRecords, userFilter, parameters);
  request.DynamicSelectFieldNames.items = dynamicSelect;
  var table = new RemObjects.DataAbstract.DataTable("Employees");
  table.dynamicOrder = ["Title","!FirstName"];

  // Obtaining the data 
  adapter.getData(table, request, function () {
    drawTable(table, "t");

 


// simple way, similar to 'Designtime', with manual filling table fields
procedure ConfigureTableForDynamicSelect(aTable: TDADataTable; 
                                         aDynamicSelect: array of string);
var
  i: integer;
  lField: TDAField;
begin
  aTable.Close;
  aTable.Fields.Clear;
  for I := Low(aDynamicSelect) to High(aDynamicSelect) do begin
    lField := aTable.Fields.Add;
    lField.Name := aDynamicSelect[i];
  end;
end;

ConfigureTableForDynamicSelect(tbl_Employees, ['EmployeeID', 'FirstName',
                               'Title', 'BirthDate', 'HireDate']);

tbl_Employees.RemoteDataAdapter := RemoteDataAdapter;
tbl_Employees.DynamicOrder.Add('Title');
tbl_Employees.DynamicOrder.Add('FirstName', True);
RemoteDataAdapter.DynamicSelect:=True;
RemoteDataAdapter.Fill([tbl_Employees],False,True);