How to define associations in hibernate file - java

I have a query which when i run in sqlDeveloper i get the result. Here is the query
select * from Losa_Cust_Reject_App rejectApp
inner join
Losa_Cust losaCust
on
rejectApp.app_Ref_No = losaCust.app_Ref_No
where
rejectApp.app_Ref_No != '0000001912' and rejectApp.app_Dt >= '23-SEP-2012'
and
rejectApp.cust_Id1 = 'A111111111' and rejectApp.cust_Id1_Type = '01';
i translated this query to hibernate as following
public List findAppByDate(String appRefNo, Date previousAppDate, String currentId1,
String currentIdType1) {
StringBuffer query = new StringBuffer("from ");
query.append(LosaCustRejectApp.class.getName());
query.append(" rejectApp inner join ");
query.append(LosaCust.class.getName());
query.append(" losaCust with rejectApp.appRefNo = losaCust.comp_id.appRefNo");
query.append(" where rejectApp.appRefNo != ? and rejectApp.appDt >= ?");
query.append(" and rejectApp.custId1 = ? and rejectApp.custId1Type = ? ");
List result = null;
try {
result = getHibernateTemplate().find(query.toString(),
new Object[] { appRefNo, previousAppDate, currentId1, currentIdType1 });
if (CollectionUtils.isNotEmpty(result)) {
return result;
}
} catch (Exception e) {
String message = e.getMessage();
System.out.println();
}
return result;
}
But i want to define mapping in hibernate so hibernate make the join automatically. How can i define association in hibernate file for the above query so hibernate make the join automatically.
here is my LosaCustReject.hbm.xml
<hibernate-mapping default-lazy="false">
<class name="com.thetasp.losa.data.LosaCustRejectApp" table="LOSA_CUST_REJECT_APP" optimistic-lock="version">
<id name="rejectAppId" type="java.lang.Long" column="REJECT_APP_ID">
<generator class="com.thetasp.code.runningno.HibernateId">
<param name="fieldCode">REJECT_APP_ID</param>
<param name="returnType">java.lang.Long</param>
</generator>
</id>
<version name="rowVersion" type="int" column="ROW_VERSION" access="property" unsaved-value="undefined" />
<property name="appRefNo" type="java.lang.String" column="APP_REF_NO" not-null="true" length="20" />
<property name="appDt" type="java.sql.Timestamp" column="APP_DT" not-null="true" length="23" />
<property name="custId1Type" type="java.lang.String" column="CUST_ID1_TYPE" not-null="true" length="1" />
<property name="custId1" type="java.lang.String" column="CUST_ID1" not-null="true" length="20" />
.......
<property name="updateDt" type="java.sql.Timestamp" column="UPDATE_DT" length="23" />
<!-- associations -->
</class>
</hibernate-mapping>
LosaCust.hbm.xml
<hibernate-mapping default-lazy="false">
<class name="com.thetasp.losa.data.LosaCust" table="LOSA_CUST" discriminator-value="I" optimistic-lock="version">
<composite-id name="comp_id" class="com.thetasp.losa.data.LosaCustPK">
<key-property name="custId" column="CUST_ID" type="java.lang.String" length="20" />
<key-property name="appRefNo" column="APP_REF_NO" type="java.lang.String" length="20" />
</composite-id>
<discriminator column="CUST_T" type="string" length="1" >
</discriminator>
<version name="rowVersion" type="int" column="ROW_VERSION" access="property" unsaved-value="undefined" />
<property name="custLevel" type="java.lang.String" column="CUST_LEVEL" not-null="false" length="10" />
.....
<property name="staySinceMth" type="java.lang.String" column="STAYED_SINCE_MTH" length="10" />
....
<subclass name="com.thetasp.losa.data.LosaIndvCust" discriminator-value="I" lazy="false" >
<property name="id1Type" type="java.lang.String" column="ID1_TYPE" length="1" />
<property name="id1" type="java.lang.String" column="ID1" length="20" />
....
</subclass>
</class>
Thanks

