TechTalk Genome v4.2

OQL Syntax Guide

OQL syntax roots

Genome provides an object-oriented query language (Object Query Language - OQL) that developers can use to formulate queries against relational database servers. OQL's syntax derives from C# and should therefore be very familiar to any developer experienced with C#, C++ or Java.

OQL introduces a new built-in data type - the Set<T> - which supports effective handling of large sets of data and operations on result sets of data such as Projection, Filtering, Union, Intersection and Subtraction.

Building queries with OQL

Queries in Genome are rarely executed as explicitly against the DataDomain as in traditional SQL applications. Developers in OQL tend to create and manipulate Set<T>s instead and the physical database access occurs implicitly when concrete data is accessed during execution (Sets are lazy loaded). Thus, although sets are formally data types that represent a result set, they are more similar to queries or partial queries in traditional enterprise applications.

OQL provides the language construct Extent that serves as a starting point for any query executed by Genome. The extent of a type is a Set<T> containing all instances of the given type that are stored in the DataDomain.
Queries are usually built by filtering and projecting extents. The result of set operations is usually another Set<T>. Whenever a set is enumerated, the query engine translates all operations performed on the original Extent into the T-SQL language of the underlying relational database server and executes them.

Database platform independence

Since OQL's syntax and semantics do not depend on the underlying relational database server's capabilities, queries formulated in OQL are platform-independent. Therefore the application can be unaware of the underlying physical platform and can access mutliple relational database servers that implement various flavours of SQL without requiring any adaptation of application code or queries.

To introduce a CLR class into Genome, you have to provide translation guidelines about how certain features of the class can be mapped to features of the physical database. This generally includes mapping between fields of the class and database fields and specifying the database table or tables the instances of the given class are stored in, but can go as far as implementing properties or methods of the given class as OQL expressions. This mapping information is compiled into a DataDomain schema by an external tool called the schema compiler .
Since Genome supports different schemas for each DataDomain handled by the system, the application can read the same persistent classes from multiple relational database servers, even if they are stored in a different physical layout, without affecting application code or queries.

These features are certainly useful for system integration development tasks as they ensure complete independence from the underlying database server platform or even the physical structure of the (probably already existing) database.

Client-side OQL

Like SQL, OQL can be expressed in a C# program using string literals that are not parsed by the C# compiler. Both OQL and SQL are parsed and executed during runtime only, which can cause hard-to-detect runtime errors in the application code. However, unlike SQL, OQL is strongly typed, meaning that parameters and expressions are type-checked when Genome parses the query, offering you the same kind of type safety as in C#.
While client-side OQL should be avoided whenever possible for the reasons above by using server-side OQL (see below), client-side OQL is a vital feature in certain scenarios such as dynamic query building.

Server-side OQL

As a unique feature, Genome provides the possibility to also express OQL in the mapping file. Unlike client-side OQL, a server-side OQL statement is parsed during compile time when the schema compiler is executed in the build process, which brings the following benefits:

While client-side OQL is useful for dynamic query building, server-side OQL is typically used to enrich the domain model with query methods and relationships, encapsulating database independent query logic in the business layer.

Syntax differences between client-side and server-side OQL

As described above, OQL can be used on the client-side (e.g. in C# or VB.NET) and on the server-side (in the mapping file). While the semantic possibilities of OQL are the same in both scenarios, there are syntactic differences to be observed. The following reference guide presents the OQL operations supported and gives examples of how to use them on the server side (OQL) or on the client side (C#/VB.NET). It also demonstrates how these operations are translated into SQL.
Please note that any server-side OQL statement can also be expressed on the client-side using DataDomain.Evaluate<S>.


Example

                  
<Type name="Cage">
    ...

    <Member name="OldInhabitants">
      <Oql>
          <![CDATA[ 
            extentof(Animal)[Cage == this && Age>10]
         ]]></Oql>
    </Member>
</Type>
                    
              

                  
public abstract class Cage : Persistent
{
    ...
       
    public Set<Animal> OldInhabitants
    {
        get { return this.DataDomain.Evaluate<Set<Animal>>("extentof(Animal)[Cage == this && Age>10]");
    }
     
    ...
}
                    
              


To mimic server-side OQL syntax in C#, the DataDomain.Extent<S> and the operations supported by the Set<T> were introduced (see also OqlReference.Chapter25).


Example

                    
public abstract class Cage : Persistent
{
    ...
       
    public Set<Animal> OldInhabitants
    {
                                  // extentof(Animal)[Cage == this && Age>10]
        get { return this.DataDomain.Extent<Animal>()["Cage == {0} && Age>10", this];
    }
     
    ...
}
                    
                


Further information about OQL

A full introduction to OQL can be found at the .