====== Related to [[http://www.hibernate.org/|Hibernate]] ====== ===== Hibernate forum links ===== * [[http://community.jboss.org/en/hibernate/faq|Community FAQ]] * [[http://www.javalobby.org/java/forums/t48846.html|Hibernate: Truly Understanding the Second-Level and Query Caches]] * The ''ehcache.xml'' file location: the problem was raised many times but still is actual: [[http://forum.hibernate.org/viewtopic.php?t=946843|topic 1]], [[http://forum.hibernate.org/viewtopic.php?t=944832|topic 2]], [[http://track.sipfoundry.org/browse/XCF-494|topic 3]], [[sourceforgeforum>3305407|topic 4]], [[sourceforgeforum>3284483|topic 5]] * Additional where-clause limitations for '''' and '''' associations: [[http://forum.hibernate.org/viewtopic.php?t=948699|topic 1]], [[http://forum.hibernate.org/viewtopic.php?t=948812|topic 2]] * [[wp>List of object-relational mapping software#Java|Alternative ORM frameworks]] ===== Questions answered ===== === What are the ways to map ''Enum'' types? === ''UserType'' example of mapping ''Enum'' to ''int'' is [[https://www.hibernate.org/312.html|here]], ''Enum'' to ''string'' is [[https://www.hibernate.org/272.html|here]]. Hibernate also provides the nice implementation, which is in ''hibernate-annotations'' (merged into core from v3.6.0). Sample of usage: ... org.mycompany.dao.SemanticType === How to initialize a lazily loaded collection? === You need to open the session and re-associate the object with a session via ''Session.merge(object)'' before accessing the lazy collection. Alternatively you can use the [[http://forum.springsource.org/showthread.php?p=357469|following example]]: public void initializeLazyCollection(MyBean bean) { final Session session = getSessionFactory().openSession(); try { // Associate the bean with a session: session.lock(bean, LockMode.READ); Hibernate.initialize(bean.getChildren()); } finally { session.close(); } } Alternatively you may use [[http://noon.gilead.free.fr/gilead/index.php?page=configuration|Glead]] (see also [[stackoverflow>3397475|Using GWT with Hibernate]]). === How to re-associate the detached entity with session? === If your entity has no lazy associations, then ''Session.lock(entity, LockMode.NONE)'' would do the job. Otherwise do ''Session.merge(entity)'' (see [[stackoverflow>912659|What is the proper way to re-attach detached objects in Hibernate?]]). === What is the difference between ''Session.save()'' and ''Session.persist()''? === Is covered [[https://forum.hibernate.org/viewtopic.php?t=951275#p2325758|here]]. === Why bags ''equals()'' and ''hashCode()'' behave differently from lists and maps? === Follow this discussion: [[https://forum.hibernate.org/viewtopic.php?f=9&t=971056#p2421672|equals() and hashCode() for PersistentBag and PersistentIdentifierBag]]. === When I clear the collection and re-add entities, I get ''ConstraintViolationException''. === This can only happen when you add entities that violate DB unique constraint (not the primary key). Ideologically this unique constraint should be the entity ID, but often it is not desired as the number of columns (= properties in composite ID) grows with each level of tables hierarchy (''A->B->C'') and the only way out is to use synthetic (autogenerated) ID. However Hibernate can't handle this case. As from [[https://forum.hibernate.org/viewtopic.php?t=934483|here]] and [[stackoverflow>706673#707364|here]] the order of issued SQL statements is: * 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()'' and the only solution is to [[stackoverflow>2065254#2065819|flush the session]] after ''collection.clear()''. Alternative solution is to [[https://forum.hibernate.org/viewtopic.php?f=1&t=934483&sid=d875e422d4d9f7bd8b00fd0db64276d2&p=2450195#p2450195|walk the entity tree and re-assign the IDs]]. === How to write a mapping for ''one-to-many'' association with composite ID? === In our simple example we will deal with two entities: the document and the image, associated with a document. The SQL schema is: create table document ( id integer unsigned not null auto_increment, country varchar(255) not null, indexed_date datetime not null, constraint document_pk primary key (id) ) engine=InnoDB; create table image ( document_id integer unsigned not null, page_number integer unsigned not null, image_data longblob not null, constraint image_pk primary key (document_id, page_number), constraint image_fk foreign key (document_id) references document (id) on delete cascade ) engine=InnoDB; In our example we will not introduce the synthetic key for ''image'' table to show how to deal with composite ID, which in our case is ''(document_id, page_number)''. The mapping is: Hibernate can only trace back the relations which are explicitly described as '''' or '''', i.e. they are [[http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-parentchild.html#example-parentchild-bidir|bidirectional]]. So for our example the following mapping will not work: ... as Hibernate will not trace the relation back to ''document'' table by only knowing the column name ''document_id'' (see [[http://opensource.atlassian.com/projects/hibernate/browse/HHH-4012|HHH-4012]]). Java code example: Document document = new Document(); document.setIndexedDate(new Timestamp(9876543210L)); document.setCountry("USA") Collection images = new ArrayList(); { final DocumentImage image = new DocumentImage(); image.setPageNumber(1); image.setImageData("ANdj17shOL12p".getBytes()); image.setParentDocument(document); images.add(image); } { final DocumentImage image = new DocumentImage(); image.setPageNumber(2); image.setImageData("(*&$@!9&!".getBytes()); image.setParentDocument(document); images.add(image); } document.setImages(images); Session session = getSessionFactory().openSession(); session.saveOrUpdate(document); session.flush(); session.close(); If you use ''%%cascade="all-delete-orphan"%%'' for your association, you need to be careful when updating the lazily loaded collection of images, in particular, when you use the code ''document.setImages(images)'' you actually replace the Hibernate lazy collection instance with another implementation. This confuses Hibernate, who will throw the following exception: org.hibernate.HibernateException: A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance: com.mycompany.myproject.common.Document.images at org.hibernate.engine.Collections.processDereferencedCollection(Collections.java:118) at org.hibernate.engine.Collections.processUnreachableCollection(Collections.java:62) at org.hibernate.event.def.AbstractFlushingEventListener.flushCollections(AbstractFlushingEventListener.java:241) at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:100) at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50) at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206) Knowing that Hibernate will in any case initialize the collection (maybe with empty collection instance), you need to use the following code: ''document.getImages().addAll(images)''. We need to specify ''%%cascade="all"%%'' (or weaker) and to control the session orphans ourselves. You can pass the persistent/transient Hibernate object to ''Session#saveOrUpdate()'' or to ''Session#persist()''. * In first case ''saveOrUpdate'' event be triggered on parent entity and all child relations, causing Hibernate to check each entity if it exists in the database (so Hibernate will issue as many ''select from image'' statements plus either ''update image'' or ''insert into image'' as there are entities in collection). * In second case ''saveOrUpdate'' event be triggered on parent entity and ''persist'' event will be triggered for all child entities, so only ''insert into image'' statements will be issued. Database will trigger the exception in case the child entity with the same ID already exists. For example, assume that you have another one-to-many relation in documents (the text paragraphs), and you want to persist images and not paragraphs. * In case of ''Session#persist()'' the side effect is that Hibernate will initialize/load the lazy collection with paragraphs (will issue one ''select * from paragraph''), but ''persist'' event will trigger no action for these newly loaded entities. In this case you need to set the collection which you don't want to be processed to ''null'': document.setParagraphs(null); document.setImages(images); session.persist(document); * In case of ''Session#saveOrUpdate()'' the side effect is that Hibernate will check each entity if it exists in the database. For more examples of how to use bidirectional associations with composite keys, see examples that come together with Hibernate distribution (e.g. have a loot at ''hibernate-distribution.tar.gz/project\testsuite\src\test\java\org\hibernate\test\legacy\Middle.hbm.xml''). === What is the difference between ''delete'' v.s. ''delete-orphan'' and ''all-delete-orphan'' v.s. ''all,delete-orphan'' ? === From [[stackoverflow>1377585#1377615|What is the difference between ''delete-orphan'' and ''delete''?]]:
Cascade ''delete'' means if parent entity is deleted, delete the related entities. ''delete-orphan'' means: if an entity is removed from a related one-to-many collection, then not only disassociate it from the current entity, but delete it (does not allow it to stay //orphan//).
''all-delete-orphan'' and ''all,delete-orphan'' are synonyms and should result the same behaviour (see [[https://forum.hibernate.org/viewtopic.php?t=938758|here]]).
=== How to set the the foreign key to ''NULL'' when the parent entity is deleted? === I think that is exactly what controlled by ''inverse'' property: * if ''inverse='false''' then when collection entry is removed, the parent key is set to null (''update child set parent_id = null where parent_id = ?'') * if ''inverse='true''' then when collection entry is removed, it is deleted by key (''delete from child where id = ?'') === How to expand the lifetime of Hibernate session across two transactions (e.g. two ''@Transactional'' methods) to preserve L1 cache? === By default Hibernate session is closed as soon as transaction is closed. As mentioned [[stackoverflow>2435705#2436485|here]] you need to define [[http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-interceptors|interceptor]] that binds the Hibernate session to HTTP request and thus allows it to span across all transactions: The corresponding flow is displayed on figure 5.4 "Implementing application transactions with a long ''Session'' using disconnection" on p174 in chapter "Transactions, concurrency, and caching" of //[[http://www.manning.com/bauer/|Hibernate In Action]]// by Christian Bauer and Gavin King, Manning, 2005. To Unit test it you need a helper method, that repeats the functionality of Spring ''[[springfish>org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/DispatcherServlet.java?r=3644#l740|DispatcherServlet]]'': public abstract class AbstractTest { @Autowired protected HandlerAdapter handlerAdapter; @Autowired protected HandlerMapping handlerMapping; protected MockHttpServletRequest request = new MockHttpServletRequest(); protected MockHttpServletResponse response = new MockHttpServletResponse(); /** * This function feeds the given request to Spring MVC. The code is a simplified flow from * {@link org.springframework.web.servlet.DispatcherServlet}. */ protected void handleRequest() throws Exception { final HandlerExecutionChain handler = handlerMapping.getHandler(request); final HandlerInterceptor[] interceptors = handler.getInterceptors(); if (interceptors != null) { for (int i = 0; i < interceptors.length; i++) { if (!interceptors[i].preHandle(request, response, handler.getHandler())) { throw new IllegalStateException("The interceptor " + interceptors[i] + " prevents the request from being processed"); } } } handlerAdapter.handle(request, response, handler.getHandler()); } /** * The same as {@link #handleRequest()} but sets a request URL beforehand. */ protected void handleRequest(String requestURI) throws Exception { request.setRequestURI(requestURI); handleRequest(); } } Alternatively, you can use the following code (assuming that property ''HibernateTemplate.alwaysUseNewSession = false''): SessionFactoryUtils.initDeferredClose(getHibernateTemplate().getSessionFactory()); try { getHibernateTemplate().doSomething(); ... getHibernateTemplate().doAgain(); } finally { SessionFactoryUtils.processDeferredClose(getHibernateTemplate().getSessionFactory()); } === How to avoid ''OutOfMemoryError'' caused by constantly growing Hibernate L1 cache? === You need to set ''autoClear'' property on ''Session'' instance, which will clean the session after the transaction completion (from [[http://taapps-javalibs.blogspot.com/2009/07/grailscheck-list-when.html|here]]): final Session session = getSessionFactory().getCurrentSession(); if (session instanceof SessionImplementor) { ((SessionImplementor) session).setAutoClear(true); } You may also wish to disable the 2nd level cache and analyse the heap dump (''export JAVA_OPTS=-verbose:gc -XX:+PrintClassHistogram -XX:+PrintGCDetails -Xloggc:/tmp/jvm_loggc.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp'' + [[http://www.eclipse.org/mat/|Memory Analyzer]]). See the [[http://taapps-javalibs.blogspot.com/2009/07/grailscheck-list-when.html|complete note]]. === The column datatype which I would like to query via native SQL is ''char(3)'' but Hibernate maps it to ''java.lang.Character'' so only first character is returned. How to change the returned type to ''java.lang.String''? === You need to explicitly define the return type as mentioned [[stackoverflow>4873201#4873520|here]] in your mapping file: or programmatically via ''org.hibernate.SQLQuery#addScalar(String columnAlias, Type type)''. {{tag>Hibernate Spring}}