I think you could do something like this
In LosaCust.java define a field representing the one-to-many association to LosaCustRejectApp entities:
List<LosaCustRejectApp> associatedLosaCustRejectApps;
In LosaCust.hbm.xml you map this new field using something like this:
<list name="associatedLosaCustRejectApps" table="LOSA_CUST_REJECT_APP" >
<key>
<column name="app_Ref_No" not-null="true" />
</key>
<one-to-many class="com.thetasp.losa.data.LosaCustRejectApp" />
</set>
For more details and even a complete tutorial on how to do this type of mapping you can go here:
Hibernate – One-to-Many example (XML Mapping)
Best regards

Related

Hibernate session.flush throws java.lang.StackOverflowError

I am using Hibernate 4.3.8.
Oracle Release 12.1.0.2.0 .
I have two entity name as Child and Parent Entity.
They are basically joined entity.
We are using Hibernate batching property for performance reason but when it try to save record in Child entity it throws StackOverflowError.
Hibernate Batching property:
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
Child Entity HBM
<hibernate-mapping>
<class entity-name="ChildEntity_Name" table="ChildEntity_DB" dynamic-insert="true" dynamic-update="true">
<id name="ID" type="java.lang.Long" column="ID">
<generator class="native"/>
</id>
<version name="RevisionId" access="field" column="RevisionId" type="java.lang.Long" unsaved-value="undefined" generated="never"/>
<property name="ModifiedUser" type="java.lang.String" column="ModifiedUser"/>
<property name="DealName_db" type="java.lang.String" column="DealName_db"/>
<property name="TotalPrice_db" type="java.lang.Long" column="TotalPrice_db"/>
<property name="DealDate_db" type="java.lang.String" column="DealDate_db"/>
<property name="ModifiedDate" type="java.util.Date" column="ModifiedDate"/>
<property name="CreatedUser" type="java.lang.String" column="CreatedUser"/>
<property name="CreatedDate" type="java.util.Date" column="CreatedDate"/>
<many-to-one name="CE_UK" entity-name="Parent_Entity_Name" property-ref="UK_PD1" unique="false" fetch="join" update="true" insert="true">
<column name="CustID_db" not-null="true"/>
</many-to-one>
<properties name="UK_Child" unique="true" insert="true" update="true">
<property name="DealId_db" type="java.lang.String" column="DealId_db"/>
</properties>
</class>
</hibernate-mapping>
Parent Entity HBM:
<hibernate-mapping>
<class entity-name="Parent_Entity_Name" table="Parent_Entity_DB" dynamic-insert="true" dynamic-update="true" mutable="true" polymorphism="implicit" select-before-update="false" optimistic-lock="version">
<id name="ID" type="java.lang.Long" column="ID">
<generator class="native"/>
</id>
<version name="RevisionId" access="field" column="RevisionId" type="java.lang.Long" unsaved-value="undefined" generated="never"/>
<property name="ModifiedUser" type="java.lang.String" column="ModifiedUser" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<property name="CustName_db" type="java.lang.String" column="CustName_db" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<property name="CustAddress_db" type="java.lang.String" column="CustAddress_db" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<property name="ModifiedDate" type="java.util.Date" column="ModifiedDate" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<property name="CreatedUser" type="java.lang.String" column="CreatedUser" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<property name="CreatedDate" type="java.util.Date" column="CreatedDate" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
<properties name="UK_PD1" unique="true" insert="true" update="true" optimistic-lock="true">
<property name="CustID_db" type="java.lang.String" column="CustID_db" unique="false" optimistic-lock="true" lazy="false" generated="never"/>
</properties>
</class>
</hibernate-mapping>
Class:
import java.util.HashMap;
import java.util.Map;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
public class TestBatching {
public static void main(String[] args) {
Session session = null;
Transaction tx = null;
try {
session = HibernateUtil.getSessionFactory().openSession();
System.out.println("Got the hibernate session ...");
tx = session.beginTransaction();
System.out.println("Opening tx ...");
Map<String, Object> parentEntityMap = new HashMap();
HashMap uniqueKeyMapping = new java.util.HashMap<>();
uniqueKeyMapping.put("CustID_db", String.valueOf(1));
parentEntityMap.put("CustID_db", String.valueOf(1));
parentEntityMap.put("UK_PD1", uniqueKeyMapping);
parentEntityMap.put("CustName_db", String.valueOf("John"));
parentEntityMap.put("CustAddress_db", String.valueOf("Mumbai"));
parentEntityMap.put("ModifiedDate", java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));
parentEntityMap.put("CreatedDate", java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));
parentEntityMap.put("ModifiedUser", String.valueOf("User1"));
parentEntityMap.put("CreatedUser", String.valueOf("User1"));
System.out.println("Saving record in Parent Entity ......");
session.save("Parent_Entity_Name", parentEntityMap);
System.out.println("Saved record in Parent Entity ......");
Map<String, Object> childEntityMap = new HashMap();
HashMap uniqueKeyMapping1 = new java.util.HashMap<>();
uniqueKeyMapping1.put("DealId_db", String.valueOf(1));
childEntityMap.put("UK_Child", uniqueKeyMapping1);
childEntityMap.put("DealId_db", String.valueOf(1));
childEntityMap.put("CustID_db", String.valueOf(1));
childEntityMap.put("DealName_db", String.valueOf("SS"));
childEntityMap.put("DealDate_db", "2017-11-15 15:30:14.332");
childEntityMap.put("TotalPrice_db", Long.valueOf(100));
childEntityMap.put("RevisionId", Long.valueOf("1"));
HashMap fkMapping = new java.util.HashMap<>();
fkMapping.put("CustID_db", String.valueOf(1));
fkMapping.put("ID", Long.valueOf("1"));
fkMapping.put("UK_PD1", fkMapping);
fkMapping.put("RevisionId", Long.valueOf("1"));
childEntityMap.put("CE_UK", fkMapping);
childEntityMap.put("ModifiedDate", java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));
childEntityMap.put("CreatedDate", java.sql.Timestamp.valueOf("2017-11-15 15:30:14.332"));
childEntityMap.put("ModifiedUser", String.valueOf("User1"));
childEntityMap.put("CreatedUser", String.valueOf("User1"));
System.out.println("Saving record in Child Entity ......");
session.save("ChildEntity_Name", childEntityMap);
System.out.println("Saved record in Child Entity ......");
System.out.println("Flushing session ......");
session.flush();
System.out.println("Flushed session ......");
System.out.println("Commiting tx ......");
tx.commit();
System.out.println("Commited tx ......");
} catch (Exception e) {
e.printStackTrace();
} finally {
if (session != null) {
session.close();
System.out.println(" closing hibernate session ...");
}
}
}
}
Hibernate Configuration:
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:#localhost:1521:xe</property>
<property name="hibernate.connection.username">user1</property>
<property name="hibernate.connection.password">user1</property>
<!-- Hibernate caching settings -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<property name="hibernate.cache.use_second_level_cache">false</property>
<!-- Hibernate-c3p0 settings -->
<property name="hibernate.c3p0.min_size">2</property>
<property name="hibernate.c3p0.max_size">50</property>
<property name="hibernate.c3p0.acquire_increment">1</property>
<property name="hibernate.c3p0.idle_test_period">100</property>
<property name="hibernate.c3p0.timeout">100</property>
<property name="hibernate.c3p0.max_statements">0</property>
<!-- Hibernate-Batching settings -->
<property name="hibernate.jdbc.batch_size">100</property>
<property name="hibernate.jdbc.batch_versioned_data">true</property>
<property name="hibernate.order_inserts">true</property>
<property name="hibernate.order_updates">true</property>
<!-- HBM Mapping files -->
<mapping resource="Child_entity.hbm.xml"/>
<mapping resource="Parent_entity.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Output:
Got the hibernate session ...
Opening tx ...
Saving record in Parent Entity ......
Saved record in Parent Entity ......
Saving record in Child Entity ......
Saved record in Child Entity ......
Flushing session ......
closing hibernate session ...
Exception in thread "main" java.lang.StackOverflowError
at java.base/java.lang.Long.hashCode(Long.java:1402)
at java.base/java.util.Objects.hashCode(Objects.java:116)
at java.base/java.util.HashMap$Node.hashCode(HashMap.java:297)
at java.base/java.util.AbstractMap.hashCode(AbstractMap.java:527)
at java.base/java.util.Objects.hashCode(Objects.java:116)
Note: Without hibernate batching property it is working fine.
Can anyone please help me here?

