From 6a2d5753821bba8a1adbe510a07a3bb4293b980b Mon Sep 17 00:00:00 2001 From: Hardy Ferentschik Date: Wed, 14 Jul 2010 19:31:59 +0000 Subject: [PATCH] HHH-5379 Added CascadeTypes for annotations git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19954 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../docbook/en-US/content/session_api.xml | 1831 ++++++++--------- 1 file changed, 871 insertions(+), 960 deletions(-) diff --git a/documentation/manual/src/main/docbook/en-US/content/session_api.xml b/documentation/manual/src/main/docbook/en-US/content/session_api.xml index 94beb8ed4e..a1003ed5da 100644 --- a/documentation/manual/src/main/docbook/en-US/content/session_api.xml +++ b/documentation/manual/src/main/docbook/en-US/content/session_api.xml @@ -1,4 +1,4 @@ - + - - %BOOK_ENTITIES; - ]> - - Working with objects + Working with objects - - Hibernate is a full object/relational mapping solution that not only shields - the developer from the details of the underlying database management - system, but also offers state management of objects. This is, - contrary to the management of SQL statements in common JDBC/SQL - persistence layers, a natural object-oriented view of persistence in Java - applications. - + Hibernate is a full object/relational mapping solution that not only + shields the developer from the details of the underlying database management + system, but also offers state management of objects. + This is, contrary to the management of SQL statements in + common JDBC/SQL persistence layers, a natural object-oriented view of + persistence in Java applications. - - In other words, Hibernate application developers should always think about the - state of their objects, and not necessarily about the - execution of SQL statements. This part is taken care of by Hibernate and is only - relevant for the application developer when tuning the performance of the system. - + In other words, Hibernate application developers should always think + about the state of their objects, and not necessarily + about the execution of SQL statements. This part is taken care of by + Hibernate and is only relevant for the application developer when tuning the + performance of the system. -
- Hibernate object states +
+ Hibernate object states - - Hibernate defines and supports the following object states: - + Hibernate defines and supports the following object states: - - - - Transient - an object is transient if it has just - been instantiated using the new operator, and it - is not associated with a Hibernate Session. It has no - persistent representation in the database and no identifier value has been - assigned. Transient instances will be destroyed by the garbage collector if - the application does not hold a reference anymore. Use the Hibernate - Session to make an object persistent (and let Hibernate - take care of the SQL statements that need to be executed for this transition). - - - - - Persistent - a persistent instance has a representation - in the database and an identifier value. It might just have been saved or loaded, - however, it is by definition in the scope of a Session. - Hibernate will detect any changes made to an object in persistent state and - synchronize the state with the database when the unit of work completes. - Developers do not execute manual UPDATE statements, or - DELETE statements when an object should be made transient. - - - - - Detached - a detached instance is an object that has been - persistent, but its Session has been closed. The reference - to the object is still valid, of course, and the detached instance might even - be modified in this state. A detached instance can be reattached to a new - Session at a later point in time, making it (and all the - modifications) persistent again. This feature enables a programming model for - long running units of work that require user think-time. We call them - application transactions, i.e., a unit of work from the - point of view of the user. - - - + + + Transient - an object is transient if it + has just been instantiated using the new operator, + and it is not associated with a Hibernate Session. + It has no persistent representation in the database and no identifier + value has been assigned. Transient instances will be destroyed by the + garbage collector if the application does not hold a reference + anymore. Use the Hibernate Session to make an + object persistent (and let Hibernate take care of the SQL statements + that need to be executed for this transition). + - - We will now discuss the states and state transitions (and the Hibernate methods that - trigger a transition) in more detail. - + + Persistent - a persistent instance has a + representation in the database and an identifier value. It might just + have been saved or loaded, however, it is by definition in the scope + of a Session. Hibernate will detect any changes + made to an object in persistent state and synchronize the state with + the database when the unit of work completes. Developers do not + execute manual UPDATE statements, or + DELETE statements when an object should be made + transient. + -
+ + Detached - a detached instance is an object + that has been persistent, but its Session has been + closed. The reference to the object is still valid, of course, and the + detached instance might even be modified in this state. A detached + instance can be reattached to a new Session at a + later point in time, making it (and all the modifications) persistent + again. This feature enables a programming model for long running units + of work that require user think-time. We call them + application transactions, i.e., a unit of work + from the point of view of the user. + + -
- Making objects persistent + We will now discuss the states and state transitions (and the + Hibernate methods that trigger a transition) in more detail. +
- - Newly instantiated instances of a persistent class are considered - transient by Hibernate. We can make a transient - instance persistent by associating it with a - session: - +
+ Making objects persistent - Newly instantiated instances of a persistent class are considered + transient by Hibernate. We can make a transient + instance persistent by associating it with a + session: + + DomesticCat fritz = new DomesticCat(); fritz.setColor(Color.GINGER); fritz.setSex('M'); fritz.setName("Fritz"); -Long generatedId = (Long) sess.save(fritz);]]> +Long generatedId = (Long) sess.save(fritz); - - If Cat has a generated identifier, the identifier is - generated and assigned to the cat when save() - is called. If Cat has an assigned - identifier, or a composite key, the identifier should be assigned to - the cat instance before calling save(). - You can also use persist() instead of save(), - with the semantics defined in the EJB3 early draft. - + If Cat has a generated identifier, the identifier + is generated and assigned to the cat when + save() is called. If Cat has an + assigned identifier, or a composite key, the identifier + should be assigned to the cat instance before calling + save(). You can also use persist() + instead of save(), with the semantics defined in the + EJB3 early draft. - - - - persist() makes a transient instance persistent. - However, it does not guarantee that the identifier value will be assigned to - the persistent instance immediately, the assignment might happen at flush time. - persist() also guarantees that it will not execute an - INSERT statement if it is called outside of transaction - boundaries. This is useful in long-running conversations with an extended - Session/persistence context. - - - - - save() does guarantee to return an identifier. If an INSERT - has to be executed to get the identifier ( e.g. "identity" generator, not - "sequence"), this INSERT happens immediately, no matter if you are inside or - outside of a transaction. This is problematic in a long-running conversation - with an extended Session/persistence context. - - - + + + persist() makes a transient instance + persistent. However, it does not guarantee that the identifier value + will be assigned to the persistent instance immediately, the + assignment might happen at flush time. persist() + also guarantees that it will not execute an INSERT + statement if it is called outside of transaction boundaries. This is + useful in long-running conversations with an extended + Session/persistence context. + - - Alternatively, you can assign the identifier using an overloaded version - of save(). - + + save() does guarantee to return an + identifier. If an INSERT has to be executed to get the identifier ( + e.g. "identity" generator, not "sequence"), this INSERT happens + immediately, no matter if you are inside or outside of a transaction. + This is problematic in a long-running conversation with an extended + Session/persistence context. + + -Alternatively, you can assign the identifier using an overloaded + version of save(). + + DomesticCat pk = new DomesticCat(); pk.setColor(Color.TABBY); pk.setSex('F'); pk.setName("PK"); pk.setKittens( new HashSet() ); pk.addKitten(fritz); -sess.save( pk, new Long(1234) );]]> - - - If the object you make persistent has associated objects (e.g. the - kittens collection in the previous example), - these objects can be made persistent in any order you like unless you - have a NOT NULL constraint upon a foreign key column. - There is never a risk of violating foreign key constraints. However, you - might violate a NOT NULL constraint if you - save() the objects in the wrong order. - - - - Usually you do not bother with this detail, as you will normally use Hibernate's - transitive persistence feature to save the associated - objects automatically. Then, even NOT NULL - constraint violations do not occur - Hibernate will take care of everything. - Transitive persistence is discussed later in this chapter. - - -
+sess.save( pk, new Long(1234) ); -
- Loading an object + If the object you make persistent has associated objects (e.g. the + kittens collection in the previous example), these + objects can be made persistent in any order you like unless you have a + NOT NULL constraint upon a foreign key column. There is + never a risk of violating foreign key constraints. However, you might + violate a NOT NULL constraint if you + save() the objects in the wrong order. - - The load() methods of Session provide - a way of retrieving a persistent instance if you know its identifier. - load() takes a class object and loads the state into - a newly instantiated instance of that class in a persistent state. - + Usually you do not bother with this detail, as you will normally use + Hibernate's transitive persistence feature to save + the associated objects automatically. Then, even NOT + NULL constraint violations do not occur - Hibernate will take + care of everything. Transitive persistence is discussed later in this + chapter. +
- +
+ Loading an object -The load() methods of Session + provide a way of retrieving a persistent instance if you know its + identifier. load() takes a class object and loads the + state into a newly instantiated instance of that class in a persistent + state. + + Cat fritz = (Cat) sess.load(Cat.class, generatedId); + + // you need to wrap primitive identifiers long id = 1234; -DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );]]> +DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) ); - - Alternatively, you can load state into a given instance: - + Alternatively, you can load state into a given instance: -Cat cat = new DomesticCat(); // load pk's state into cat sess.load( cat, new Long(pkId) ); -Set kittens = cat.getKittens();]]> +Set kittens = cat.getKittens(); - - Be aware that load() will throw an unrecoverable exception if - there is no matching database row. If the class is mapped with a proxy, - load() just returns an uninitialized proxy and does not - actually hit the database until you invoke a method of the proxy. This - is useful if you wish to create an association to an object - without actually loading it from the database. It also allows multiple - instances to be loaded as a batch if batch-size is - defined for the class mapping. - - - - If you are not certain that a matching row exists, you should use the - get() method which hits the database immediately and - returns null if there is no matching row. - - - Be aware that load() will throw an unrecoverable + exception if there is no matching database row. If the class is mapped + with a proxy, load() just returns an uninitialized + proxy and does not actually hit the database until you invoke a method of + the proxy. This is useful if you wish to create an association to an + object without actually loading it from the database. It also allows + multiple instances to be loaded as a batch if + batch-size is defined for the class mapping. + + If you are not certain that a matching row exists, you should use + the get() method which hits the database immediately + and returns null if there is no matching row. + + Cat cat = (Cat) sess.get(Cat.class, id); if (cat==null) { cat = new Cat(); sess.save(cat, id); } -return cat;]]> +return cat; - - You can even load an object using an SQL SELECT ... FOR UPDATE, - using a LockMode. See the API documentation for more information. - + You can even load an object using an SQL SELECT ... FOR + UPDATE, using a LockMode. See the API + documentation for more information. - - - - Any associated instances or contained collections will - not be selected FOR UPDATE, unless you decide - to specify lock or all as a - cascade style for the association. - - - - It is possible to re-load an object and all its collections at any time, using the - refresh() method. This is useful when database triggers are used to - initialize some of the properties of the object. - - - Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE); + + Any associated instances or contained collections will + not be selected FOR UPDATE, unless + you decide to specify lock or all as + a cascade style for the association. + + It is possible to re-load an object and all its collections at any + time, using the refresh() method. This is useful when + database triggers are used to initialize some of the properties of the + object. + + sess.save(cat); sess.flush(); //force the SQL INSERT -sess.refresh(cat); //re-read the state (after the trigger executes)]]> +sess.refresh(cat); //re-read the state (after the trigger executes) - - How much does Hibernate load - from the database and how many SQL SELECTs will it use? This - depends on the fetching strategy. This is explained in - . - + How much does Hibernate load from the database and how many SQL + SELECTs will it use? This depends on the + fetching strategy. This is explained in . +
-
+
+ Querying -
- Querying + If you do not know the identifiers of the objects you are looking + for, you need a query. Hibernate supports an easy-to-use but powerful + object oriented query language (HQL). For programmatic query creation, + Hibernate supports a sophisticated Criteria and Example query feature (QBC + and QBE). You can also express your query in the native SQL of your + database, with optional support from Hibernate for result set conversion + into objects. - - If you do not know the identifiers of the objects you are looking for, - you need a query. Hibernate supports an easy-to-use but powerful object - oriented query language (HQL). For programmatic query creation, Hibernate - supports a sophisticated Criteria and Example query feature (QBC and QBE). - You can also express your query in the native SQL of your database, with - optional support from Hibernate for result set conversion into objects. - +
+ Executing queries -
- Executing queries + HQL and native SQL queries are represented with an instance of + org.hibernate.Query. This interface offers methods + for parameter binding, result set handling, and for the execution of the + actual query. You always obtain a Query using the + current Session: - - HQL and native SQL queries are represented with an instance of org.hibernate.Query. - This interface offers methods for parameter binding, result set handling, and for the execution - of the actual query. You always obtain a Query using the current - Session: - - - List cats = session.createQuery( + "from Cat as cat where cat.birthdate < ?") .setDate(0, date) .list(); @@ -309,35 +273,32 @@ Cat mother = (Cat) session.createQuery( Query mothersWithKittens = (Cat) session.createQuery( "select mother from Cat as mother left join fetch mother.kittens"); -Set uniqueMothers = new HashSet(mothersWithKittens.list());]]> +Set uniqueMothers = new HashSet(mothersWithKittens.list()); - - A query is usually executed by invoking list(). The - result of the query will be loaded completely into a collection in memory. - Entity instances retrieved by a query are in a persistent state. The - uniqueResult() method offers a shortcut if you - know your query will only return a single object. Queries that - make use of eager fetching of collections usually return duplicates of - the root objects, but with their collections initialized. You can filter - these duplicates through a Set. - + A query is usually executed by invoking list(). + The result of the query will be loaded completely into a collection in + memory. Entity instances retrieved by a query are in a persistent state. + The uniqueResult() method offers a shortcut if you + know your query will only return a single object. Queries that make use + of eager fetching of collections usually return duplicates of the root + objects, but with their collections initialized. You can filter these + duplicates through a Set. -
- Iterating results +
+ Iterating results - - Occasionally, you might be able to achieve better performance by - executing the query using the iterate() method. - This will usually be the case if you expect that the actual - entity instances returned by the query will already be in the session - or second-level cache. If they are not already cached, - iterate() will be slower than list() - and might require many database hits for a simple query, usually - 1 for the initial select which only returns identifiers, - and n additional selects to initialize the actual instances. - + Occasionally, you might be able to achieve better performance by + executing the query using the iterate() method. + This will usually be the case if you expect that the actual entity + instances returned by the query will already be in the session or + second-level cache. If they are not already cached, + iterate() will be slower than + list() and might require many database hits for a + simple query, usually 1 for the initial select + which only returns identifiers, and n additional + selects to initialize the actual instances. - // fetch ids Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate(); while ( iter.hasNext() ) { Qux qux = (Qux) iter.next(); // fetch the object @@ -348,18 +309,16 @@ while ( iter.hasNext() ) { // dont need to process the rest break; } -}]]> -
- -
- Queries that return tuples +} +
- - Hibernate queries sometimes return tuples of objects. Each tuple - is returned as an array: - +
+ Queries that return tuples - Hibernate queries sometimes return tuples of objects. Each tuple + is returned as an array: + + Iterator kittensAndMothers = sess.createQuery( "select kitten, mother from Cat kitten join kitten.mother mother") .list() .iterator(); @@ -369,20 +328,18 @@ while ( kittensAndMothers.hasNext() ) { Cat kitten = (Cat) tuple[0]; Cat mother = (Cat) tuple[1]; .... -}]]> +} +
-
+
+ Scalar results -
- Scalar results + Queries can specify a property of a class in the + select clause. They can even call SQL aggregate + functions. Properties or aggregates are considered "scalar" results + and not entities in persistent state. - - Queries can specify a property of a class in the select clause. - They can even call SQL aggregate functions. Properties or aggregates are considered - "scalar" results and not entities in persistent state. - - - Iterator results = sess.createQuery( "select cat.color, min(cat.birthdate), count(cat) from Cat cat " + "group by cat.color") .list() @@ -394,92 +351,79 @@ while ( results.hasNext() ) { Date oldest = (Date) row[1]; Integer count = (Integer) row[2]; ..... -}]]> +} +
-
+
+ Bind parameters -
- Bind parameters + Methods on Query are provided for binding + values to named parameters or JDBC-style ? + parameters. Contrary to JDBC, Hibernate numbers parameters + from zero. Named parameters are identifiers of the form + :name in the query string. The advantages of named + parameters are as follows: - - Methods on Query are provided for binding values to - named parameters or JDBC-style ? parameters. - Contrary to JDBC, Hibernate numbers parameters from zero. - Named parameters are identifiers of the form :name in - the query string. The advantages of named parameters are as follows: - + + + named parameters are insensitive to the order they occur in + the query string + - - - - named parameters are insensitive to the order they occur in the - query string - - - - - they can occur multiple times in the same query - - - - - they are self-documenting - - - + + they can occur multiple times in the same query + - + they are self-documenting + + + + //named parameter (preferred) Query q = sess.createQuery("from DomesticCat cat where cat.name = :name"); q.setString("name", "Fritz"); -Iterator cats = q.iterate();]]> +Iterator cats = q.iterate(); - //positional parameter Query q = sess.createQuery("from DomesticCat cat where cat.name = ?"); q.setString(0, "Izi"); -Iterator cats = q.iterate();]]> +Iterator cats = q.iterate(); - //named parameter list List names = new ArrayList(); names.add("Izi"); names.add("Fritz"); Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)"); q.setParameterList("namesList", names); -List cats = q.list();]]> +List cats = q.list(); +
-
+
+ Pagination -
- Pagination + If you need to specify bounds upon your result set, that is, the + maximum number of rows you want to retrieve and/or the first row you + want to retrieve, you can use methods of the Query + interface: - - If you need to specify bounds upon your result set, that is, the maximum number of rows - you want to retrieve and/or the first row you want to retrieve, you can - use methods of the Query interface: - - - Query q = sess.createQuery("from DomesticCat cat"); q.setFirstResult(20); q.setMaxResults(10); -List cats = q.list();]]> +List cats = q.list(); - - Hibernate knows how to translate this limit query into the native - SQL of your DBMS. - + Hibernate knows how to translate this limit query into the + native SQL of your DBMS. +
-
+
+ Scrollable iteration -
- Scrollable iteration + If your JDBC driver supports scrollable + ResultSets, the Query interface + can be used to obtain a ScrollableResults object + that allows flexible navigation of the query results. - - If your JDBC driver supports scrollable ResultSets, the - Query interface can be used to obtain a - ScrollableResults object that allows flexible - navigation of the query results. - - - Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " + "order by cat.name"); ScrollableResults cats = q.scroll(); if ( cats.first() ) { @@ -496,215 +440,188 @@ if ( cats.first() ) { pageOfCats = new ArrayList(); cats.beforeFirst(); int i=0; - while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) ); + while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) ); } -cats.close()]]> +cats.close() - - Note that an open database connection and cursor is required for this - functionality. Use setMaxResult()/setFirstResult() - if you need offline pagination functionality. - + Note that an open database connection and cursor is required for + this functionality. Use + setMaxResult()/setFirstResult() + if you need offline pagination functionality. +
-
+
+ Externalizing named queries -
- Externalizing named queries + You can also define named queries in the mapping document. + Remember to use a CDATA section if your query + contains characters that could be interpreted as markup. - - You can also define named queries in the mapping document. Remember to use a - CDATA section if your query contains characters that could - be interpreted as markup. - - - <query name="ByNameAndMaximumWeight"><![CDATA[ from eg.DomesticCat as cat where cat.name = ? - and cat.weight > ? -] ]>]]> + and cat.weight > ? +] ]></query> - - Parameter binding and executing is done programatically: - + Parameter binding and executing is done programatically: - Query q = sess.getNamedQuery("ByNameAndMaximumWeight"); q.setString(0, name); q.setInt(1, minWeight); -List cats = q.list();]]> +List cats = q.list(); - - The actual program code is independent of the query language that - is used. You can also define native SQL queries in metadata, or migrate - existing queries to Hibernate by placing them in mapping files. - + The actual program code is independent of the query language + that is used. You can also define native SQL queries in metadata, or + migrate existing queries to Hibernate by placing them in mapping + files. - - Also note that a query declaration inside a <hibernate-mapping> - element requires a global unique name for the query, while a query declaration inside a - <class> element is made unique automatically by prepending the - fully qualified name of the class. For example - eg.Cat.ByNameAndMaximumWeight. - + Also note that a query declaration inside a + <hibernate-mapping> element requires a global + unique name for the query, while a query declaration inside a + <class> element is made unique automatically + by prepending the fully qualified name of the class. For example + eg.Cat.ByNameAndMaximumWeight. +
+
-
+
+ Filtering collections -
+ A collection filter is a special type of + query that can be applied to a persistent collection or array. The query + string can refer to this, meaning the current + collection element. -
- Filtering collections - - A collection filter is a special type of query that can be applied to - a persistent collection or array. The query string can refer to this, - meaning the current collection element. - - - Collection blackKittens = session.createFilter( pk.getKittens(), "where this.color = ?") .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) ) .list() -);]]> - - - The returned collection is considered a bag that is a copy of the given - collection. The original collection is not modified. This is contrary to - the implication of the name "filter", but consistent with expected behavior. - +); - - Observe that filters do not require a from clause, although they can have - one if required. Filters are not limited to returning the collection elements themselves. - + The returned collection is considered a bag that is a copy of the + given collection. The original collection is not modified. This is + contrary to the implication of the name "filter", but consistent with + expected behavior. - Observe that filters do not require a from + clause, although they can have one if required. Filters are not limited + to returning the collection elements themselves. + + Collection blackKittenMates = session.createFilter( pk.getKittens(), "select this.mate where this.color = eg.Color.BLACK.intValue") - .list();]]> + .list(); - - Even an empty filter query is useful, e.g. to load a subset of elements in a - large collection: - + Even an empty filter query is useful, e.g. to load a subset of + elements in a large collection: - Collection tenKittens = session.createFilter( mother.getKittens(), "") .setFirstResult(0).setMaxResults(10) - .list();]]> + .list(); +
-
+
+ Criteria queries -
- Criteria queries + HQL is extremely powerful, but some developers prefer to build + queries dynamically using an object-oriented API, rather than building + query strings. Hibernate provides an intuitive + Criteria query API for these cases: - - HQL is extremely powerful, but some developers prefer to build queries dynamically - using an object-oriented API, rather than building query strings. Hibernate provides - an intuitive Criteria query API for these cases: - - - Criteria crit = session.createCriteria(Cat.class); crit.add( Restrictions.eq( "color", eg.Color.BLACK ) ); crit.setMaxResults(10); -List cats = crit.list();]]> - - - The Criteria and the associated Example - API are discussed in more detail in . - +List cats = crit.list(); -
+ The Criteria and the associated + Example API are discussed in more detail in . +
-
- Queries in native SQL +
+ Queries in native SQL - - You can express a query in SQL, using createSQLQuery() and - let Hibernate manage the mapping from result sets to objects. - You can at any time call session.connection() and - use the JDBC Connection directly. If you choose to use the - Hibernate API, you must enclose SQL aliases in braces: - + You can express a query in SQL, using + createSQLQuery() and let Hibernate manage the mapping + from result sets to objects. You can at any time call + session.connection() and use the JDBC + Connection directly. If you choose to use the + Hibernate API, you must enclose SQL aliases in braces: - List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10") .addEntity("cat", Cat.class) -.list();]]> - - + + List cats = session.createSQLQuery( "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " + "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " + - "FROM CAT {cat} WHERE ROWNUM<10") + "FROM CAT {cat} WHERE ROWNUM<10") .addEntity("cat", Cat.class) -.list()]]> - - - SQL queries can contain named and positional parameters, just like Hibernate queries. - More information about native SQL queries in Hibernate can be found in - . - - -
+.list() + SQL queries can contain named and positional parameters, just like + Hibernate queries. More information about native SQL queries in + Hibernate can be found in .
+
-
- Modifying persistent objects +
+ Modifying persistent objects - - Transactional persistent instances (i.e. objects loaded, saved, created or - queried by the Session) can be manipulated by the application, - and any changes to persistent state will be persisted when the Session - is flushed. This is discussed later in this chapter. There is no need - to call a particular method (like update(), which has a different - purpose) to make your modifications persistent. The most straightforward way to update - the state of an object is to load() it - and then manipulate it directly while the Session is open: - + Transactional persistent instances (i.e. + objects loaded, saved, created or queried by the + Session) can be manipulated by the application, and any + changes to persistent state will be persisted when the + Session is flushed. This is + discussed later in this chapter. There is no need to call a particular + method (like update(), which has a different purpose) + to make your modifications persistent. The most straightforward way to + update the state of an object is to load() it and then + manipulate it directly while the Session is + open: - DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) ); cat.setName("PK"); -sess.flush(); // changes to cat are automatically detected and persisted]]> +sess.flush(); // changes to cat are automatically detected and persisted - - Sometimes this programming model is inefficient, as it requires in the same session both an SQL - SELECT to load an object and an SQL UPDATE - to persist its updated state. Hibernate offers an - alternate approach by using detached instances. - + Sometimes this programming model is inefficient, as it requires in + the same session both an SQL SELECT to load an object + and an SQL UPDATE to persist its updated state. + Hibernate offers an alternate approach by using detached instances. - - Hibernate does not offer its own API for direct execution of - UPDATE or DELETE statements. Hibernate is a - state management service, you do not have to think in - statements to use it. JDBC is a perfect API for executing - SQL statements, you can get a JDBC Connection at any time - by calling session.connection(). Furthermore, the notion - of mass operations conflicts with object/relational mapping for online - transaction processing-oriented applications. Future versions of Hibernate - can, however, provide special mass operation functions. See - for some possible batch operation tricks. - - + + Hibernate does not offer its own API for direct execution of + UPDATE or DELETE statements. + Hibernate is a state management service, you do not + have to think in statements to use it. JDBC is a + perfect API for executing SQL statements, you can get a JDBC + Connection at any time by calling + session.connection(). Furthermore, the notion of mass + operations conflicts with object/relational mapping for online + transaction processing-oriented applications. Future versions of + Hibernate can, however, provide special mass operation functions. See + for some possible batch operation + tricks. + +
-
+
+ Modifying detached objects -
- Modifying detached objects + Many applications need to retrieve an object in one transaction, + send it to the UI layer for manipulation, then save the changes in a new + transaction. Applications that use this kind of approach in a + high-concurrency environment usually use versioned data to ensure + isolation for the "long" unit of work. - - Many applications need to retrieve an object in one transaction, send it to the - UI layer for manipulation, then save the changes in a new transaction. - Applications that use this kind of approach in a high-concurrency environment - usually use versioned data to ensure isolation for the "long" unit of work. - + Hibernate supports this model by providing for reattachment of + detached instances using the Session.update() or + Session.merge() methods: - - Hibernate supports this model by providing for reattachment of detached instances - using the Session.update() or Session.merge() - methods: - - - // in the first session Cat cat = (Cat) firstSession.load(Cat.class, catId); Cat potentialMate = new Cat(); firstSession.save(potentialMate); @@ -714,66 +631,57 @@ cat.setMate(potentialMate); // later, in a new session secondSession.update(cat); // update cat -secondSession.update(mate); // update mate]]> +secondSession.update(mate); // update mate - - If the Cat with identifier catId had already - been loaded by secondSession when the application tried to - reattach it, an exception would have been thrown. - + If the Cat with identifier + catId had already been loaded by + secondSession when the application tried to reattach + it, an exception would have been thrown. - - Use update() if you are certain that the session does - not contain an already persistent instance with the same identifier. Use - merge() if you want to merge your modifications at any time - without consideration of the state of the session. In other words, update() - is usually the first method you would call in a fresh session, ensuring that - the reattachment of your detached instances is the first operation that is executed. - + Use update() if you are certain that the session + does not contain an already persistent instance with the same identifier. + Use merge() if you want to merge your modifications at + any time without consideration of the state of the session. In other + words, update() is usually the first method you would + call in a fresh session, ensuring that the reattachment of your detached + instances is the first operation that is executed. - - The application should individually update() detached instances - that are reachable from the given detached instance only if it wants - their state to be updated. This can be automated using transitive - persistence. See for more information. - + The application should individually update() + detached instances that are reachable from the given detached instance + only if it wants their state to be updated. This can + be automated using transitive persistence. See for more information. - - The lock() method also allows an application to reassociate - an object with a new session. However, the detached instance has to be unmodified. - + The lock() method also allows an application to + reassociate an object with a new session. However, the detached instance + has to be unmodified. - //just reassociate: sess.lock(fritz, LockMode.NONE); //do a version check, then reassociate: sess.lock(izi, LockMode.READ); //do a version check, using SELECT ... FOR UPDATE, then reassociate: -sess.lock(pk, LockMode.UPGRADE);]]> +sess.lock(pk, LockMode.UPGRADE); - - Note that lock() can be used with various - LockModes. See the API documentation and the - chapter on transaction handling for more information. Reattachment is not - the only usecase for lock(). - + Note that lock() can be used with various + LockModes. See the API documentation and the chapter on + transaction handling for more information. Reattachment is not the only + usecase for lock(). - - Other models for long units of work are discussed in . - + Other models for long units of work are discussed in . +
-
+
+ Automatic state detection -
- Automatic state detection + Hibernate users have requested a general purpose method that either + saves a transient instance by generating a new identifier or + updates/reattaches the detached instances associated with its current + identifier. The saveOrUpdate() method implements this + functionality. - - Hibernate users have requested a general purpose method that either saves a - transient instance by generating a new identifier or updates/reattaches - the detached instances associated with its current identifier. - The saveOrUpdate() method implements this functionality. - - - // in the first session Cat cat = (Cat) firstSession.load(Cat.class, catID); // in a higher tier of the application @@ -782,157 +690,129 @@ cat.setMate(mate); // later, in a new session secondSession.saveOrUpdate(cat); // update existing state (cat has a non-null id) -secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id)]]> +secondSession.saveOrUpdate(mate); // save the new instance (mate has a null id) - - The usage and semantics of saveOrUpdate() seems to be confusing - for new users. Firstly, so long as you are not trying to use instances from one session - in another new session, you should not need to use update(), - saveOrUpdate(), or merge(). Some whole - applications will never use either of these methods. - + The usage and semantics of saveOrUpdate() seems + to be confusing for new users. Firstly, so long as you are not trying to + use instances from one session in another new session, you should not need + to use update(), saveOrUpdate(), or + merge(). Some whole applications will never use either + of these methods. - - Usually update() or saveOrUpdate() are used in - the following scenario: - + Usually update() or + saveOrUpdate() are used in the following + scenario: - - - - the application loads an object in the first session - - - - - the object is passed up to the UI tier - - - - - some modifications are made to the object - - - - - the object is passed back down to the business logic tier - - - - - the application persists these modifications by calling - update() in a second session - - - + + + the application loads an object in the first session + - - saveOrUpdate() does the following: - + + the object is passed up to the UI tier + - - - - if the object is already persistent in this session, do nothing - - - - - if another object associated with the session has the same identifier, - throw an exception - - - - - if the object has no identifier property, save() it - - - - - if the object's identifier has the value assigned to a newly instantiated - object, save() it - - - - - if the object is versioned by a <version> or - <timestamp>, and the version property value - is the same value assigned to a newly instantiated object, - save() it - - - - - otherwise update() the object - - - + + some modifications are made to the object + - - and merge() is very different: - + + the object is passed back down to the business logic tier + - - - - if there is a persistent instance with the same identifier currently - associated with the session, copy the state of the given object onto - the persistent instance - - - - - if there is no persistent instance currently associated with the session, - try to load it from the database, or create a new persistent instance - - - - - the persistent instance is returned - - - - - the given instance does not become associated with the session, it - remains detached - - - + + the application persists these modifications by calling + update() in a second session + + -
+ saveOrUpdate() does the following: -
- Deleting persistent objects + + + if the object is already persistent in this session, do + nothing + - - Session.delete() will remove an object's state from the database. - Your application, however, can still hold a reference to a deleted object. - It is best to think of delete() as making a persistent instance, - transient. - + + if another object associated with the session has the same + identifier, throw an exception + - + + if the object has no identifier property, + save() it + - - You can delete objects in any order, without risk of foreign key - constraint violations. It is still possible to violate a NOT - NULL constraint on a foreign key column by deleting objects in - the wrong order, e.g. if you delete the parent, but forget to delete the - children. - + + if the object's identifier has the value assigned to a newly + instantiated object, save() it + -
- -
- Replicating object between two different datastores - - - It is sometimes useful to be able to take a graph of persistent instances - and make them persistent in a different datastore, without regenerating identifier - values. - - - + if the object is versioned by a + <version> or + <timestamp>, and the version property value + is the same value assigned to a newly instantiated object, + save() it + + + + otherwise update() the object + + + + and merge() is very different: + + + + if there is a persistent instance with the same identifier + currently associated with the session, copy the state of the given + object onto the persistent instance + + + + if there is no persistent instance currently associated with the + session, try to load it from the database, or create a new persistent + instance + + + + the persistent instance is returned + + + + the given instance does not become associated with the session, + it remains detached + + +
+ +
+ Deleting persistent objects + + Session.delete() will remove an object's state + from the database. Your application, however, can still hold a reference + to a deleted object. It is best to think of delete() as + making a persistent instance, transient. + + sess.delete(cat); + + You can delete objects in any order, without risk of foreign key + constraint violations. It is still possible to violate a NOT + NULL constraint on a foreign key column by deleting objects in + the wrong order, e.g. if you delete the parent, but forget to delete the + children. +
+ +
+ Replicating object between two different datastores + + It is sometimes useful to be able to take a graph of persistent + instances and make them persistent in a different datastore, without + regenerating identifier values. + + //retrieve a cat from one database Session session1 = factory1.openSession(); Transaction tx1 = session1.beginTransaction(); Cat cat = session1.get(Cat.class, catId); @@ -944,140 +824,117 @@ Session session2 = factory2.openSession(); Transaction tx2 = session2.beginTransaction(); session2.replicate(cat, ReplicationMode.LATEST_VERSION); tx2.commit(); -session2.close();]]> +session2.close(); - - The ReplicationMode determines how replicate() - will deal with conflicts with existing rows in the database: - - - - - - ReplicationMode.IGNORE: ignores the object when there is - an existing database row with the same identifier - - - - - ReplicationMode.OVERWRITE: overwrites any existing database - row with the same identifier - - - - - ReplicationMode.EXCEPTION: throws an exception if there is - an existing database row with the same identifier - - - - - ReplicationMode.LATEST_VERSION: overwrites the row if its - version number is earlier than the version number of the object, or ignore - the object otherwise - - - + The ReplicationMode determines how + replicate() will deal with conflicts with existing rows + in the database: - - Usecases for this feature include reconciling data entered into different database - instances, upgrading system configuration information during product upgrades, - rolling back changes made during non-ACID transactions and more. - - -
+ + + ReplicationMode.IGNORE: ignores the object + when there is an existing database row with the same identifier + -
- Flushing the Session + + ReplicationMode.OVERWRITE: overwrites any + existing database row with the same identifier + - - Sometimes the Session will execute the SQL statements - needed to synchronize the JDBC connection's state with the state of objects held in - memory. This process, called flush, occurs by default at the following - points: - + + ReplicationMode.EXCEPTION: throws an + exception if there is an existing database row with the same + identifier + - - - - before some query executions - - - - - from org.hibernate.Transaction.commit() - - - - - from Session.flush() - - - + + ReplicationMode.LATEST_VERSION: overwrites + the row if its version number is earlier than the version number of + the object, or ignore the object otherwise + + - - The SQL statements are issued in the following order: - + Usecases for this feature include reconciling data entered into + different database instances, upgrading system configuration information + during product upgrades, rolling back changes made during non-ACID + transactions and more. +
- - - - all entity insertions in the same order the corresponding objects - were saved using Session.save() - - - - - all entity updates - - - - - all collection deletions - - - - - all collection element deletions, updates and insertions - - - - - all collection insertions - - - - - all entity deletions in the same order the corresponding objects - were deleted using Session.delete() - - - +
+ Flushing the Session - - An exception is that objects using native ID generation are - inserted when they are saved. - + Sometimes the Session will execute the SQL + statements needed to synchronize the JDBC connection's state with the + state of objects held in memory. This process, called + flush, occurs by default at the following + points: - - Except when you explicitly flush(), there are absolutely no - guarantees about when the Session executes - the JDBC calls, only the order in which they are executed. - However, Hibernate does guarantee that the Query.list(..) - will never return stale or incorrect data. - + + + before some query executions + - - It is possible to change the default behavior so that flush occurs less frequently. - The FlushMode class defines three different modes: only flush - at commit time when the Hibernate Transaction API - is used, flush automatically using the explained routine, or never flush unless - flush() is called explicitly. The last mode is useful for long running - units of work, where a Session is kept open and disconnected for - a long time (see ). - + + from + org.hibernate.Transaction.commit() + - + from Session.flush() + + + + The SQL statements are issued in the following order: + + + + all entity insertions in the same order the corresponding + objects were saved using Session.save() + + + + all entity updates + + + + all collection deletions + + + + all collection element deletions, updates and insertions + + + + all collection insertions + + + + all entity deletions in the same order the corresponding objects + were deleted using Session.delete() + + + + An exception is that objects using native ID + generation are inserted when they are saved. + + Except when you explicitly flush(), there are + absolutely no guarantees about when the + Session executes the JDBC calls, only the + order in which they are executed. However, Hibernate + does guarantee that the Query.list(..) will never + return stale or incorrect data. + + It is possible to change the default behavior so that flush occurs + less frequently. The FlushMode class defines three + different modes: only flush at commit time when the Hibernate + Transaction API is used, flush automatically using the + explained routine, or never flush unless flush() is + called explicitly. The last mode is useful for long running units of work, + where a Session is kept open and disconnected for a + long time (see ). + + sess = sf.openSession(); Transaction tx = sess.beginTransaction(); sess.setFlushMode(FlushMode.COMMIT); // allow queries to return stale state @@ -1090,188 +947,245 @@ sess.find("from Cat as cat left outer join cat.kittens kitten"); // change to izi is not flushed! ... tx.commit(); // flush occurs -sess.close();]]> +sess.close(); - - During flush, an exception might occur (e.g. if a DML operation violates a constraint). - Since handling exceptions involves some understanding of Hibernate's transactional - behavior, we discuss it in . - + During flush, an exception might occur (e.g. if a DML operation + violates a constraint). Since handling exceptions involves some + understanding of Hibernate's transactional behavior, we discuss it in + . +
-
+
+ Transitive persistence -
- Transitive persistence + It is quite cumbersome to save, delete, or reattach individual + objects, especially if you deal with a graph of associated objects. A + common case is a parent/child relationship. Consider the following + example: - - It is quite cumbersome to save, delete, or reattach individual objects, - especially if you deal with a graph of associated objects. A common case is - a parent/child relationship. Consider the following example: - + If the children in a parent/child relationship would be value typed + (e.g. a collection of addresses or strings), their life cycle would depend + on the parent and no further action would be required for convenient + "cascading" of state changes. When the parent is saved, the value-typed + child objects are saved and when the parent is deleted, the children will + be deleted, etc. This works for operations such as the removal of a child + from the collection. Since value-typed objects cannot have shared + references, Hibernate will detect this and delete the child from the + database. - - If the children in a parent/child relationship would be value typed (e.g. a collection - of addresses or strings), their life cycle would depend on the parent and no - further action would be required for convenient "cascading" of state changes. - When the parent is saved, the value-typed child objects are saved and - when the parent is deleted, the children will be deleted, etc. This - works for operations such as the removal of a child from the collection. - Since value-typed objects cannot have shared - references, Hibernate will detect this and delete the child from the database. - + Now consider the same scenario with parent and child objects being + entities, not value-types (e.g. categories and items, or parent and child + cats). Entities have their own life cycle and support shared references. + Removing an entity from the collection does not mean it can be deleted), + and there is by default no cascading of state from one entity to any other + associated entities. Hibernate does not implement persistence by + reachability by default. - - Now consider the same scenario with parent and child objects being entities, - not value-types (e.g. categories and items, or parent and child cats). Entities - have their own life cycle and support shared references. Removing an entity from - the collection does not mean it can be deleted), and there is by default no - cascading of state from one entity to any other associated entities. Hibernate - does not implement persistence by reachability by default. - + For each basic operation of the Hibernate session - including + persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), + evict(), replicate() - there is a corresponding cascade style. + Respectively, the cascade styles are named create, merge, + save-update, delete, lock, refresh, evict, replicate. If you + want an operation to be cascaded along an association, you must indicate + that in the mapping document. For example: - - For each basic operation of the Hibernate session - including persist(), merge(), - saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate() - there is a - corresponding cascade style. Respectively, the cascade styles are named create, - merge, save-update, delete, lock, refresh, evict, replicate. If you want an - operation to be cascaded along an association, you must indicate that in the mapping - document. For example: - - - ]]> - - - Cascade styles my be combined: - - - ]]> - - - You can even use cascade="all" to specify that all - operations should be cascaded along the association. The default cascade="none" - specifies that no operations are to be cascaded. - - - - A special cascade style, delete-orphan, applies only to one-to-many - associations, and indicates that the delete() operation should - be applied to any child object that is removed from the association. - + <one-to-one name="person" cascade="persist"/> + Cascade styles my be combined: - - Recommendations: - + <one-to-one name="person" cascade="persist,delete,lock"/> - - - - It does not usually make sense to enable cascade on a <many-to-one> - or <many-to-many> association. Cascade is often useful for - <one-to-one> and <one-to-many> - associations. - - - - - If the child object's lifespan is bounded by the lifespan of the parent - object, make it a life cycle object by specifying - cascade="all,delete-orphan". - - - - - Otherwise, you might not need cascade at all. But if you think that you will often be - working with the parent and children together in the same transaction, and you want to save - yourself some typing, consider using cascade="persist,merge,save-update". - - - + You can even use cascade="all" to specify that + all operations should be cascaded along the + association. The default cascade="none" specifies that + no operations are to be cascaded. - - Mapping an association (either a single valued association, or a collection) with - cascade="all" marks the association as a - parent/child style relationship where save/update/delete of the - parent results in save/update/delete of the child or children. - - - Furthermore, a mere reference to a child from a persistent parent will result in - save/update of the child. This metaphor is incomplete, however. A child which becomes - unreferenced by its parent is not automatically deleted, except - in the case of a <one-to-many> association mapped with - cascade="delete-orphan". The precise semantics of cascading - operations for a parent/child relationship are as follows: - + In case you are using annotatons you probably have noticed the + cascade attribute taking an array of + CascadeType as a value. The cascade concept in JPA + is very is similar to the transitive persistence and cascading of + operations as described above, but with slightly different semantics and + cascading types: - - - - If a parent is passed to persist(), all children are passed to - persist() - - - - - If a parent is passed to merge(), all children are passed to - merge() - - - - - If a parent is passed to save(), update() or - saveOrUpdate(), all children are passed to saveOrUpdate() - - - - - If a transient or detached child becomes referenced by a persistent parent, - it is passed to saveOrUpdate() - - - - - If a parent is deleted, all children are passed to delete() - - - - - If a child is dereferenced by a persistent parent, nothing - special happens - the application should explicitly delete - the child if necessary - unless cascade="delete-orphan", - in which case the "orphaned" child is deleted. - - - + + + CascadeType.PERSIST: cascades the persist + (create) operation to associated entities persist() is called or if + the entity is managed + - - Finally, note that cascading of operations can be applied to an object graph at - call time or at flush time. All operations, - if enabled, are cascaded to associated entities reachable when the operation is - executed. However, save-update and delete-orphan - are transitive for all associated entities reachable during flush of the - Session. - + + CascadeType.MERGE: cascades the merge + operation to associated entities if merge() is called or if the entity + is managed + -
+ + CascadeType.REMOVE: cascades the remove + operation to associated entities if delete() is called + -
- Using metadata + + CascadeType.REFRESH: cascades the refresh + operation to associated entities if refresh() is called + - - Hibernate requires a rich meta-level model of all entity and value types. - This model can be useful to the application itself. For example, the application - might use Hibernate's metadata to implement a "smart" deep-copy algorithm that understands - which objects should be copied (eg. mutable value types) and which objects that should not (e.g. - immutable value types and, possibly, associated entities). - - - Hibernate exposes metadata via the ClassMetadata and - CollectionMetadata interfaces and the Type - hierarchy. Instances of the metadata interfaces can be obtained from the - SessionFactory. - + + CascadeType.DETACH: cascades the detach + operation to associated entities if detach() is called + - + CascadeType.ALL: all of the above + + + + + CascadeType.ALL also covers Hibernate specific operations like + save-update, lock etc... + + + A special cascade style, delete-orphan, applies + only to one-to-many associations, and indicates that the + delete() operation should be applied to any child + object that is removed from the association. Using annotations there is no + CascadeType.DELETE-ORPHAN equivalent. Instead you can + use the attribute orphanRemoval as seen in . If an entity is + removed from a @OneToMany collection or an + associated entity is dereferenced from a @OneToOne + association, this associated entity can be marked for deletion if + orphanRemoval is set to true. + + + <literal>@OneToMany</literal> with + <literal>orphanRemoval</literal> + + @Entity +public class Customer { + private Set<Order> orders; + + @OneToMany(cascade=CascadeType.ALL, orphanRemoval=true) + public Set<Order> getOrders() { return orders; } + + public void setOrders(Set<Order> orders) { this.orders = orders; } + + [...] +} + +@Entity +public class Order { ... } + +Customer customer = em.find(Customer.class, 1l); +Order order = em.find(Order.class, 1l); +customer.getOrders().remove(order); //order will be deleted by cascade + + + Recommendations: + + + + It does not usually make sense to enable cascade on a + many-to-one or many-to-many association. In fact the + @ManyToOne and @ManyToMany don't + even offer a orphanRemoval attribute. Cascading is + often useful for one-to-one and one-to-many associations. + + + + If the child object's lifespan is bounded by the lifespan of the + parent object, make it a life cycle object by + specifying + cascade="all,delete-orphan"(@OneToMany(cascade=CascadeType.ALL, + orphanRemoval=true)). + + + + Otherwise, you might not need cascade at all. But if you think + that you will often be working with the parent and children together + in the same transaction, and you want to save yourself some typing, + consider using + cascade="persist,merge,save-update". + + + + Mapping an association (either a single valued association, or a + collection) with cascade="all" marks the association as + a parent/child style relationship where + save/update/delete of the parent results in save/update/delete of the + child or children. + + Furthermore, a mere reference to a child from a persistent parent + will result in save/update of the child. This metaphor is incomplete, + however. A child which becomes unreferenced by its parent is + not automatically deleted, except in the case of a + one-to-many association mapped with + cascade="delete-orphan". The precise semantics of + cascading operations for a parent/child relationship are as + follows: + + + + If a parent is passed to persist(), all + children are passed to persist() + + + + If a parent is passed to merge(), all + children are passed to merge() + + + + If a parent is passed to save(), + update() or saveOrUpdate(), all + children are passed to saveOrUpdate() + + + + If a transient or detached child becomes referenced by a + persistent parent, it is passed to + saveOrUpdate() + + + + If a parent is deleted, all children are passed to + delete() + + + + If a child is dereferenced by a persistent parent, + nothing special happens - the application should + explicitly delete the child if necessary - unless + cascade="delete-orphan", in which case the + "orphaned" child is deleted. + + + + Finally, note that cascading of operations can be applied to an + object graph at call time or at flush + time. All operations, if enabled, are cascaded to associated + entities reachable when the operation is executed. However, + save-update and delete-orphan are + transitive for all associated entities reachable during flush of the + Session. +
+ +
+ Using metadata + + Hibernate requires a rich meta-level model of all entity and value + types. This model can be useful to the application itself. For example, + the application might use Hibernate's metadata to implement a "smart" + deep-copy algorithm that understands which objects should be copied (eg. + mutable value types) and which objects that should not (e.g. immutable + value types and, possibly, associated entities). + + Hibernate exposes metadata via the ClassMetadata + and CollectionMetadata interfaces and the + Type hierarchy. Instances of the metadata interfaces + can be obtained from the SessionFactory. + + Cat fritz = ......; ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class); Object[] propertyValues = catMeta.getPropertyValues(fritz); @@ -1280,13 +1194,10 @@ Type[] propertyTypes = catMeta.getPropertyTypes(); // get a Map of all properties which are not collections or associations Map namedValues = new HashMap(); -for ( int i=0; i - -
- +} +
-