Contents
The EMF Model Query framework provides a set of tools to construct and execute
query statements. These query statements provide a client with a uniform way of
discovering and potentially modifying the matching EObjects. Queries are first
constructed with their query clauses and then they are ready to be executed.
[
back to top]
This tutorial assumes that the reader is familiar with EMF and is familiar with
the concept of querying data. A crucial part of understanding EMF is being able
to understand its reflective mechanisms including EClasses
and
EStructuralFeatures
.
For reference, the full
example for this tutorial is available.
[
back to top]
In order to demonstrate EMF Query, we will be making use of the extended library
model (EXTLibrary). This model
is a variant of the standard EMF example model used in many of its tutorials.
For those readers who are not familiar with this model, it describes a library
with books and writers. The most important aspect of the library model for this
tutorial is the fact that books are modeled as EObjects whose EClass is
Book
and they contain an EStructuralFeature called pages
that stores an integer number of pages contained in the book.
The goal of this tutorial is to create an EMF query that will discover which
books contain more than 500 pages. These books are considered "large" books.
[
back to top]
There are two query statements available:
SELECT and
UPDATE.
The SELECT statement provides querying without modification while the UPDATE statement provides
querying with modification. In this case, we require only querying without the modification.
Often times, pseudocode can be used to clarify the function of the query
statement. In EMF query the pseudocode is very close to the code. We will use
pseudocode for now and switch back to the actual code near the end of this
tutorial.
Here is our query so far:
SELECT
FROM [source]
WHERE [condition]
[
back to top]
Every query statement requires some query clauses. The SELECT statement requires
two clauses, a "FROM" and a "WHERE." The former clause
describes the source of EObjects where SELECT can iterate in order to derive
results. The latter clause describes the criteria for an EObject that matches.
The
FROM
clause requires an
EObjectSource.
We will trivially satisfy the FROM clause by providing a collection of EObjects
called selectedEObjects
:
SELECT
FROM selectedEObjects
WHERE [condition]
The FROM clause defaults to hierarchical iteration, which means that for each
EObject in the selectedEObjects collection, the SELECT statement will traverse
its contained EObjects (eContents()
) recursively until it reaches
the leaves of the containment subtree to find its matching EObjects.
[
back to top]
The final part of a SELECT statement is the
WHERE
clause along with its condition. This condition will be evaluated at each
EObject encountered by the FROM clause to determine whether the EObject matches
the criteria of the query. The condition provided to the WHERE clause falls
under a specialized condition called an
EObjectCondition
that is a condition that is specially designed to evaluate an EObject.
Our original purpose for this query is to find book EObjects whose pages are
larger than 500. The pages EStructuralFeature is an EAttribute whose value will
be an integer so we will choose the
EObjectAttributeValueCondition.
Its purpose is to evaluate the value of a specific EAttribute:
SELECT
FROM selectedEObjects
WHERE EObjectAttributeValueCondition
EXTLibraryPackage.eINSTANCE.getBook_Pages()
[inner condition]
[
back to top]
Some conditions will require other conditions in order to perform their
function. This gives clients enough versatility to formulate their queries.
In the case of EObjectAttributeValueCondition, it must be constructed with a
Condition.
Unlike the WHERE clause, it does not require the special EObjectCondition. This
is because EAttributes may store primitive values like Strings, Integers or
Booleans. Our EAttribute "pages" is an Integer EAttribute so we will
use a number condition that will match a range of numerical values:
SELECT
FROM selectedEObjects
WHERE EObjectAttributeValueCondition
EXTLibraryPackage.eINSTANCE.getBook_Pages()
NumberCondition.IntegerValue(500, MAX_VALUE)
Now we have the final pseudo-code representation of the query. The
NumberCondition.IntegerValue
condition will match any Integer between 500 and the maximum integer value
inclusive.
[
back to top]
Since the beginning of the tutorial, we have been operating in pseudocode. When
we translate the pseudocode into EMF Query code we get the following:
statement =
new SELECT(
new FROM(selectedEObjects),
new WHERE(new EObjectAttributeValueCondition(
EXTLibraryPackage.eINSTANCE.getBook_Pages(),
new NumberCondition.IntegerValue(new Integer(500), new Integer(Integer.MAX_VALUE)))
)
)
The
EStructuralFeatureValueGetter
object is explicitly provided to perform the reflective retrieval of the
structural feature value. This object may be substituted in order to provide
more a more optimal way to retrieve this value. In the above example
the default value getter is used although there are other constructors to allow
clients to provide their own.
Every query statement has an execute()
method, which returns back
the collection of matching EObjects.
statement.execute();
For robustness, the executor of the query statement should call the
getException()
on the returned
IQueryResult
of the execute() method in order to verify that no exceptions occurred during
the execution of the query.
[
back to top]
BookCategory category;
/*
* Looking for writers whose authored books of the specified category
*/
EObjectCondition condition = new EObjectReferenceValueCondition(
new EObjectTypeRelationCondition(EXTLibraryPackage.eINSTANCE
.getWriter()), EXTLibraryPackage.eINSTANCE.getWriter_Books(),
new EObjectAttributeValueCondition(EXTLibraryPackage.eINSTANCE
.getBook_Category(), new ObjectInstanceCondition(category)));
// Build the query statement
SELECT statement = new SELECT(
new FROM(selectedEObjects),
new WHERE(condition)
);
// Execute query
return statement.execute();
The above query makes use of the
EObjectReferenceValueCondition
and
EObjectTypeRelationCondition.
The former allows one to evaluate the value of an EReference. In this case, it
is evaluating the value of the books EReference. By default, if the EReference
has a multiplicity larger than 1 this condition will default to a
"ConditionPolicy.ANY," which means that it will match an EObject if
any of its referenced EObjects matches the provided value condition.
Two nested conditions are provided to the EObjectReferenceValueCondition: a
context condition and a value condition. The context condition evaluates against
the container of the EReference while the value condition evaluates against the
referenced EObjects. Notice that both conditions will have to be
EObjectConditions because they will be matching against EObjects.
In the above query, the context condition is an EObjectTypeRelationCondition,
which will ensure that the EObject has a certain EClass (type). The value
condition was chosen to be the EObjectAttributeValueCondition, which will
compare the book's category identity against the chosen category enumeration
literal.
Writer chosenWriter;
String name = chosenWriter.getName();
/*
* Looking for books whose writer name is the specified name
*/
EObjectCondition condition = new EObjectReferenceValueCondition(
new EObjectTypeRelationCondition(EXTLibraryPackage.eINSTANCE.getBook()),
EXTLibraryPackage.eINSTANCE.getBook_Author(),
new EObjectAttributeValueCondition(EXTLibraryPackage.eINSTANCE
.getWriter_Name(), new StringValue(name)));
// Build the select query statement
SELECT statement = new SELECT(
new FROM(chosenWriter.eResource().getContents()),
new WHERE(condition));
This query is similar in structure to the previous example. The differences are
that the context condition is checking that the container of the EReference is
a book and the author of the book has a value name
for the name
EAttribute.
[
back to top]
In this tutorial, we did the following:
- Developed a query statement in pseudocode.
- Satisfied the query statement and its clauses.
- Used a nested condition to evaluate the value of an EAttribute.
- Executed the query to produce the results.
- Checked to ensure that the query did not generate any exceptions during its execution.
- Analyzed some more sophistocated queries.
[
back to top]
Copyright (c) 2000, 2007 IBM Corporation and others. All Rights Reserved.