Many to many xml relationship using spring giving same object in owner oject

I have two tables user and dailyGame in which there are may-to-mapping. And I want to send following information in response to show daily game list:
gameName
format
startTime
fees
member count (I want to get count from 3rd table ie. dailyGame_user.)
My user.hbm.xml file contains :
<set name="dailyGames" table="dailygame_user"
inverse="false" lazy="true" fetch="select" cascade="all" >
<key>
<column name="userId" not-null="true" />
</key>
<many-to-many entity-name="com.mindbowser.draftDynasty.dto.DailyGameDTO">
<column name="groupId" not-null="true" />
</many-to-many>
</set>
And DailyGame.hbm.xml :
<set name="members" table="dailygame_user" inverse="true" lazy="true" fetch="select">
<key>
<column name="gameId" not-null="true" />
</key>
<many-to-many entity-name="com.mindbowser.draftDynasty.dto.UserDTO">
<column name="userId" not-null="true" />
</many-to-many>
</set>
UserDTO.java:
Set<DailyGameDTO> dailyGames = new HashSet<DailyGameDTO>();
DailyGameDTO.java:
Set<UserDTO> members = new HashSet<UserDTO>();
And for fetching Daily game List I am using following code:
dailyGameDao:
public List<DailyGameDTO> getDailyGameList() {
List<DailyGameDTO> gameList = null;
DailyGameDTO dailyGameDTO=null;
List<DailyGameDTO> memList=null;
try {
Criteria criteria = getCurrentSession().createCriteria(DailyGameDTO.class);
gameList = criteria.list();
} catch (HibernateException ex) {
logger.error(ex.getStackTrace(), ex);
throw ex;
}
return gameList;
}
This "gameList" variable should consist userDTO object but it contains dailyGameDTO object only instead of userDTO .
try to change lazy="true" to lazy="false".

