User: dsundstrom Date: 01/09/18 11:14:06 Added: src/xdocs/howto howtocmp2.xml Log: Added CMP 2.x documentation. Revision Changes Path 1.1 manual/src/xdocs/howto/howtocmp2.xml Index: howtocmp2.xml =================================================================== <section id="cmp-2.0-quick-docs" lang="en"> <title>CMP 2.0 [JBoss 3.0]</title> <para>Author:<author> <firstname>Dain</firstname> <surname>Sundstrom</surname> </author> <email>[EMAIL PROTECTED]</email> </para> <section id="activate-cmp-2.0"> <title>Activate CMP 2.0</title> <section id="change-ejb-jar.xml-doctype"> <title>Change ejb-jar.xml doctype</title> <para> CMP 2.0 is only available to Entity Beans in an EJB 2.0 jar files. An EJB 2.0 jar is identified by the doctype of the ejb-jar.xml file. The correct doctype follows: </para> <programlisting><![CDATA[ <!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd"> ]]></programlisting> </section> <section id="add-jbosscmp-jdbc.xml"> <title>Add jbosscmp-jdbc.xml</title> <para> The optional configuration information for JBossCMP-JDBC is contained in the jbosscmp-jdbc.xml. This file is located in the META-INF directory of the EJB jar. </para> </section> </section> <section id="container-managed-persistence-fields"> <title>Container Managed Persistence Fields (CMP Fields)</title> <section id="abstract-accessors"> <title>Abstract accessors</title> <para> Each CMP field is declared in the entity bean class with a set of abstract accessors. For example, to declare the string CMP field foo, add the following to the entity bean class: </para> <programlisting><![CDATA[ public abstract String getFoo(); public abstract void setFoo(String foo); ]]></programlisting> <note><para> Each field is required to have both a getter and a setter. </para></note> </section> <section id="declare-each-field-in-ejb-jar.xml"> <title>Declare each field in ejb-jar.xml</title> <para> The declaration of a CMP field in the ejb-jar.xml file has not changed in EJB 2.0. For example, to declare the field foo, add the following line to the entity section of the ejb-jar.xml file: </para> <programlisting><![CDATA[ <cmp-field><field-name>foo</field-name></cmp-field> ]]></programlisting> </section> <section id="cmp-field-mapping"> <title>CMP Field Mapping</title> <para> The basic declaration of the CMP field mapping has not changed in JBossCMP-JDBC. For example, to declare that the foo field should be stored in the column foo_col, you would add the following to the entity section of the jbosscmp-jdbc.xml file: </para> <programlisting><![CDATA[ <cmp-field> <field-name>foo</field-name> <column-name>foo_col</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(50)</sql-type> </cmp-field> ]]></programlisting> <para> The last two elements, jdbc-type and sql-type, are optional. That is optional as a group; if you have one you must have the other. The jdbc-type element defines the jdbc type used to set the value of this field in a prepared statement (see java.sql.PreparedStatement#setObject(int, java.lang.Object, int)). The possible values for jdbc-type are defined in the class java.sql.types. The sql-type element is used by JBossCMP-JDBC for the SQL CREATE TABLE statement generated during auto-table creation. </para> </section> <section id="dependent-value-class-mapping"> <title>Dependent value Class Mapping</title> <para> A Dependent Value Class (DVC) is defined as any java class that is the type of a CMP fields, other then the automatically recognized types. See section 10.3.3 of EJB2.0 pfd2 for further requirements. By default a DVC is serialized and stored in a single database column. JBossCMP-JDBC supports the storage of the internal data of a DVC into one or more columns. </para> <note><para> Dependent value classes are not the same thing as dependent value objects which were defined in EJB 2.0 pfd1. </para></note> <para> A DVC that will be mapped must follow the Java Beans naming specification for getters and setters. Each property that will be stored in the database must have both a getter and a setter. The bean must be serializable and must have a no-arg constructor. The properties may be another DVC or any EJB automatically recognized type, but not an EJB. </para> <para> The declaration of an address DVC and a credit card DVC follows: </para> <programlisting><![CDATA[ <dependent-value-classes> <dependent-value-class> <description>address information</description> <class>com.hypothermic.example.cd.Address</class> <property> <property-name>line1</property-name> <column-name>LINE1</column-name> </property> <property> <property-name>line2</property-name> <column-name>LINE2</column-name> </property> <property> <property-name>city</property-name> <column-name>CITY</column-name> </property> <property> <property-name>state</property-name> <column-name>ST</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(2)</sql-type> </property> <property> <property-name>zip</property-name> </property> <property> <property-name>zipPlusFour</property-name> <column-name>ZIP_4</column-name> </property> </dependent-value-class> <dependent-value-class> <description>Credit Card</description> <class>com.hypothermic.example.cd.Card</class> <property> <property-name>cardHolder</property-name> <column-name>CARD_HOLDER</column-name> </property> <property> <property-name>billingAddress</property-name> <column-name>ADD</column-name> </property> <property> <property-name>cardNumber</property-name> <column-name>CARD_NUMBER</column-name> </property> </dependent-value-class> </dependent-value-classes> ]]></programlisting> <para> Each DVC is declared with a dependent-value-class element. A DVC is identified by class type, and this type is declared in the class entity. Each property to be persisted is declared with a property element. This specification is based on the entity element, so it should be self-explanatory. </para> <para> The dependent-value-classes section defined the internal structure and default mapping of the classes. When JBossCMP-JDBC encounters a field that has an unknown type, it searches the list of registered DVC, and if a DVC is found, it persist this field into a set of columns, otherwise the field is stored in serialized form in single column. A DVC can be constructed from other DVC and so on, so when JBossCMP-JDBC runs into a DVC it flattens the DVC tree structure it into a set of columns. If the manager finds a DVC circuit, it will throw an EJBException. The default column name of a property is the column name of the base CMP field followed by an underscore and then the property column name. If the property is a DVC the process it repeated. For example, Card type a field named cc will have the following columns: </para> <programlisting><![CDATA[ cc_CARD_HOLDER cc_ADD_LINE1 cc_ADD_LINE2 cc_ADD_CITY cc_ADD_ST cc_ADD_zip cc_ADD_ZIP_4 cc_CARD_NUMBER ]]></programlisting> <para> The default mappings of columns can be overridden in the entity element as follows: </para> <programlisting><![CDATA[ <entity> <name-name>CustomerBean</name-name> <table-name>CUSTOMER</table-name> <cmp-field> <field-name>userId</field-name> <column-name>USER_ID</column-name> </cmp-field> <cmp-field> <field-name>creditCard</field-name> <column-name>CREDIT_CARD</column-name> <property> <property-name>cardNumber</property-name> <column-name>CC_NUM</column-name> <jdbc-type>VARCHAR</jdbc-type> <sql-type>VARCHAR(20)</sql-type> </property> <property> <property-name>billingAddress.line1</property-name> <column-name>ADDRESS_LINE1</column-name> </property> </cmp-field> </entity> ]]></programlisting> <para> When overriding property info in the entity, you need to refer to the property from a flat perspective as in billingAddress.line1 above. </para> </section> <section id="eager-loading"> <title>Eager loading</title> <para> The new eager-load element is declared after your cmp-field elements in the entity section. Eager load tells the store manager which fields to load when loading your bean from the database. In CMP 1.x every field in the bean was eager loaded, and this is the default if eager-load is not specified. The XML follows: </para> <programlisting><![CDATA[ <eager-load> <field-name>title</field-name> <field-name>artist</field-name> </eager-load> ]]></programlisting> <para> This tells the manager to only load the title and artist fields. In addition to these two fields, the manager always loads the primary key fields. If you would like to not eager-load any fields, just specify an empty eager-load element. In the future I plan on adding a similar section to the query metadata. </para> </section> <section id="lazy-load-groups"> <title>Lazy load groups</title> <para> Lazy loading is the other half of eager loading. If a field is not eager loaded it must be lazy loaded. Lazy loaded fields are organized into groups. When the bean accesses an unloaded field, the manager loads the field and any field in a group that the unloaded field is a member. The manager performs a set join and then removes any field that is already loaded. The lazy-load-groups element should follow the eager-load element in the entity. An example follows: </para> <programlisting><![CDATA[ <lazy-load-groups> <lazy-load-group> <field-name>type</field-name> <field-name>notes</field-name> </lazy-load-group> <lazy-load-group> <field-name>notes</field-name> <field-name>producer</field-name> </lazy-load-group> </lazy-load-groups> ]]></programlisting> <para> When the bean calls getType(), the manager loads type and notes (assuming notes is not already loaded). When the bean called getNotes, the manager will load notes, type and producer. </para> </section> <section id="read-only-columns"> <title>Read-only columns</title> <para> Jaws supported read-only beans with a read-only and time-out elements in the entity element. In JBossCMP-JDBC this has been extended to field level with the addition of the read-only and time-out elements to cmp-field. These elements work the same way as they do in the entity tag. If a field is read-only, it will not be stored in or inserted into the database. If a pk field is read-only, the create method will throw a CreateException. If a set accessor is called for a read-only field, it throws an EJBException. Read-only fields are useful for fields that are filled in by database triggers, such as last update. </para> </section> </section> <section id="container-managed-relationships"> <title>Container Managed Relationships (CMR)</title> <section id="cmr-abstract-accessors"> <title>CMR abstract accessors</title> <para> At least one of the two entities in a relationship must have a CMR field abstract accessor. The signature of a CMR field abstract accessor is similar to a CMP abstract accessor, except the type must be Collection, Set or the local interface of the related entity. For example, to declare a relationship between Order and LineItem, add the following to the Order bean class: </para> <programlisting><![CDATA[ public abstract Set getLineItems(); public abstract void setLineItems(Set lineItems); ]]></programlisting> <para> and add the following to the LineItem bean class: </para> <programlisting><![CDATA[ public abstract OrderLocal getOrder(); public abstract void setOrderLocal(OrderLocal orderLocal); ]]></programlisting> <para> Although only one of the above declarations is required, each CMR field must have both a getter and a setter. </para> </section> <section id="declare-relationship-in-ejb-jar.xml"> <title>Declare relationship in ejb-jar.xml</title> <para> Relationships are declared in the top-level relationships section of the ejb-jar.xml file. An ejb-relation is composed of two ejb-relationship-role elements. An ejb-relationship-role must always have a relationship-role-source and a multiplicity. The role source contains the ejb-name of the entity that has this role. A role can either have a multiplicity of one or many. The multiplicity is many if the other side of the relationship has a cmr-field that is collection valued (type java.util.Collection or java.util.Set), otherwise it has a multiplicity of one. If the entity has a set of abstract accessors for the relationship, the cmr-field must be declared in the ejb-relationship-role element. Additionally, if the cmr-field is collection valued, the cmr-field-type must be declared. Finally, a role can be set to cascade-delete. Cascade deletion is only allowed for a role where the other side of the relation has a multiplicity of one. If cascade delete is enabled for the role, when the parent related entity is deleted the child entity is also deleted. The declaration for the relationship between Order and LineItem follows: </para> <programlisting><![CDATA[ <relationships> <ejb-relation> <ejb-relation-name>Order-LineItem</ejb-relation-name> <ejb-relationship-role> <ejb-relationship-role-name>order-has-lineitems</ejb-relationship-role-name> <relationship-role-source> <ejb-name>OrderEJB</ejb-name> </relationship-role-source> <multiplicity>One</multiplicity> <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</ejb-relationship-role-name> <relationship-role-source> <ejb-name>LineItemEJB</ejb-name> </relationship-role-source> <multiplicity>Many</multiplicity> <cascade-delete/> <cmr-field> <cmr-field-name>order</cmr-field-name> </cmr-field> </ejb-relationship-role> </ejb-relation> </relationships> ]]></programlisting> </section> <section id="relationship-mapping"> <title>Relationship Mapping</title> <para> Relationships can be mapped either a using a foreign key or separate relationship table. One-to-one and one-to-many use the foreign key mapping style by default, and many-to-many can only use the relation table mapping style. The mapping style that a relationship used can be declared in the relationships section or the jbosscmp-jdbc.xml file. Relationships are identified by the ejb-relation-name from the ejb-jar.xml file. The beginning of the relationship mapping declaration for Order-LineItem follows: </para> <programlisting><![CDATA[ <relationships> <ejb-relation> <ejb-relation-name>Order-LineItem</ejb-relation-name> ... </ejb-relation> </relationships> ]]></programlisting> <section id="foreign-key-mapping"> <title>Foreign Key Mapping</title> <para> Foreign key mapping is the most common mapping style for one-to-one and one-to-many relationships. The complete foreign key mapping for Order-LineItem follows: </para> <programlisting><![CDATA[ <relationships> <ejb-relation> <ejb-relation-name>Order-LineItem</ejb-relation-name> <foreign-key-mapping> <ejb-relationship-role> <ejb-relationship-role-name>order-has-lineitems</ejb-relationship-role-name> <foreign-key-fields/> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>lineitem-belongsto-order</ejb-relationship-role-name> <foreign-key-fields> <foreign-key-field> <field-name>orderId</field-name> <column-name>ORDER_ID</column-name> </foreign-key-field> </foreign-key-fields> </ejb-relationship-role> </foreign-key-mapping> </ejb-relation> </relationships> ]]></programlisting> <para> As you can see, the mapping style is declared by adding the foreign-key-mapping element to the relationship. This element contains the mapping information for the two individual roles. If exact field level mapping is not desired, just leave the foreign-key-mapping element empty. Each role is identified by ejb-relationship-role-name, and each ejb-relationship-role can contain a foreign-key-fields element. If no foreign key fields are desired for the role, this element is left empty, as in order-has-lineitems. Otherwise, the foreign-key-fields element contains one or more foreign-key-field elements. The foreign-key-field element uses the same syntax as the cmp-field element of entity. The only important note is the field-name element must match the field-name of one of the primary key fields of the related element. In the example above, the lineitem role has a foreign key for the orderId of the order entity. </para> <para> The foreign-key-mapping style is only allowed for one-to-one and one-to-many relationships. In one-to-one relationships one or both roles can have foreign keys. In one-to-man relationships only the many side of the relationship can have foreign keys. </para> <para> The foreign-key-mapping is not dependent on the directionality of the relationship. This means that in a one-to-one unidirectional relationship (only one side has an accessor) one or both roles can still have foreign keys. </para> </section> <section id="relation-table-mapping"> <title>Relation Table Mapping</title> <para> Relation table mapping is less common for one-to-one and one-to-many relationships, but is the only mapping style allowed for many-to-many relationships. The complete relation table mapping for Order-LineItem follows: </para> <programlisting><![CDATA[ <relationships> <ejb-relation> <ejb-relation-name>Order-LineItem</ejb-relation-name> <table-mapping> <table-name>ORDER_LINEITEM</table-name> <create-table>true</create-table> <remove-table>true</remove-table> <ejb-relationship-role> <ejb-relationship-role-name>order-has-lineitems</ejb-relationship-role-name> <table-key-fields> <table-key-field> <field-name>orderId</field-name> <column-name>ORDER_ID</column-name> </table-key-field> </table-key-fields> </ejb-relationship-role> <ejb-relationship-role> <ejb-relationship-role-name>lineitem-belongsto-order</ejb-relationship-role-name> <table-key-fields> <table-key-field> <field-name>lineItemId</field-name> <column-name>LINEITEM_ID</column-name> </table-key-field> </table-key-fields> </ejb-relationship-role> </table-mapping> </ejb-relation> </relationships> ]]></programlisting> <para> The table-mapping is quite similar to the foreign-key-mapping element, and only the differences will be documented. In the table-mapping element the table-name can be declared along with the other table options. The table options are same table options available for entities. Roles in a table-mapping have table-key-fields like the foreign-key-mapping has foreign-key fields. Unlike a foreign key field which map the primary keys of the related role, table-key-fields map the primary key of the current role. For example, the order role has an orderId table-key-field and the lineitem role has a field for lineItemID. Table mappings must map the primary keys of both entities in the relationship, which is different from the foreign key mapping where only one role must have a mapping. </para> </section> </section> </section> <section id="ejb-ql"> <title>EJB-QL</title> <para> EJB-QL is a new J2EE platform independent way to specify finders and ejbSelect methods in CMP 2.0. Finders have not changed in CMP 2.0, but ejbSelect methods are new. The ejbSelect method is designed to provide private query statements to an entity implementation. </para> <section id="declare-finder-or-ejbselect"> <title>Declare Finder or ejbSelect</title> <para> Finders are still declared in the home interface of the entity, except finders no longer throw a RemoteException. The following code declares a finder: </para> <programlisting><![CDATA[ public Collection findWithStatus(String status) throws FinderException; ]]></programlisting> <para> The select methods are declared in the entity implementation class, and are also abstract like cmp and cmr accessors. The following code declares an ejbSelect method: </para> <programlisting><![CDATA[ public abstract Set ejbSelectOrdersShippedToCA() throws FinderException; ]]></programlisting> </section> <section id="declare-ejb-ql-in-ejb-jar.xml"> <title>Declare EJB-QL in ejb-jar.xml</title> <para> Every finder or ejbSelect method is required to have an ejb-ql query defined in the ejb-jar.xml file. The ejb-ql is declared in a query element, which is contained in the entity element. The following is the declaration for the above queries: </para> <programlisting><![CDATA[ <entity> <ejb-name>OrderEJB</ejb-name> ... <query> <description>Search for all orders shipped to CA</description> <query-method> <method-name>ejbSelectOrdersShippedToCA</method-name> <method-params> </method-params> </query-method> <ejb-ql> SELECT OBJECT(o) FROM Order o WHERE o.shippingAddress.state = 'CA' </ejb-ql> </query> <query> <description>Find all orders with the specified status</description> <query-method> <method-name>findWithStatus</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <ejb-ql> SELECT DISTINCT OBJECT(o) FROM Order o WHERE c.status=?1 </ejb-ql> </query> </entity> ]]></programlisting> <para> There are some important things to note about EJB-QL. </para> <para> EJB-Ql is a typed language, and only allows comparison of like types, which means that strings can only be compared with strings. </para> <para> EJB-QL is similar to SQL but has some suprising differences. For example, in an equals comparison a variable must be on the left hand side. Some examples follow: </para> <informalexample><![CDATA[ p.name = 'Name' is legal 'Name' = p.name is not legal 'Name' = 'Name' is not legal ]]></informalexample> <caution><para> The IS EMPTY opperaor is not available for MySQL and mSQL, but the IS NOT EMPTY operator is available. The is because MySQL and mSQL do not support the EXISTS clause. In the future it will be possible to map IS EMPTY to a LEFT OUTER JOIN which MySQL supports. Unfortunately mSQL does not support either of these possible mappings, so mSQL will not be able to use IS EMPTY. </para></caution> </section> <section id="function-mapping"> <title>Function Mapping</title> <para> EJB-QL contains six functions: ABS, CONCAT, SUBSTRING, LOCATE, LENGTH, AND SQRT. By default these functions are mapped to JDBC sql extension scalar functions. For example, CONCAT('Hot', 'Java') would map to {fn concat('Hot', 'Java')}. Several of the major database vendors don't support this style of functions in an effort to lock users into their database. The mapping for these functions can be overridden in the jbosscmp-jdbc.xml file by adding function-mapping elements to the type-mapping element. The following is an example of the concat function mapping for oracle. </para> <programlisting><![CDATA[ <type-mapping> <name>Oracle8</name> <function-mapping> <function-name>concat</function-name> <function-sql>(?1 || ?2)</function-sql> </function-mapping> </type-mapping> ]]></programlisting> </section> <section id="ejb-ql-to-sql-mapping-in-jbosscmp-jdbc.xml"> <title>EJB-QL to SQL mapping in jbosscmp-jdbc.xml</title> <para> The EJB-QL to SQL mapping can be overridden in the jbosscmp-jdbc.xml file. The finder or ejbSelect is required to have a query method in the ejb-jar.xml file, but the SQL generated can be completely changed. Overridden queries are specified as follows: </para> <programlisting><![CDATA[ <entity> <query> <description>Find all orders with the specified status</description> <query-method> <method-name>findWithStatus</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <!-- sql here --> </query> </entity> ]]></programlisting> <section id="declared-sql"> <title>Declared SQL</title> <para> Declared SQL is implemented similar to JAWS, except the from and where clauses have been broken up. </para> <programlisting><![CDATA[ <query> <description>Find all orders with the specified status</description> <query-method> <method-name>findWithStatus</method-name> <method-params> <method-param>java.lang.String</method-param> </method-params> </query-method> <declared-sql> <where>STATUS={0}</where> <order>ORDER_NUMBER</order> </declared-sql> </query> ]]></programlisting> </section> </section> </section> </section> _______________________________________________ Jboss-development mailing list [EMAIL PROTECTED] https://lists.sourceforge.net/lists/listinfo/jboss-development