Skip to content

queries

Josef edited this page Apr 24, 2023 · 6 revisions

Query Examples

This topic contains the following examples:

Queries are often applied to get specific information from an AML document which cannot be supplied by a class member or a property. The Aml.Engine supports queries with the provision of a query service interface. The Aml.Engine contains two implementation of the query service interface IQuery. The main purpose of the Query service is it, to find related objects (Class to Class, Instance to Class and Instance to Instance relations).

The IQuery implementation QueryService is the registered default query service. The implementation is based on System.Xml.Linq integrated Query language. The second alternative implementation LookupService uses lookup tables and indexed based access to query objects. This service performs faster in most queries but needs additional memory space and an initialization phase to build the lookup tables. The tables are automatically updated when the AML document is modified.

The default System.Xml.Linq based query service is activated by default. To access this service, the static property QueryService can be used. To use the table based LookupService, the registration method of the LookupService shall be called first. The registration of the LookupService deactivates the default QueryService.

The choice of the right query service can be made depending on the type of application. If the AutomationML document is only read by the application (for example in a data import application) the default QueryService is sufficient. If modifications are made to the AutomationML document by the application, the LookupService is more suitable, since the LookupService uses updatable indices, which the QueryService does not.

Service registration

Activation

var service = LookupService.Register();

// after registration, the service locator has changed the query service property
Assert.AreEqual (service, Aml.Engine.Services.ServiceLocator.QueryService);

After registration, all queries including those which are called by the Aml.Engine will be performed by the LookupService. To switch back to the default System.Xml.Linq based QueryService, the LookupService shall be unregistered.

Deactivation

LookupService.UnRegister();

// after unregistration, the service locator has changed the query service property again
Assert.IsTrue (Aml.Engine.Services.ServiceLocator.QueryService is Aml.Engine.Services.QueryService);

After deregistration, all queries including those which are called by the Aml.Engine will be performed by the default System.Xml.Linq base QueryService again. Please note, that the ServiceLocator will always allow only a single service registered for a service interface type. If the LookupService should be your preferred query service, leave it registered as long as it is used. This service needs to create tables to locate objects. If the service is unregistered the service and its tables are disposed. If it is registered again, all tables have to be rebuild.

Back To Top

Basic queries

The most common queries are querying a CAEXObject by an ID or the CAEXPath. The query service is not explicitly set in these examples. The effects of query service selection on the runtime of the queries in these examples are described here.

FindByID example

using Aml.Engine.Services;
using Aml.Engine.CAEX.Extensions;

// The current query service is not explicitly defined in these examples
CAEXObject FindByID (CAEXDocument document, InternalElementType internalElement)
{
    // this is a document extension method
    var caexObj_1 = document.FindByID (internalElement.ID);
    
    // this is the equivalent method
    var caexObj_2 = ServiceLocator.QueryService.FindByID (document, internalElement.ID);

    Assert.AreEqual (caexObj_1, caexObj_2);
    Assert.AreEqual (caexObj_1, internalElement);
    return caexObj_1;
}

FindByPath example

using Aml.Engine.Services;
using Aml.Engine.CAEX.Extensions;

// Try to find the referenced SystemUnitClass of an InternalElement.             
CAEXObject FindByPath (CAEXDocument document, InternalElementType internalElement)
{
    // this is a document extension method
    var caexObj_1 = document.FindByPath (internalElement.RefBaseSystemUnitPath);
    // this is the equivalent method
    var caexObj_2 = ServiceLocator.QueryService.FindByPath
        			(document, internalElement.RefBaseSystemUnitPath);

    Assert.AreEqual (caexObj_1, caexObj_2);

    // The InternalElementType contains a property which can be used to get and set the SystemUnitClass
    Assert.AreEqual (caexObj_1, internalElement.SystemUnitClass);
    return caexObj_1;
}

Back To Top

Query class to class relations

Class to Class relations are inheritance relations.

First generation of derived classes

using Aml.Engine.Services;

// get the first generation of derived role classes from the specified role class
void GetDerivedFirstGeneration (RoleFamilyType roleClass)
{
    var derivedClasses = ServiceLocator.QueryService.AllClassReferences (roleClass);
}

All generations of derived classes

using Aml.Engine.Services;

// get the first and all following generations of derived role classes from the specified role class
void GetDerivedFirstGeneration (RoleFamilyType roleClass)
{
    var derivedClasses = ServiceLocator.QueryService.AllClassReferencesDeep (roleClass);
}

Back To Top

Query class to instance relations

A Class to Instance relations is always defined using a ClassPath as a value in any Attribute of a CAEXObject, which is not a class (InternalElement, ExternalInterface, Attribute, RoleRequirement, SupportedRoleClass). You have to either provide a full CAEX path or the CAEX class object itself as a parameter of a query.

ExternalInterface Instances of an InterfaceClass

using Aml.Engine.Services;
using Aml.Engine.AmlObjects;
using Aml.Engine.CAEX;

// Get all ExternalInterfaces, which are ExternalDataConnectors, including those ExternalInterfaces,
// which reference a derived class from an ExternalDataConnector.
// This method is appropriate, to get a collection of external sources.
void GetAllExternalDataConnectorInstances (CAEXDocument document)
{                  
    var externalInterfaces = ServiceLocator.QueryService.AllClassReferencesDeep(document, 
                   	AutomationMLInterfaceClassLib.ExternalDataConnector,
					CAEX_CLASSModel_TagNames.EXTERNAL_INTERFACE);

    foreach (var externalInterface in externalInterfaces)
    {
         var refUriAttribute = ((ObjectWithAMLAttribute)externalInterface).RefURIAttribute;
         if (refUriAttribute != null)
         {
             Console.WriteLine (refUriAttribute.Value);
         }
    }
}

Back To Top

Query instance to instance relations

An Instance to Instance relation is always defined using an InternalLink. The Query Interface contains special queries to explore Instance to Instance Relations.

InternalLinks connected to an ExternalInterface

using Aml.Engine.Services;
using Aml.Engine.AmlObjects;
using Aml.Engine.CAEX;

// Get all InternalLinks, which are attached to an ExternalInterface. 
// This method is appropriate, to get a collection of related ExternalInterfaces.

IEnumerable<ExternalInterfaceType> GetAllRelatedExternalInterfaces(ExternalInterfaceType externalInterface)
{
  var internalLinks = ServiceLocator.QueryService.InternalLinksToInterface(externalInterface);

  // or use the equivalent extension method externalInterface.InternalLinksToInterface();

  foreach (var internalLink in internalLinks)
  {
    if (internalLink.AInterface.Equals(externalInterface)
      yield return internalLink.BInterface;
    else
      yield return internalLink.AInterface;
  }
}

Back To Top

See Also

Reference