<query>
<query-method>
<method-name></method-name>
<method-params>
<method-param></method-param>
</method-params>
</query-method>
<result-type-mapping></result-type-mapping>
<ejb-ql></ejb-ql>
</query>
Nazwa metody to <method-name>, natomiast jej parametry to
<method-params>.
<result-type-mapping> określa zwracany typ i może zawierać wartości lokalne (Local), bądź zdalne (Remote).
Tag <ejb-ql> zawiera natomiast treść samego zapytania.
Oto przykładowy model:

Zamówienie (Order) posiada adres (Address) i składa się z wielu pozycji(LineItem), każda z nich dotyczy jednego produktu (Product).
Relacje w deskryptorze wdrożeniowym są zadeklarowane w następujący sposób:
<relationships>
<!--
JEDEN-DO-WIELE: Order
LineItem pozycje wchodzące w skład zamówienia
-->
<ejb-relation>
<ejb-relation-name>Order-LineItem</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>
order-has-lineitems zamówienie posiada pozycje
</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>OrderEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>lineItems</cmr-field-name>
<cmr-field-type>java.util.Collection
</cmr-field-type>
</cmr-field>
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>lineitem-belongsto-order pozycja dotyczy konkretnego zamówienia
</ejb-relationship-role-name>
<multiplicity>Many</multiplicity>
<cascade-delete/>
<relationship-role-source>
<ejb-name>LineItemEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>order</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
<!--
JEDEN-DO-WIELE
relacja jednostronna:
Product nie jest świadomy swojego powiązania z
LineItem zależność pozycji z produktem
-->
<ejb-relation>
<ejb-relation-name>Product-LineItem</ejb-relation-name>
<ejb-relationship-role>
<ejb-relationship-role-name>product-has-lineitems</ejb-relationship-role-name>
<multiplicity>One</multiplicity>
<relationship-role-source>
<ejb-name>ProductEJB</ejb-name>
</relationship-role-source>
<!--
since Product does not know about LineItem there is no cmr field in
Product for accessing Lineitem
-->
nie ma taga cmr-field bo produkt nie wie o pozycji która mu odpowiada
</ejb-relationship-role>
<ejb-relationship-role>
<ejb-relationship-role-name>lineitem-for-product</ejb-relationship-role-name> pozycja dotyczy produktu
<multiplicity>Many</multiplicity>
<relationship-role-source>
<ejb-name>LineItemEJB</ejb-name>
</relationship-role-source>
<cmr-field>
<cmr-field-name>product</cmr-field-name>
</cmr-field>
</ejb-relationship-role>
</ejb-relation>
</relationships>
Address <-> Order).
public interface OrderHome extends
javax.ejb.EJBHome {
...
public
Order findByPrimaryKey(int orderId) throws
FinderException,RemoteException; zwraca pojedynczy obiekt
public Order
findByBiggestOrder() throws FinderException,RemoteException;
public
java.util.Collection findAllOrders(String supplierName) zwraca kolekcję
throws
FinderException,RemoteException;
}
public
interface OrderHome extends javax.ejb.EJBLocalHome
{
...
public Order
findByPrimaryKey(int orderId) throws
FinderException; zwraca pojedynczy obiekt
public Order findBiggestOrder() throws
FinderException;
public java.util.Collection findAllOrders(String
supplierName) zwraca kolekcję
throws FinderException;
}
ejbSelect<METHOD>
ejbSelect<METHOD>InEntityPrzykład:
public abstract class OrderBean implements javax.ejb.EntityBean
{
...
public abstract java.util.Collection
ejbSelectAllOrderedProducts(Date date) metoda ogólna
throws
FinderException;
...
public abstract java.util.Collection
ejbSelectAllOrderedProductsInEntity(Date date) metoda związana z konkretną instancją
throws
FinderException;
}
Metody postaci ejbSelect<METHOD> nie są związane z
konkrtną instacją ziarna encyjnego. W powyższym przykładzie
ejbSelectAllOrderProducts zwraca kolekcję wszystkich produktów (Product) związanych
z wszystkimi zamówieniami (Order). Natomiast metody postaci
ejbSelect<METHOD>InEntity są związane z konretną instancją obiektu encyjnego. Powyższa metoda
ejbSelectAllOrderProductsInEntity zwraca wszystkie produkty, ale związane tylko z tą instancją
OrderBean w której została wywołana.
EJB QL ::= select_clause from_clause [where_clause]
from_clause ::= FROM identification_variable_declaration
[, identification_variable_declaration]*
identification_variable_declaration ::=
collection_member_declaration |
range_variable_declaration
collection_member_declaration ::=
IN (collection_valued_path_expression) [AS] identifier
range_variable_declaration ::=
abstract_schema_name [AS] identifier
single_valued_path_expression ::=
{single_valued_navigation |
identification_variable}.cmp_field |
single_valued_navigation
single_valued_navigation ::=
identification_variable.[single_valued_cmr_field.]*
single_valued_cmr_field
collection_valued_path_expression ::=
identification_variable.[single_valued_cmr_field.]*
collection_valued_cmr_field
select_clause ::= SELECT [DISTINCT]
{single_valued_path_expression |
OBJECT(identification_variable)}
where_clause ::= WHERE conditional_expression
conditional_expression ::= conditional_term |
conditional_expression OR conditional_term
conditional_term ::= conditional_factor |
conditional_term AND conditional_factor
conditional_factor ::= [ NOT ] conditional_test
conditional_test ::= conditional_primary
conditional_primary ::=
simple_cond_expression | (conditional_expression)
simple_cond_expression ::=
comparison_expression |
between_expression |
like_expression |
in_expression |
null_comparison_expression |
empty_collection_comparison_expression |
collection_member_expression
between_expression ::=
arithmetic_expression [NOT] BETWEEN
arithmetic_expression AND arithmetic_expression
in_expression ::=
single_valued_path_expression
[NOT] IN (string_literal [, string_literal]* )
like_expression ::=
single_valued_path_expression
[NOT] LIKE pattern_value [ESCAPE escape-character]
null_comparison_expression ::=
single_valued_path_expression IS [NOT] NULL
empty_collection_comparison_expression ::=
collection_valued_path_expression IS [NOT] EMPTY
collection_member_expression ::=
{single_valued_navigation | identification_variable |
input_parameter}
[NOT] MEMBER [OF] collection_valued_path_expression
comparison_expression ::=
string_value { =|<>} string_expression |
boolean_value { =|<>} boolean_expression} |
datetime_value { = | <> | > | < } datetime_expression |
entity_bean_value { = | <> } entity_bean_expression |
arithmetic_value comparison_operator
single_value_designator
arithmetic_value ::= single_valued_path_expression |
functions_returning_numerics
single_value_designator ::= scalar_expression
comparison_operator ::=
= | > | >= | < | <= | <>
scalar_expression ::= arithmetic_expression
arithmetic_expression ::= arithmetic_term |
arithmetic_expression { + | - } arithmetic_term
arithmetic_term ::= arithmetic_factor |
arithmetic_term { * | / } arithmetic_factor
arithmetic_factor ::= { + |- } arithmetic_primary
arithmetic_primary ::= single_valued_path_expression |
literal | (arithmetic_expression) |
input_parameter | functions_returning_numerics
string_value ::= single_valued_path_expression |
functions_returning_strings
string_expression ::= string_primary | input_expression
string_primary ::= single_valued_path_expression | literal |
(string_expression) | functions_returning_strings
datetime_value ::= single_valued_path_expression
datetime_expression ::= datetime_value | input_parameter
boolean_value ::= single_valued_path_expression
boolean_expression ::= single_valued_path_expression |
literal | input_parameter
entity_bean_value ::=
single_valued_navigation | identification_variable
entity_bean_expression ::= entity_bean_value | input_parameter
functions_returning_strings ::=
CONCAT(string_expression, string_expression) |
SUBSTRING(string_expression, arithmetic_expression,
arithmetic_expression)
functions_returning_numerics::=
LENGTH(string_expression) |
LOCATE(string_expression,
string_expression[, arithmetic_expression]) |
ABS(arithmetic_expression) |
SQRT(arithmetic_expression)
from_clause ::= FROM identification_variable_declaration [, identification_variable_declaration]*identification_variable_declaration ::= collection_member_declaration | range_variable_declarationcollection_member_declaration ::= IN (collection_valued_path_expression) [AS] identifier range_variable_declaration ::= abstract_schema_name [AS] identifier
ANDAS BETWEENDISTINCTEMPTYFALSEFROMINIS LIKE |
MEMBERNOTNULLOBJECTOFORSELECTTRUEUNKNOWNWHERE |
FROM, które mogą być oczywiście używane także przez klauzule WHERE oraz SELECT.
Ponieważ te zmienne są identyfikatorami, obejmują je restrykcje ich dotyczące. Dodatkowo nie mogą być identyczne z nazwami ziaren encyjnych EJB oraz zadeklarowanych abstrakcyjnych schematów.
SELECT OBJECT(o) FROM Order o, IN (o.lineItems) li
WHERE
li.product.product_type='Floppy Drive'
o, oraz li. o to zmienna odpowiadająca zamówienion, a li oznacza kolekcję lineItems dotyczącą pozycji zamówienia o.
Zmienna o odpowiada abstakcyjnemu typowi ze schematu, podobnie li oraz li.product - tak będzie można dostać się do produktu odpowiadającego pozycji zamówienia.OBJCECT w klauzuli SELECT określa że o jest obiektem, a nie na przykład klasą java.lang.String - która byłaby zwracana gdyby klauzula ta miała postać:
SELECT li.product.product_type ...
single_valued_path_expression ::=
{single_valued_navigation |
identification_variable}.cmp_field |
single_valued_navigation
single_valued_navigation ::=
identification_variable.[single_valued_cmr_field.]*
single_valued_cmr_field
collection_valued_path_expression ::=
identification_variable.[single_valued_cmr_field.]*
collection_valued_cmr_field
cmp-field odpowiadają utrwalanym polom ziaren EJB, a cmr-field odpowiadają relacjom zdefiniowanym w deskryptorze wdrożeniowym.
Wyrażenia ścieżkowe w łatwy sposób umożliwiają przechodzenie po powiązanych ze sobą ziarnach.
Wyrażenia mogą być więc trzech typów
Klauzulawhere_clause ::= WHERE conditional_expression
Mogą występować konstrukcje dobrze znane ze składni SQL:conditional_expression ::= conditional_term | conditional_expression OR conditional_term conditional_term ::= conditional_factor | conditional_term AND conditional_factor conditional_factor ::= [ NOT ] conditional_test conditional_test ::= conditional_primary conditional_primary ::= simple_cond_expression | (conditional_expression) simple_cond_expression ::= comparison_expression | between_expression | like_expression | in_expression | null_comparison_expression | empty_collection_comparison_expression | collection_member_expression
BETWEEN, IN, LIKE, porównywanie do NULL.
A także sprawdzanie czy kolekcja jest pusta (EMPTY) bądź też - czy zawiera dany element (MEMBER OF).
Wartośći typu NULL powstają jeżeli referencja nie wskazuje obiektu utrwalonego w bazie. Semantyka tej wartości jest taka sama jak zwykłego NULL w SQL. Podobnie jest, jeśli chodzi o porównywanie wartości określonych i nieokreślonych.
Priorytety operatorów są oczywiście również takie same jak w SQL:
| Typ |
Porządek |
|---|---|
| Nawigacyjny |
. (kropka
w wyrażeniu ścieżkowym) |
| Arytmetyczny |
+ -
(unarne)* /
(mnożenie i dzielenie)+ - (dodawanie i odejmowanie) |
| Porównywanie |
=>>=<<=<> (różne od) |
| Logiczne |
NOT
AND
OR |
SELECT OBJECT (li) FROM lineItems AS li
WHERE li.quantity NOT BETWEEN 100 and 200
SELECT OBJECT (li) FROM lineItems AS li
WHERE li.quantity < 100 AND li.quantity > 200
TRUE i FALSE.
public abstract class OrderBean implements javax.ejb.EntityBean
{
...
//method-a
public abstract java.util.Collection
ejbSelectLineItems(int quantity) parametr przekazywany
throws
FinderException;
...
SELECT OBJECT (o) FROM Order AS o IN (o.lineItems) li
WHERE
li.quantity = ?1
<query>
<description>
Method to
find order specified no of
lineItems</description>
<query-method>
<method-name>ejbSelectLineItems</method-name>
<method-params>
<method-param>int</method-param>
</method-params>
</query-method>
<result-type-mapping>Local</result-type-mapping>
<ejb-ql>
SELECT
OBJECT (o) FROM Order AS o IN (o.lineItems) li
WHERE li.quantity =
?1
</ejb-ql>
</query>
//method-b
public abstract
java.util.Collection ejbSelectAllProducts(String product_type, double
price) parametry przekazywane
throws FinderException;
}
SELECT OBJECT (o) FROM Order AS o IN(o.lineItems) li
WHERE
li.product.product_type=?1 AND li.product.price=?2
EJB QL zawiera kilka wbudowanych operacji na obiektach klasy String i innych prostych typach,
na przykład
Funkcje obsługujące String:
CONCAT (String, String) Łączy dwa napisy
SUBSTRING (String, start, length) Zwraca podciąg
LOCATE (String, String [, start]) Pozycja podciągu w napisie
LENGTH (String) Długość napisuFunkcje arytmetyczne:
select_clause ::= SELECT [DISTINCT]
{single_valued_path_expression |
OBJECT(identification_variable)}
Oczywiście typ zwracanej wartości, jak to już było wspomniane, musi odpowiadać typowi odpowiedniej metody wyszukującej lub selekcjonującej.
public Collection findAll() throws FinderException;
Zapytanie
findall zwraca kolekcję obiektów relizująch interejs zamówien (LocalOrder)
:
SELECT OBJECT(o) FROM Order o
SELECT NIE MOŻE zwracać wartości będącej kolekcją gdyż z jej specyfiki wynika to że zwraca wszystkie obiekty zgodne z klauzulami FROM i WHERE.
SELECT o.lineItems FROM Order As o tak jest źleSELECT OBJECT(li) FROM Order As o, IN(o.lineItems) li tak jest dobrze. W tym drugim przypadku, wybierane są poszczególne obiekty z kolekcji, a nie całe kolekcje.
DISTINCT eliminuje powtarzające się elementy. Jednak java.util.Set sam z siebie je
eliminuje, dlatego zasadne jest używanie DISTINCT tylko w przypadku metod zwracających np. java.util.Collection.
OBJECT poprzedza pojedyncze wystąpienia zmiennych, to znaczy nie będące wyrażeniami ścieżkowymi.
| J2EE tutorial | Tutorial J2EE: EJBQL |
| Learning EJBQL | O'Reilly Network: learning EJB-QL |
| EJB-QL World | EJB-QL World The place for Enterprise JavaBeans answers |
| Differences between EJB1.1 and EJB2.0 | Differences between EJB1.1 and EJB2.0: EJB-QL |