Blocking Queue, Single Producer - Multiple Consumer Synchronization issues

I want to confirm before going my code to production.
I am using LinkedBlockingQueue like shown below.
I have one producer thread and five consumer thread.
Consumer thread does DB operation, So I have increased it to 5 to fasten the process.
Now, is there any way I will run into (Synchronization/Multiple updates for row/or any issue which I need to take care) problem either at Code or DB level.
Below is my complete code.
private int numberOfConsumers = 5;
private LinkedBlockingQueue<RequestParameters> processorQueue;
public void init(){
processorQueue = new LinkedBlockingQueue<RequestParameters>();
for (int i = 0; i < numberOfConsumers ; i++) {
try {
QueueConsumer c = new QueueConsumer(processorQueue);
c.setName("ThreadName-"+i);
c.start();
} catch (Exception e) {
logger.error("", e);
}
}
this.postCallProcessorDaemon = this;
}
class QueueConsumer extends Thread {
private Logger log = Logger.getLogger(QueueConsumer.class);
private final BlockingQueue<RequestParameters> queue;
QueueConsumer(BlockingQueue<RequestParameters> q) { queue = q; }
public void run() {
try {
while (true) {
RequestParameters rp = queue.take();
consumeRecord(rp);
}
} catch (Exception ex) {
log.error("Exception in run method", ex);
}
}
void consumeRecord(RequestParameters requestParameters)
{
try{
process(requestParameters);
} catch (Throwable e) {
log.error("Exception",e);
}
}
private void process(RequestParameters requestParameters) throws Exception{
for (Action each : allActions) {
if(each.doProcessing(requestParameters)){
boolean status = each.process(requestParameters);
}
}
}
}
public boolean process(RequestParameters parameters) {
//In my process method, I am inserting rows in table based on data in Queue.
}
HBM file which I am using for ORM mapping
<class name="CampaignSubscriptionsSummary" table="campaign_subscriptions_summary">
<composite-id name="id" class="com.on.robd.config.db.reports.CampaignSubscriptionsSummaryId">
<key-property name="reportTime" type="timestamp">
<column name="REPORT_TIME" length="19" />
</key-property>
<key-property name="campaignId" type="long">
<column name="CAMPAIGN_ID" />
</key-property>
<key-property name="recipient" type="string">
<column name="RECIPIENT" length="24" />
</key-property>
<key-property name="selectedPack" type="string">
<column name="SELECTED_PACK" length="256" />
</key-property>
</composite-id>
<many-to-one name="campaign" class="com.on.robd.config.db.campaigns.Campaign" update="false" insert="false" fetch="select">
<column name="CAMPAIGN_ID" not-null="true" />
</many-to-one>
<many-to-one name="campaignSubscriptionsStatusDim" class="com.on.robd.config.db.reports.CampaignSubscriptionStatusDim" fetch="select">
<column name="SUBSCRIPTION_STATUS_ID" not-null="true" />
</many-to-one>
<property name="sender" type="string">
<column name="SENDER" length="24" not-null="true" />
</property>
<property name="callDuration" type="java.lang.Integer">
<column name="CALL_DURATION" />
</property>
<property name="dtmfInput" type="string">
<column name="DTMF_INPUT" length="16" not-null="true" />
</property>
<property name="promptForPack" type="string">
<column name="PROMPT_FOR_PACK" length="256" />
</property>
<property name="wavFile" type="string">
<column name="WAV_FILE" length="256" />
</property>
<property name="subscriptionUrl" type="string">
<column name="SUBSCRIPTION_URL" length="256" />
</property>
<property name="language" type="string">
<column name="LANGUAGE" length="256" />
</property>
<property name="reobdTime" type="timestamp">
<column name="REOBD_TIME" length="19" />
</property>
<many-to-one name="campaignTypeDim" class="com.on.robd.config.db.reports.CampaignTypeDim" fetch="select">
<column name="CAMPAIGN_TYPE_ID" not-null="true" />
</many-to-one>
</class>
Most likely you'll have DB locking issues between the consumers, but it depends on your database vendor. Check your DB vendors docs to see if it uses table, row or partition locking on write.
But Regardless you'll get better write performance is you use batch inserting. See http://docs.jboss.org/hibernate/orm/3.3/reference/en-US/html/batch.html . The simplest way to batch, would be to have your Producer push a collection of RequestParameters into your BlockingQueue. This could also reduce the number of open connections you have to the DB which will also help with performance.

