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.
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.
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.
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.
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:
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]");
}
...
}
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];
}
...
}
A full introduction to OQL can be found at the .