<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>InEntity
Przykł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
AND AS BETWEEN DISTINCT EMPTY FALSE FROM IN IS LIKE |
MEMBER NOT NULL OBJECT OF OR SELECT TRUE UNKNOWN WHERE |
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 ...
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ówsingle_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
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:
Oczywiście typ zwracanej wartości, jak to już było wspomniane, musi odpowiadać typowi odpowiedniej metody wyszukującej lub selekcjonującej.select_clause ::= SELECT [DISTINCT] {single_valued_path_expression | OBJECT(identification_variable)}
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 |