Hibernate exception on open sessions. How can I debug this?

I am newbie in hybernate and I am struggling with the following exception:
Exception in thread "AWT-EventQueue-0"
org.hibernate.HibernateException: illegally attempted to associate a
proxy with two open Sessions
I get this when I try to delete an object (an order).
My setting/code:
Order.hbm.xml
<hibernate-mapping>
<class name="com.database.entities.Order" table="ORDERS">
<id name="orderId" type="java.lang.Long">
<column name="ORDERID" />
<generator class="identity" />
</id>
<property name="product" type="java.lang.String">
<column name="SHIP" />
</property>
<property name="orderDate" type="java.util.Date">
<column name="ORDERDATE" />
</property>
<property name="quantity" type="java.lang.Integer">
<column name="QUANTITY" />
</property>
<many-to-one name="customer" class="com.database.entities.Customer" fetch="join">
<column name="CUSTOMERID"/>
</many-to-one>
<many-to-one name="associate" column="ASSOCIATEID" class="com.database.entities.Employee" fetch="join">
</many-to-one>
</class>
</hibernate-mapping>
A session holder:
public class DBSession {
private static SessionFactory sessionFactory;
static{
Configuration cfg = new Configuration();
sessionFactory = cfg.configure().buildSessionFactory();
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown() {
getSessionFactory().close();
}
}
And relevant DAOs all extending the following:
public abstract class GenericDAO<T, ID extends Serializable> implements GenericDAOIF<T, ID> {
private Class<T> persistentClass;
private Session session;
public Session getSession() {
if(session == null || !session.isOpen()){
session = DBUtil.getSessionFactory().openSession();
}
return session;
}
public void setSession(Session session) {
this.session = session;
}
#SuppressWarnings("unchecked")
#Override
public T findById(ID id, boolean lock) {
T entity;
if(lock)
entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE);
else
entity = (T) getSession().load(getPersistentClass(), id);
return entity;
}
#Override
public T makePersistent(T entity) {
getSession().beginTransaction();
getSession().saveOrUpdate(entity);
flush();
getSession().getTransaction().commit();
return entity;
}
#Override
public void flush() {
getSession().flush();
}
#Override
public void clear() {
getSession().clear();
}
#Override
public void makeTransient(T entity) {
getSession().getTransaction().begin();
getSession().delete(entity);
getSession().getTransaction().commit();
}
}
While all the other queries work (e.g. insert/select for other entities and order) when I try to delete an order I get the following exception in the following part of the code of GenericDAO:
public void makeTransient(T entity) {
getSession().getTransaction().begin();
getSession().delete(entity);//--> Exception here
getSession().getTransaction().commit();
}
The exception stack trace:
Exception in thread "AWT-EventQueue-0" org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions
at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126)
at org.hibernate.engine.StatefulPersistenceContext.reassociateProxy(StatefulPersistenceContext.java:573)
at org.hibernate.engine.StatefulPersistenceContext.unproxyAndReassociate(StatefulPersistenceContext.java:618)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:89)
at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73)
at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956)
at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934)
at com.dao.GenericDAO.makeTransient(GenericDAO.java:100)
at com.ui.panels.AdminDBPanel$11.actionPerformed(AdminDBPanel.java:414)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
This happens only when I delete an order (that is why I posted only that part of code).
I do not understand what this exception means.
But searching Google I tried the following which did not work:
1) Merging with session:
#Override
public void makeTransient(T entity) {
getSession().merge(entity);
getSession().getTransaction().begin();
getSession().delete(entity);
getSession().getTransaction().commit();
}
2) Closing the session and reopening it:
public Session getSession() {
if(session == null || !session.isOpen()){
session = DBUtil.getSessionFactory().openSession();
}
else{
session.close();
session = DBUtil.getSessionFactory().openSession();
}
return session;
}
I am stuck on how to debug this.
Any input is highly welcome
UPDATE:
Extra info:
Employee mapping:
<hibernate-mapping>
<class name="com.database.entities.Employee" table="ASSOCIATE">
<id name="assosiateId" type="java.lang.Long">
<column name="ASSOCIATEID" />
<generator class="identity" />
</id>
<property name="firstName" type="java.lang.String" not-null="true">
<column name="FIRSTNAME" />
</property>
<property name="lastName" type="java.lang.String" not-null="true">
<column name="LASTNAME" />
</property>
<property name="userName" type="java.lang.String" not-null="true">
<column name="USERNAME" />
</property>
<property name="password" type="java.lang.String" not-null="true">
<column name="PASSWORD" />
</property>
<set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true">
<key>
<column name="ASSOCIATEID" />
</key>
<one-to-many class="com.database.entities.Order" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.database.entities.Customer" table="CUSTOMER">
<id name="customerId" type="java.lang.Long">
<column name="CUSTOMERID" />
<generator class="identity" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMERNAME" />
</property>
<set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true">
<key>
<column name="CUSTOMERID" />
</key>
<one-to-many class="com.database.entities.Order" />
</set>
</class>
</hibernate-mapping>
Customer mapping:
<hibernate-mapping>
<class name="com.database.entities.Customer" table="CUSTOMER">
<id name="customerId" type="java.lang.Long">
<column name="CUSTOMERID" />
<generator class="identity" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMERNAME" />
</property>
<set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true">
<key>
<column name="CUSTOMERID" />
</key>
<one-to-many class="com.database.entities.Order" />
</set>
</class>
</hibernate-mapping>
OrderDAO:
public class OrderDAO extends GenericDAO<Order, Long> implements OrderDAOIF {
#Override
public void addOrder(Order order, Customer customer, Associate associate) {
Session session = getSession();
Transaction tx = session.beginTransaction();
order.setAssociate(associate);
order.setCustomer(customer);
session.saveOrUpdate(order);
tx.commit();
session.close();
}
#Override
public void updateOrderStatus(String status, Long orderId) {
Order order = findById(orderId, false);
order.setOrderState(status);
Session session = getSession();
Transaction tx = session.beginTransaction();
session.saveOrUpdate(order);
tx.commit();
session.close();
}
}
The code that starts the exception:
Order order = getFactory().getOrderDAO().findById(Long.valueOf(orderId), false);
getFactory().getOrderDAO().makeTransient(order);//--> Exception thrown here
The error means that you are trying to associate a object loaded in one session with another session. There is a bigger issue with how you are doing session management - but I cannot comment on that without a lot more info. The merge work around you tried can fix the problem with a simple change - use the reference returned by the merge method for further operation.
#Override
public void makeTransient(T entity) {
T newEntityRef = getSession().merge(entity);
getSession().getTransaction().begin();
getSession().delete(newEntityRef);
getSession().getTransaction().commit();
}
The problem is due to this piece of code.
Order order = getFactory().getOrderDAO().findById(Long.valueOf(orderId), false);
getFactory().getOrderDAO().makeTransient(order);//--> Exception thrown here
Assuming that the getOrderDao() is creating a new instance of the the OrderDao class. The call to findById uses a new instance of session (let us call it s1) to load the object. The loaded object is a proxy which is associated with the session that was used to load it. Then next call creates a new OrderDAO (by calling getOrderDAO method) - now when makeTransient is called a new session (let us call this s2) is created. You are now trying to pass a proxy loaded by s1 to s2 - which is what the exception is indicating. Merge method takes the object and either creates a new object in s2 or merges content with an existing object - either ways the input object passed is not changed - the new object that is created will be the return value.
Writing the code this way will also fix the issue without the merge.
OrderDao orderDao = getFactory().getOrderDAO();
Order order = orderDao.findById(Long.valueOf(orderId), false);
orderDao.makeTransient(order);
The other problem with the above code is that the session is not getting closed. Each session uses a JDBC connection - so it will lead to a connection leak.
Take a look at the following to get an idea of how to fix your code. Basically your DAO should not open a new session and should not be managing transactions. You should be doing it outside.
http://community.jboss.org/wiki/SessionsAndTransactions
http://community.jboss.org/wiki/GenericDataAccessObjects

