Going further into Hibernate i've stumbled upon the following situation:
I have an #Entity Person
#Entity
#Table(name = "PERSON")
#Inheritance(strategy = InheritanceType.SINGLE_TABLE)
#DiscriminatorColumn(name="type",discriminatorType=DiscriminatorType.STRING)
#DiscriminatorValue(value="person")
public class Person implements PersonInterface{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "USER_ID")
protected Integer id;
#Column(name = "NAME")
protected String name;
#ElementCollection
#Formula("(SELECT groupId FROM PERSON_GROUPS WHERE id = id")
protected List<Integer> groups = new ArrayList<>();
#Override
public Integer getId() {
return id;
}
#Override
public Collection<Integer> getGroups(){
return groups;
}
#Override
public String getName() {
return name;
}
}
Which is split in two parts, Immutable and Mutable:
#Entity
#DiscriminatorValue("mutableperson")
#Transactional
public class MutablePerson extends Person implements MutablePersonInterface{
#Override
public void setName(String name) {
this.name = name;
}
#Override
public void setId(Integer id) {
this.id = id;
}
#Override
public void setGroups(List<Integer> groupIds) {
this.groups = groupIds;
}
public void excludeFromGroup(Integer groupId){
Hibernate.initialize(this.groups);
this.groups.remove(groupId);
}
}
Now, when i try to call something like:
Session session = sessionFactory.openSession();
MutablePerson personFromDb = (MutablePerson) personService.getMutablePersonById(0);
personFromDb.excludeFromGroup(group1.getId());
session.saveOrUpdate(personFromDb);
I get an exception:
Exception in thread "main" org.hibernate.HibernateException: collection is not associated with any session
at org.hibernate.collection.internal.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:704)
at org.hibernate.Hibernate.initialize(Hibernate.java:65)
at com.studytrails.tutorials.springhibernatejpa.MutablePerson.excludeFromGroup(MutablePerson.java:57)
at com.studytrails.tutorials.springhibernatejpa.TestSpringHibernateJpa.main(TestSpringHibernateJpa.java:48)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Which tells me, that #Transactional annotation for that MutablePerson class doesn't really work and Hibernate is not creating a transaction.
Here's this bit of my spring configuration:
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
<property name="dataSource" ref="dataSource" />
<property name="jpaDialect" ref="jpaDialect" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
As far as i can tell from Hibernate docs and examples, this config is correct and it should work, but it doesn't. Am i missing yet another Hibernate nuance here?
P.S. I know i could've done this in DAO or Service class, but unfortunately i'm bound to use existing API, which works with groups in the mutable half of the entity.
Entities are not managed by Spring. they are created as a product of database operation via hibernate or manually to save date. therefore the #Transactional annotation will not work as this is not a spring managed bean.
Spring transactional context wraps around a spring managed bean and act on it. it cannot wrap non spring beans
Possible Solution
Move the transactional context ideally for service layer or at least Jpa Repository/Dao layer.
Related
I can't to get list of data through ehcache.
servlet-context:
<cache:annotation-driven />
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
p:cacheManager-ref="ehcache"/>
<bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
p:configLocation="/WEB-INF/spring/appServlet/ehcache.xml" p:shared="true" />
ehcache.xml
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="ehcache.xsd"
updateCheck="true" monitoring="autodetect" dynamicConfig="true">
<cache name="category"
maxEntriesLocalHeap="5000"
maxEntriesLocalDisk="1000"
eternal="false"
diskSpoolBufferSizeMB="20"
timeToIdleSeconds="200"
timeToLiveSeconds="500"
memoryStoreEvictionPolicy="LFU"
transactionalMode="off">
<persistence strategy="localTempSwap"/>
</cache>
I have an entity of Category:
#Entity
#Table(name = "categories")
public class Category implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long categoryId;
#Column(nullable = false)
private String name;
private long level;
private long parentId;
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "categories")
private Set<Post> posts;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "userId")
private User user;
public Category() {
}
public Category(User user, long level, String name, long parentId) {
this.user = user;
this.level = level;
this.name = name;
this.parentId = parentId;
}
// ...
}
Then, I try to cache this methods:
#Service
#Repository
#Transactional
public class CategoryServiceImpl implements CategoryService {
#Resource
private CategoryRepository categoryRepository;
#Override
#CachePut(value = "category", key = "#category.categoryId")
public Category add(Category category) {
return categoryRepository.saveAndFlush(category);
}
#Override
#Cacheable("category")
public Category findById(long id) {
return categoryRepository.findOne(id);
}
#Override
#Cacheable("category")
public Category findByParentIdThroughCategoryId(long prntId, long userId) {
return categoryRepository.findByParentIdThroughCategoryId(prntId, userId);
}
#Override
#Cacheable("category")
public List<Category> findByParentId(long prntId, long userId) {
return categoryRepository.findByParentId(prntId, userId);
}
#Override
#Cacheable("category")
public List<Category> findAll(long userId) {
return categoryRepository.findAll(userId);
}
#Override
#CacheEvict("category")
public void remove(long id) {
categoryRepository.delete(id);
}
}
When adding a category, and then try to bring it to view all categories that have user findByParentId/findall, it returns an empty list
[]
It has something to do that for example I cache the categories, and then take the list of categories, I tried to get the category with ID 11 -- findById, and found:
ru.mrchebik.model.Category#f0b8277
Your setup has a number of problems both at Ehcache and Spring levels.
For Ehcache, you should not have a smaller disk size than the heap size. For a while now the tiering model in ehcache means that all entries must be in the disk tier, so you are effectively artificially constraining the heap size to the disk size with this setup.
On the Spring side, you are using a single cache to hold different things, but they will conflict.
Your #CachePut will store a single category, mapped to a long key which matches what your #Cacheable on findById does.
However, this will conflict with the #Cacheable on findAll which also uses a long as the key but caches a List<Category>. So any collision between userId and categoryId can cause unexpected class cast exceptions in client code - expecting a List getting a Category or the opposite.
Finally you have two methods which take two long as parameters but do a different service call while the caching is configured the same. And that service call returns again disjoint types - List<Category> and Category. Which will cause similar issues as in the previous point.
Also, I am under the impression that you expect single entry caching to magically append entries to matching lists. This is not going to happen.
I strongly recommend reviewing your caching needs and better understand what the Spring abstraction offers ... and what it does not.
I'm kinda new with the Spring's transaction management. I think I'm missing some configuration but I can't deal with it.
The error is that I'm getting failed to lazily initialize a collection of role exception.
I'm using Spring Data for my DAO. Also, I know about setting the fetchType to Eager but this is what I'm trying to avoid.
DAO:
public interface CourseDao extends CrudRepository<CourseEntity, Long> {
CourseEntity findByName(String name);
}
Service:
#Service
public class CourseMaterialSearchService {
private final CourseDao courseDao;
private final CourseMaterialEntityTransformer courseMaterialEntityTransformer;
#Autowired
public CourseMaterialSearchService(CourseDao courseDao, CourseMaterialEntityTransformer courseMaterialEntityTransformer) {
super();
this.courseDao = courseDao;
this.courseMaterialEntityTransformer = courseMaterialEntityTransformer;
}
#Transactional
public List<CourseMaterial> findMaterialsFor(final Long courseId) {
final CourseEntity entity = courseDao.findOne(courseId);
final List<CourseMaterialEntity> materials = entity.getCourseMaterialEntityList();
return courseMaterialEntityTransformer.transformEntities(materials);
}
}
And my application-context.xml is (of course this is just the relevant part):
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="example" />
<property name="dataSource" ref="exampleDataSource" />
<property name="packagesToScan" value="com.example.example.**.repository" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
</bean>
<tx:annotation-driven proxy-target-class="true" transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
When I call the findMaterialsFor method in CourseMaterialSearchService, the exception occurs. How should I solve this?
Any suggestions will be appreciated.
Thank you guys.
Stacktrace:
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.example.example.course.repository.domain.CourseEntity.courseMaterialEntityList, could not initialize proxy - no Session
org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:575)
org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:214)
org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:554)
org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:142)
org.hibernate.collection.internal.PersistentBag.iterator(PersistentBag.java:294)
com.example.example.course.service.transform.CourseMaterialEntityTransformer.transformEntities(CourseMaterialEntityTransformer.java:15)
com.example.example.course.service.CourseMaterialSearchService.findMaterialsFor(CourseMaterialSearchService.java:29)
CourseMaterialEntityTransformer:
public class CourseMaterialEntityTransformer {
public List<CourseMaterial> transformEntities(final Iterable<CourseMaterialEntity> entities) {
final List<CourseMaterial> result = new ArrayList<>();
for (final CourseMaterialEntity entity : entities) {
result.add(transformEntity(entity));
}
return result;
}
public CourseMaterial transformEntity(final CourseMaterialEntity entity) {
final CourseMaterial result = new CourseMaterial();
result.setId(entity.getId());
result.setName(entity.getName());
result.setCourseName(entity.getCourseEntity().getName());
result.setCurrentFileName(entity.getCurrentFileName());
result.setOriginalFileName(entity.getOriginalFileName());
result.setCategory(entity.getMaterialCategoryEntity().getName());
result.setUploader(entity.getUserEntity().getName());
return result;
}
}
com.example.example.course.service.transform.CourseMaterialEntityTransformer.transformEntities(CourseMaterialEntityTransformer.java:15):
for (final CourseMaterialEntity entity : entities) {
CourseEntity:
#Entity(name = "courses")
public class CourseEntity {
#Id
#GeneratedValue
private Long id;
private String name;
#OneToMany(mappedBy = "courseEntity")
private List<CourseMaterialEntity> courseMaterialEntityList;
public Long getId() {
return id;
}
public void setId(final Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(final String name) {
this.name = name;
}
public List<CourseMaterialEntity> getCourseMaterialEntityList() {
return courseMaterialEntityList;
}
public void setCourseMaterialEntityList(final List<CourseMaterialEntity> courseMaterialEntityList) {
this.courseMaterialEntityList = courseMaterialEntityList;
}
}
Spring applies transactions using AOP. AOP on beans is only applied to beans in the same application context.
You have a <tx:annotation-driven /> in your application-context.xml, which is loaded by the ContextLoaderListener. This file contains a <context:component-scan /> which detects the #Service.
However if you also have the same <context:component-scan /> in the file loaded by the DispatcherServlet, or at least if the same #Service is detected it results in another instance of this service which will not have AOP applied.
As a general rule-of-thumb you want to load everything BUT #Controllers in your ContextLoaderListener and only web related things (view resolvers, #Controllers) in your DispatcherServlet.
See context depended scan-component filter.
You are trying to access a lazy-loaded attribute outside of a transaction. The object then has no connection with the EntityManager (database), since it's outside of a transaction, and thus cannot go fetch the lazy-loaded attribute.
By default Collections are lazy-loaded . You can replace below your code :
#OneToMany(mappedBy = "courseEntity")
private List<CourseMaterialEntity> courseMaterialEntityList;
With :
#OneToMany(fetch = FetchType.EAGER, mappedBy = "courseEntity", cascade = CascadeType.ALL)
private List<CourseMaterialEntity> courseMaterialEntityList;
You need to change #OneToMany(mappedBy = "courseEntity") to #OneToMany(mappedBy = "courseEntity", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
The default fetch type is lazy so when you try and access the collection it hasn't been loaded from the database.
I'm trying to build this simple project but I keep getting the same error. Can anybody help figure this out?
HibernateTest.java
public class HibernateTest
{
public static void main(String[] args)
{
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
Query query = session.getNamedQuery("findById");
List<?> list = query.list();
if (!list.isEmpty())
{ UserDetails userD = (UserDetails) list.get(0);
System.out.println(userD); }
}
}
UserDetails.java
package com;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;
#Entity
#Table (name="UserDetails")
#NamedQuery(
name = "findById",
query = "SELECT x FROM UserDetails x WHERE x.id = '3'")
public class UserDetails
{
#Id
#Column(name="UserID")
private int id;
#Column(name="UserName")
private String name;
public void setId(int id)
{ this.id = id; }
public int getId()
{ return id; }
public void setName(String name)
{ this.name = name; }
public String getName()
{ return name; }
}
I'm not exactly sure what's wrong because I have the same query running in a different project and it works fine.
I got the same issue and i have resolved the issue by adding the following in applicationContext.xml.
<property name="annotatedClasses">
<list>
<value>com.Employee</value>
</list>
</property>
If you are using XML configuration, you can define a named query with the <query> tag. For example:
<query name = "findById">
<![CDATA[SELECT x FROM UserDetails x WHERE x.id = '3']]>
</query>
The <query> tag is on the same level as the <class> tag, as a child of the <hibernate-mapping> tag.
While this will not answer your immediate problem, if you are using Hibernate, and JPA annotations, why not using EntityManager instead of Hibernate session and stuff ?
With a Persistence Unit (as well as persistence.xml in your META-INF folder), you would do that:
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("persistenceUnit");
EntityManager em = emf.createEntityManager();
Query query = em.createNamedQuery("findById");
Or better:
TypedQuery<UserDetails> query = em.createNamedQuery("findById", UserDetails.class);
The method are roughly the same (after all, JPA was made of Hibernate).
I have a problem with lazy initialisation. I can't find a solution.
Exception:
[pool-1-thread-12] ERROR:12:20:14.840 o.h.LazyInitializationException - failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: de.beeld.forges.domain.Server.applications, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
[pool-2-thread-1] ERROR:12:20:14.840 o.s.s.support.MethodInvokingRunnable - Invocation of method 'readStatusCache' on target class [class de.beeld.forges.task.annotation.ScheduledProcessor$$EnhancerByCGLIB$$ee649dc3] failed
java.util.ConcurrentModificationException: null
at java.util.AbstractList$Itr.checkForComodification(AbstractList.java:372)
at java.util.AbstractList$Itr.next(AbstractList.java:343)
hibernate.xml
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"
p:dataSource-ref="standardDataSource" p:lobHandler-ref="defaultLobHandler">
<property name="annotatedClasses">
<list>
<value>de.beeld.forges.domain.Server</value>
<value>de.beeld.forges.domain.Application</value>
<value>de.beeld.forges.domain.Forge</value>
</list>
</property>
</property>
</bean>
<bean id="defaultLobHandler" class="org.springframework.jdbc.support.lob.DefaultLobHandler" />
<!-- Read in DAOs from the hibernate package -->
<context:component-scan base-package="de.beeld.forges.dao" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager"
p:sessionFactory-ref="sessionFactory" />
<bean id="transactionTemplate"
class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<context:component-scan base-package="de.beeld">
<context:exclude-filter expression="org.springframework.stereotype.Controller"
type="annotation" />
<context:exclude-filter expression="org.springframework.stereotype.Repository"
type="annotation" />
</context:component-scan>
<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
readStatusCache method:
public void readStatusCache() {
String execCommand = "java -jar ...";
List<Future<Map<Long, Integer>>> list = new ArrayList<Future<Map<Long, Integer>>>();
String serverName = null;
for (Server server : serviceFacade.getServers()) {
serverName = server.getName();
Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(),
sshConnector, execCommand, serverName);
Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker);
list.add(submit);
}
for (Future<Map<Long, Integer>> future : list) {
//do stuff
}
}
Server.java
#Entity
#org.hibernate.annotations.Entity(dynamicUpdate = true)
public class Server implements DomainObject, Comparable<Server> {
private static final long serialVersionUID = -8920952435734596243L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(unique = true, nullable = false)
#NotEmpty
private String name;
#Column(nullable = false)
#NotEmpty
#Pattern(regexp = "^([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.([01]?\\d\\d?|2[0-4]\\d|25[0-5])$", message = "The ip must be in format xxx.xxx.xxx.xxx")
private String ip;
#Column(nullable = false)
#NotEmpty
private String fqdn;
#OneToMany(mappedBy = "server", fetch = FetchType.LAZY)
private List<Application> applications;
#Version
private int version;
//getter and setter
}
Application.java
#Entity
public class Application implements DomainObject {
private static final long serialVersionUID = -8127137156319959239L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
private Server server;
#Column(nullable = false)
#NotEmpty
private String name;
#Column(nullable = false)
#NotEmpty
private String location;
#Column(nullable = false)
#NotEmpty
private String binDir;
private String confDir;
private boolean isContainer = false;
private String containerDir;
private String startup = "startup.sh";
private String shutdown = "shutdown.sh";
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private Forge forge;
#ManyToOne(fetch = FetchType.LAZY)
#Fetch(FetchMode.JOIN)
private Application parent;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private List<Application> offsprings;
#NotEmpty
private String blueprint;
private Integer replaceable = 0;
private Integer running = 0;
#Version
private int version;
//getter and setter
}
I don't really know why I cant read the list of applications from the server
If anybody could help it would be great.
Most likely because you're setting applications collection to lazy load. So when you return from the initial call to serviceFacade.getServers(), my guess is that you no longer have the session opened that was used to fetch the list of servers.
As a result, when you iterator through the applications, the session was closed, so it can't load the actual contents of the collection.
You have three possibilities:
Keep the session open (google for binding hibernate session to thread, or if the readStatusCache method is in a spring managed object, just add an #Transactional annotation to it, or the entry point from which it is called).
Change the applications collection to be an eager load
have your dao layer fully initialize the applications collection (see Hibernate.initialize method) while the session is still open.
The two loops
for (Server server : serviceFacade.getServers()) {
serverName = server.getName();
Callable<Map<Long, Integer>> worker = new ApplicationStatusReader2(server.getApplications(),
sshConnector, execCommand, serverName);
Future<Map<Long, Integer>> submit = this.serviceFacade.getExecutor().submit(worker);
list.add(submit);
}
for (Future<Map<Long, Integer>> future : list) {
//do stuff
}
are being called by two separate threads simultaneously. You can check if this is the case by synchronizing the readStatusCache() method. But this should be done in the Spring layer. Are you using transactions etc. properly?
Please read this answer for more on thread safety with spring and hibernate. Spring-Hibernate used in a webapp,what are strategies for Thread safe session management
When I got the same exception, the solution was to add the #Transactional annotation to the method in the controller.
Basically, how would I make it so that I can add a new TestEntity to the test set after the person has already been created? Also, how can I add a person that has a collection of TestEntity? I'm new to Hibernate so I feel I must be missing something since this would seem like a very common use case.
Some things I've tried:
Attempt #1:
PersonEntity person = createPerson("username");
TestEntity test = new TestEntity();
test.setTestId("2342");
test.setTestName("test name");
personDao.add(person);
person.addTest(test);
This results in the person being saved but no test information. Switching add and addTest does not change anything.
Attempt #2:
Adding a method like this to my Dao (based on http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-parentchild.html):
public void addTest(String personId, TestEntity test)
{
PersonEntity entity = (PersonEntity) getHibernateTemplate().getSessionFactory().getCurrentSession().load(PersonEntity.class, personId);
if (entity != null)
{
test.setPerson(entity);
entity.getTest().add(test);
getHibernateTemplate().getSessionFactory().getCurrentSession().save(entity);
getHibernateTemplate().getSessionFactory().getCurrentSession().flush();
}
}
And calling like this:
personDao.add(person);
personDao.addTest("username", test);
However, I get this error: org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here
Attempt #3:
Added #Transaction annotation to my dao and entity classes and added the following config to my app context:
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<!-- org.springframework.transaction.jta.JtaTransactionManager org.springframework.jdbc.datasource.DataSourceTransactionManager -->
<property name="dataSource" ref="dataSource" />
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven />
Now, using that method I created in attempt #2 and calling it in the same way, I get a stackoverflow error.
Edit Update: However, if I remove the test set from my hashCode method in PersonEntity, it works. I can also use person.addTest(test) and that will take care of adding a collection to the person entity before persisting the person entity. However, this really doesn't seem like it would be the best way to do it, no? What would be the best way to make this work? That dao method I added seems like it would be making more calls than necessary?
My classes:
PERSON
#Entity
#Table(name = "PERSON")
public class PersonEntity implements Serializable
{
private static final long serialVersionUID = -1699435979266209440L;
#Id
#Column(name = "PERSON_ID", length = 25, nullable = false)
private String personId;
#LazyCollection(value = LazyCollectionOption.FALSE)
#Cascade(CascadeType.ALL)
#OneToMany(targetEntity = TestEntity.class, mappedBy = "person")
#Where(clause="1=1")
private Set<TestEntity> test;
public void addTest(TestEntity testEntity)
{
testEntity.setPerson(this);
test.add(testEntity);
}
}
TEST
#Entity
#Table(name = "TEST")
public class TestEntity implements Serializable
{
private static final long serialVersionUID = -6524488155196023818L;
#Id
#Column(name = "TEST_ID", length = 36, nullable = false)
private String testId;
#ManyToOne
#Cascade(CascadeType.ALL)
#Index(name = "TEST_PERSON_ID_INDEX")
#JoinColumn(name = "PERSON_ID")
#ForeignKey(name = "FKT1_PERSON_ID")
private PersonEntity person;
#Column(name = "TEST_NAME", length = 60, nullable = false)
private String testName;
}
PersonDaoHibernate
public class PersonDaoHibernate extends HibernateDaoSupport implements PersonDao
{
public String add(PersonEntity person)
{
getHibernateTemplate().merge(person);
return person.getPersonId();
}
public void delete(String id)
{
Object entity = getHibernateTemplate().get(PersonEntity.class, id);
if (entity != null)
{
getHibernateTemplate().delete(entity);
}
}
public PersonEntity getById(String id)
{
return getHibernateTemplate().get(PersonEntity.class, id.toUpperCase());
}
}
I think you will have to change the method name to setTest(...), since hibernate follows java bean convention while trying to do the operation on properties.
Change that and I hope it should work fine.
Rest of code looks fine.