Hibernate's session.update(obj) method makes child objects transient (in parent/child relationship)

I have a parent-/child relationship of folders, which looks like this:
A folder can have 0-1 parent folders.
A folder can have 0-n child folders (subfolders).
Using Hibernate, I call session.update(folder) on these folders.
When such a folder has NO subfolders, everything works alright.
BUT when a folder has subfolders, session.update(folder) will make the subfolder(s) transient (subfolder's id changes from 4 to 0!).
How can that be?
Here is my mapping file:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="test.Folder" table="FOLDERS">
<id name="id" type="long" access="field">
<column name="FOLDER_ID" />
<generator class="native" />
</id>
<set name="childFolders" table="FOLDERS" lazy="false" inverse="true" cascade="none">
<key column="PARENT_FOLDER_ID" not-null="false"></key>
<one-to-many class="test.Folder" />
</set>
<many-to-one name="parentFolder" column="PARENT_FOLDER_ID" />
<property name="name" column="FOLDER_NAME" />
<property name="rootFolder" column="IS_ROOT_FOLDER" type="boolean" not-null="true" />
<property name="path" column="FOLDER_PATH" />
<property name="type" column="FOLDER_TYPE" />
<property name="fullPath" column="FULL_PATH" unique="true" not-null="true" />
</class>
</hibernate-mapping>
Update: Here is the Java code I use to update the folder:
public class DatabaseController{
private SessionFactory sessionFactory = null;
public void updateFolder(Folder folder){
Session session = null;
Transaction transaction = null;
try {
session = getSession();
transaction = session.beginTransaction();
session.update(folder);
transaction.commit();
} catch (Exception e) {
rollback(transaction);
closeSession();
} finally {
closeSession();
}
}
/*
* Returns the Hibernate session
*/
private Session getSession() {
if (_session == null) {
_session = getSessionFactory().getCurrentSession();
}
if (_session.isOpen() == false) {
_session = getSessionFactory().openSession();
}
return _session;
}
/**
* Returns the session factory
*
* #return The session factory
*/
public SessionFactory getSessionFactory() {
return sessionFactory;
}
}
That's correct
you have cascade="none" in your set definitions.
http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-transitive
You need to set cascade="save-update".
I found a solution to the problem. Changing the following lines in my hibernate mapping file fixed the issue:
<set name="childFolders" table="FOLDERS" inverse="true" cascade="none">
<key column="PARENT_FOLDER_ID"></key>
<one-to-many class="test.Folder" />
</set>
I think, removing not-null="false" for the key did the trick here.
your code :
UPDATE 2
<set name="childFolders" table="FOLDERS" lazy="false" inverse="true" cascade="none">
<key column="PARENT_FOLDER_ID" not-null="false"></key>
<one-to-many class="test.Folder" /> // **this should point to child table not itself**
</set>
you have given wrong relation ship
my code :
<set cascade="all, delete-orphan" name="childTable" order-by="param" inverse="true">
<key>
<column name="p_id"/>
</key>
<one-to-many class="com.a.data.ChildTable"/>
</set>

Categories