I'm trying to lazily load a collection in Hibernate. From what I've read this is the best practice way to do this:
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Hibernate.initialize(this.truckReviews);
session.getTransaction().commit();
session.close();
return this.truckReview;
However, when I run this unit test, the assertion fails:
Truck realTruck = Truck.getTruckByID(1);
TruckReview realFakeReview = new TruckReview();
realFakeReview.setTruck(realTruck);
realFakeReview.setUser(IntegrationTestResources.getTestUser());
realFakeReview.setReviewDate(new Date());
realFakeReview.setReviewStars(5);
realFakeReview.setReviewText("fake review");
realFakeReview.save();
assertTrue(realTruck.loadReviews().contains(realFakeReview));
realFakeReview.delete();
Needless to say, I'm a bit confused since other StackOverflow threads say this is the way to do it properly. I feel like I must be missing something very obvious but I'm still new to Hibernate and have no idea what.
Here's the mapping file for this class:
<hibernate-mapping>
<class name="edu.temple.tutrucks.Truck" table="truck" catalog="TUTrucks" optimistic-lock="version">
<id name="id" type="int">
<column name="id" />
<generator class="identity" />
</id>
<property name="truckName" type="string">
<column name="truck_name" not-null="true" />
</property>
<property name="latitude" type="double">
<column name="latitude" precision="22" scale="0" not-null="true" />
</property>
<property name="longitude" type="double">
<column name="longitude" precision="22" scale="0" not-null="true" />
</property>
<property name="openingTime" type="imm_time">
<column name="opening_time" not-null="false"></column>
</property>
<property name="closingTime" type="imm_time">
<column name="closing_time" not-null="false"></column>
</property>
<property name="avatar" type="string">
<column name="avatar"></column>
</property>
<list name="truckReviews" table="truck_review" inverse="true" lazy="true" fetch="select">
<key>
<column name="truck_id" />
</key>
<list-index column="review_stars" />
<one-to-many class="edu.temple.tutrucks.TruckReview" />
</list>
<list name="menus" table="menu" inverse="true" lazy="false" fetch="select">
<key>
<column name="truck_id" />
</key>
<list-index column="id" />
<one-to-many class="edu.temple.tutrucks.Menu" />
</list>
<set name="tags" table="tag_truck_map" inverse="true" lazy="true" fetch="select">
<key>
<column name="truck_id" />
</key>
<many-to-many column="tag_id" class="edu.temple.tutrucks.Tag"></many-to-many>
</set>
</class>
</hibernate-mapping>
Thanks in advance.
UPDATE: Still having issues, I've changed the loadReviews method to this
#Override
public Truck loadReviews() { // lazy loading needs to be fixed
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Truck retval = (Truck) session.get(Truck.class, this.getId());
Hibernate.initialize(retail.getTruckReviews());
session.getTransaction().commit();
session.close();
retval.truckReviews.size();
return retval;
}
And the test now looks like this
#Test
public void testloadReviews() {
Truck realTruck = Truck.getTruckByID(1, false, false);
TruckReview realFakeReview = new TruckReview();
realFakeReview.setTruck(realTruck);
realFakeReview.setUser(IntegrationTestResources.getTestUser());
realFakeReview.setReviewDate(new Date());
realFakeReview.setReviewStars(5);
realFakeReview.setReviewText("fake review");
realFakeReview.save();
assertTrue(realTruck.loadReviews().getTruckReviews().contains(realFakeReview));
realFakeReview.delete();
}
The problem is that you can't to use realTruck form one session to do Hibernate.initialize(this.truckReviews) using other session
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
// you need to reload persistent with
// realTruck = session.get(), realTruck = session.load() here
Hibernate.initialize(this.getTruckReviews());
You need to use a getter not a property, because of Hibernate need to have a proxy. A proxy is returned by a getter
Hibernate.initialize(this.getTruckReviews());
Related
How to get only parent without children in Hibernate and without lazy exception, when you trying to access chidlren filed after closing session?
I mean, a kind of pure parent obtainingm but I beed to be sure, that somebody will not obtain them with getter or will not catch a lazy exception.
<class name="com.electronic.commerce.models.Category" table="Category">
<id name="id" type="long" access="property">
<column name="categoryId" length="20"/>
<generator class="native"/>
</id>
<property name="name" column="categoryName" type="string"/>
<property name="parentId" column="categoryParentId" type="long"/>
<bag name="children" table="Category" inverse="true" lazy="true" fetch="select">
<key>
<column name="categoryParentId" not-null="true"/>
</key>
<one-to-many class="com.electronic.commerce.models.Category"/>
</bag>
</class>
Mixed solution
Xml:
<prop key="hibernate.enable_lazy_load_no_trans">false</prop>
Java:
DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
defaultTransactionDefinition.setPropagationBehavior(transactionDefinition);
transactionManager.getTransaction(defaultTransactionDefinition);
I have auto generated the code using netbeans to create a Hibernate configuration; so I have two tables mapped like this (Many-to-Many) :
<hibernate-mapping auto-import="true">
<class name="com.antoiovi.jobprograms.entity.Roles" table="roles" catalog="jobprograms">
<id name="rolesName" type="string">
<column name="roles_name" length="20" />
<generator class="assigned" />
</id>
<set name="userses" table="users_roles" inverse="true" lazy="false" fetch="select" cascade="all">
<key>
<column name="role_name" length="20" not-null="true" />
</key>
<many-to-many entity-name="com.antoiovi.jobprograms.entity.Users">
<column name="user_name" length="15" not-null="true" />
</many-to-many>
</set>
</class>
<hibernate-mapping auto-import="true">
<class name="com.antoiovi.jobprograms.entity.Users" table="users" catalog="jobprograms">
<id name="idusers" type="java.lang.Integer">
<column name="idusers" />
<generator class="identity" />
</id>
<property name="userName" type="string">
<column name="user_name" length="15" not-null="true" unique="true" />
</property>
<property name="userPass" type="string">
<column name="user_pass" length="15" not-null="true" />
</property>
<property name="firstName" type="string">
<column name="first_name" length="20" />
</property>
<property name="lastName" type="string">
<column name="last_name" length="25" />
</property>
<set name="roleses" table="users_roles" inverse="true" lazy="false" fetch="select" cascade="all">
<key>
<column name="user_name" length="15" not-null="true" />
</key>
<many-to-many entity-name="com.antoiovi.jobprograms.entity.Roles">
<column name="role_name" length="20" not-null="true" />
</many-to-many>
</set>
<set name="jobprograms" table="jobprogram" inverse="true" lazy="false" fetch="select" cascade="all">
<key>
<column name="users_idusers" not-null="true" />
</key>
<one-to-many class="com.antoiovi.jobprograms.entity.Jobprogram" />
</set>
</class>
I have made some modification as you can see above (auto-import=true, lazy=false), cause i have the error message
rg.hibernate.MappingException: An association from the table users_roles refers to an unmapped class: com.antoiovi.jobprograms.entity.Roles
at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1824)
at org.hibernate.cfg.Configuration.originalSecondPassCompile(Configuration.java:1756)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1423)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1856)
The config file is
<hibernate-configuration>
org.hibernate.dialect.MySQLDialect
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/jobprograms?zeroDateTimeBehavior=convertToNull
jobprograms_ad
xxxxx
thread
true
org.hibernate.hql.classic.ClassicQueryTranslatorFactory
true
the classes have refernce like this :
'#ManyToMany(fetch=FetchType.LAZY, mappedBy="roleses")
public Set<Users> getUserses() {
return this.userses;
} '
#ManyToMany(fetch=FetchType.EAGER)
#JoinTable(name="users_roles", catalog="jobprograms", joinColumns = {
#JoinColumn(name="user_name", nullable=false, updatable=false) }, inverseJoinColumns = {
#JoinColumn(name="role_name", nullable=false, updatable=false) })
public Set<Roles> getRoleses() {
return this.roleses;
}
wHEN RUNNING I HAVE THE ERROR org.hibernate.exception.SQLGrammarException, and in fact the entiti is loaded, but the set<> not..,
When testing the error is
org.hibernate.MappingException: An association from the table users_roles refers to an unmapped class: com.antoiovi.jobprograms.entity.Roles, and the HSQL ar not executed.
I tried to look in others post but i couldn't find an answer. Can anybody help me?
In config file the entities are all declared;
I think yhe promlem is in the mapping :
e <set name="roleses" table="users_roles" inverse="false" lazy="true" fetch="select" >
<key >
<column name="user_name" length="15" not-null="true" />
</key>
<many-to-many entity-name="test.Roles" property-ref="rolesName">
<column name="role_name" length="20" not-null="true" />
</many-to-many>
</set>
<set name="jobprograms" table="jobprogram" inverse="true" lazy="true" fetch="select">
<key>
<column name="users_idusers" not-null="true" />
</key>
<one-to-many class="test.Jobprogram" />
</set>
and
enter <class name="test.Roles" table="roles" catalog="jobprograms">
<id name="rolesName" type="string">
<column name="roles_name" length="20" />
<generator class="assigned" />
</id>
<set name="userses" table="users_roles" inverse="true" lazy="true" fetch="select">
<key property-ref="rolesName">
<column name="role_name" length="20" not-null="true" />
</key>
<many-to-many entity-name="test.Users" property-ref="userName">
<column name="user_name" length="15" not-null="true" />
</many-to-many>
</set>
</class>
....
this error
org.hibernate.MappingException: An association from the table users_roles refers to an unmapped class: com.antoiovi.jobprograms.entity.Roles
comes when hibernate configuration dont know about entity(Roles) mapping , either you have missed introducing enitity Roles to the hibernate configuration or you have not used correct name , please check configuraiton file and included com.antoiovi.jobprograms.entity.Roles as resourse
I think to have resolved the problem. Actually the proble are unmapped entities. But this happens because the database is not 'well formed'. Indeed the database ha 3 table users, users_roles, roles; the table roles has only one column as primarykey (varchar),and the table user_roles refers to it from its column user_roles; when forword enginering the ide (in the case netbeans) creates only 2 entities: 'Users', and 'Roles'; So i have re-designed the schema putting some virtual primary key, and creating unique constaint instead. Now i have 3 entities : Users,UserRoles, and Roles.
Student s = (Student) db.getByID(Student.class,1);
s.setFirstName("Preston");
db.saveOrUpdate(s); <--Successful save
s = new Student(){{setFirstName("asdf");setLastName("asdf1");}};
s.setSchool((School) db.getByID(School.class, 1));
db.saveOrUpdate(s); <--Error occurs
Exception in thread "main" org.hibernate.MappingException: Unknown entity: project.databaseio.TestClass$1
public void saveOrUpdate(Object object)
{
Transaction tx = sessionFactory.getCurrentSession().beginTransaction();
sessionFactory.getCurrentSession().saveOrUpdate(object);
tx.commit();
}
Stack Trace
Exception in thread "main" org.hibernate.MappingException: Unknown entity: project.databaseio.TestClass$1
at org.hibernate.impl.SessionFactoryImpl.getEntityPersister(SessionFactoryImpl.java:548)
at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1338)
at org.hibernate.engine.ForeignKeys.isTransient(ForeignKeys.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.getEntityState(AbstractSaveEventListener.java:487)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:84)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
at com.sun.proxy.$Proxy0.saveOrUpdate(Unknown Source)
at project.databaseio.DatabaseConnection.saveOrUpdate(DatabaseConnection.java:117)
at project.databaseio.TestClass.main(TestClass.java:21)
Hibernate Config for Student
<hibernate-mapping>
<class name="project.databaseio.Student" table="Student" catalog="fblaem">
<id name="id" type="java.lang.Integer">
<column name="id" />
<generator class="identity" />
</id>
<many-to-one name="school" class="project.databaseio.School" fetch="select">
<column name="SchoolID" not-null="true" />
</many-to-one>
<property name="firstName" type="string">
<column name="FirstName" not-null="true" />
</property>
<property name="lastName" type="string">
<column name="LastName" not-null="true" />
</property>
<property name="middleName" type="string">
<column name="MiddleName" />
</property>
<property name="createDate" type="timestamp">
<column name="CreateDate" length="0" />
</property>
<set name="studentEventTeams" table="StudentEventTeam" inverse="true" lazy="true" fetch="select">
<key>
<column name="StudentID" not-null="true" />
</key>
<one-to-many class="project.databaseio.StudentEventTeam" />
</set>
</class>
</hibernate-mapping>
The problem is coming from the following line:
s = new Student(){{setFirstName("asdf");setLastName("asdf1");}};
Briefly this line is creating a new instance of an inner class which implicitly inherits from Student class. This class is named TestClass$1 by Java's compiler and because there is no mapping for that, Hibernate is complaining about it. What you need to do is:
s = new Student();
s.setFirstName("blah");
s.setLastName("blah2");
s.setSchool((School) db.getByID(School.class, 1));
The declaration of your entity Student seems to be incorrect. If you are using annotations then properly annotate your class #javax.persistence.Entity annotaton.
I ran into similar problem, where my eclipse has got version problem with java and it couldnt build the code so when i added the new entity entry in my hibernate.cfg.xml it did not refresh the old one and hence when hibernate is trying to look for entity it couldnt get it.
I resolved it by deleting the old hibernate.cfg.xml in my bin location of the workspace and then pasted the new hibernate.cfg.xml and bingo it worked..
I am presently trying to do a bulk upload operation where in i need to parse an excel and update the details into the database. The problem is the data needs to be stored into multiple tables and the relationship is maintained. The problem is not when i have about 50-100 records to updated, but hugely affected when i have around 50000 records to be updated. It takes ages to upload and sometimes the browser gives up waiting for the response to arrive. Please find below the code and the mapping files. Please let me know what i can do to increase the performance and complete the processing quicker.
Note: The cascades are all required.
***.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.****.****.hibernate.****" table="V_ACCOUNT_DIM">
<id name="acctDimIdN" type="long">
<column name="ACCT_DIM_ID_N" precision="10" scale="0" />
<generator class="sequence">
<param name="sequence">ACCOUNT_DIM_SEQ</param>
</generator>
</id>
<property name="gdwIdN" type="long">
<column name="GDW_ID_N" precision="38" scale="0" not-null="true" />
</property>
<property name="pycisInstnIdN" type="java.lang.Long">
<column name="PYCIS_INSTN_ID_N" precision="10" scale="0" />
</property>
<property name="acctNotesC" type="string">
<column name="ACCT_NOTES_C" length="4000" />
</property>
<property name="trdSysShrtNmC" type="string">
<column name="TRD_SYS_SHRT_NM_C" length="100" />
</property>
<property name="reimbAuthorizeD" type="date">
<column name="REIMB_AUTHORIZE_D" length="7" />
</property>
<property name="reimbInitD" type="date">
<column name="REIMB_INIT_D" length="7" />
</property>
<property name="reimbEffD" type="date">
<column name="REIMB_EFF_D" length="7" />
</property>
<property name="acctGainLossAmtN" type="java.lang.Double">
<column name="ACCT_GAIN_LOSS_AMT_N" precision="15" />
</property>
<property name="buySellIndC" type="string">
<column name="BUY_SELL_IND_C" length="10" />
</property>
<property name="navImpcN" type="java.lang.Double">
<column name="NAV_IMPC_N" precision="15" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" not-null="true" />
</property>
<set name="incidentAcctSecFacts" table="V_INCIDENT_ACCT_SEC_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="incidentAcctFacts" table="V_INCIDENT_ACCT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="accountAttachmentFacts" table="V_ACCOUNT_ATTACHMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.A****Fact" />
</set>
</class>
</hibernate-mapping>
I****Dim.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.****.***.***.I****Dim" table="V_****_DIM">
<id name="incidentDimIdN" type="long">
<column name="INCIDENT_DIM_ID_N" precision="10" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_DIM_SEQ</param>
</generator>
</id>
<property name="errMemoIdC" type="string">
<column name="ERR_MEMO_ID_C" length="60" not-null="true" unique="true" />
</property>
<property name="errMemoD" type="date">
<column name="ERR_MEMO_D" length="7" />
</property>
<property name="idD" type="date">
<column name="ID_D" length="7" not-null="true" />
</property>
<property name="incidentD" type="date">
<column name="INCIDENT_D" length="7" not-null="true" />
</property>
<property name="ntfcD" type="date">
<column name="NTFC_D" length="7" not-null="true" />
</property>
<property name="totGainLossN" type="java.lang.Double">
<column name="TOT_GAIN_LOSS_N" precision="18" scale="2"/>
</property>
<property name="ovrdAttachedAcctC" type="string">
<column name="OVRD_ATTACHED_ACCT_C" length="1" />
</property>
<property name="gainLossCalcMthdC" type="string">
<column name="GAIN_LOSS_CALC_MTHD_C" length="4000" />
</property>
<property name="deemedAnErrC" type="string">
<column name="DEEMED_AN_ERR_C" length="1" not-null="true" />
</property>
<property name="errRatifiedC" type="string">
<column name="ERR_RATIFIED_C" length="1" not-null="true" />
</property>
<property name="errAcctUsedC" type="string">
<column name="ERR_ACCT_USED_C" length="1" not-null="true" />
</property>
<property name="aprvPrcsC" type="string">
<column name="APRV_PRCS_C" length="4000" />
</property>
<property name="incidentShrtDescC" type="string">
<column name="INCIDENT_SHRT_DESC_C" length="4000" />
</property>
<property name="incidentSumC" type="string">
<column name="INCIDENT_SUM_C" length="4000" />
</property>
<property name="incidentNotesC" type="string">
<column name="INCIDENT_NOTES_C" length="4000" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
<set name="incidentAttachmentFacts" table="V_****FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="10" scale="0" not-null="true" />
</key>
<one-to-many class="com.****.***.***.I***Fact" />
</set>
<set name="incidentActionItemFacts" table="V_****_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" />
</key>
<one-to-many class="com.****.***.***.I****Fact" />
</set>
<set name="incidentAcctSecFacts" table="V_****FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctSecFact" />
</set>
<set name="irgMemberAssignmentFacts" table="V_IRG_MEMBER_ASSIGNMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" />
</key>
<one-to-many class="com.***.***.****.IrgMemberAssignmentFact" />
</set>
<set name="incidentAcctFacts" table="V_INCIDENT_ACCT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctFact" />
</set>
<set name="acctAttachmentFacts" table="V_ACCOUNT_ATTACHMENT_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.AccountAttachmentFact" />
</set>
</class>
</hibernate-mapping>
CerSecurityDim.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.CerSecurityDim" table="V_CER_SECURITY_DIM">
<id name="cerSecuDimIdN" type="long">
<column name="CER_SECU_DIM_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">CER_SECURITY_DIM_SEQ</param>
</generator>
</id>
<property name="fmrCusipC" type="string">
<column name="FMR_CUSIP_C" length="30" not-null="true" />
</property>
<property name="tckrC" type="string">
<column name="TCKR_C" length="30" />
</property>
<property name="secuNmC" type="string">
<column name="SECU_NM_C" not-null="true" />
</property>
<property name="numOfShrTrdN" type="java.lang.Long">
<column name="NUM_OF_SHR_TRD_N" precision="10" scale="0" />
</property>
<property name="secuGainLossN" type="java.lang.Double">
<column name="SECU_GAIN_LOSS_N" precision="15" />
</property>
<property name="buySellIndC" type="string">
<column name="BUY_SELL_IND_C" length="10" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" not-null="true" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" not-null="true" />
</property>
<set name="incidentAcctSecFacts" table="V_INCIDENT_ACCT_SEC_FACT" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan" >
<key>
<column name="SECU_DIM_ID_N" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="com.***.***.****.IncidentAcctSecFact" />
</set>
</class>
</hibernate-mapping>
IncidentAcctFact.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.IncidentAcctFact" table="V_INCIDENT_ACCT_FACT">
<id name="incidentAcctFactIdN" type="long">
<column name="INCIDENT_ACCT_FACT_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_ACCT_FACT_SEQ</param>
</generator>
</id>
<many-to-one name="accountDim" class="com.***.***.****.AccountDim" fetch="select">
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="incidentDim" class="com.***.***.****.IncidentDim" fetch="select">
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<!-- <many-to-one name="attachmentTypeDim" class="com.***.***.****.AttachmentTypeDim" fetch="select">
<column name="ATTACHMENT_TYPE_DIM_ID_N" precision="22" scale="0" not-null="false" />
</many-to-one> -->
<property name="relEffFromD" type="date">
<column name="REL_EFF_FROM_D" length="7" />
</property>
<property name="relEffThruD" type="date">
<column name="REL_EFF_THRU_D" length="7" />
</property>
<property name="ltstRelIndC" type="string">
<column name="LTST_REL_IND_C" length="1" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" not-null="true" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
</class>
</hibernate-mapping>
IncidentAcctSecFact.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated Mar 19, 2012 9:24:47 AM by Hibernate Tools 3.3.0.GA -->
<hibernate-mapping>
<class name="com.***.***.****.IncidentAcctSecFact" table="V_INCIDENT_ACCT_SEC_FACT">
<id name="incidentAcctSecIdN" type="long">
<column name="INCIDENT_ACCT_SEC_ID_N" precision="22" scale="0" />
<generator class="sequence">
<param name="sequence">INCIDENT_ACCT_SEC_FACT_SEQ</param>
</generator>
</id>
<many-to-one name="accountDim" class="com.***.***.****.AccountDim" fetch="select">
<column name="ACCT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="cerSecurityDim" class="com.***.***.****.CerSecurityDim" fetch="select">
<column name="SECU_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<many-to-one name="incidentDim" class="com.***.***.****.IncidentDim" fetch="select">
<column name="INCIDENT_DIM_ID_N" precision="22" scale="0" not-null="true" />
</many-to-one>
<property name="relEffFromD" type="date">
<column name="REL_EFF_FROM_D" length="7" />
</property>
<property name="relEffThruD" type="date">
<column name="REL_EFF_THRU_D" length="7" />
</property>
<property name="ltstRelIndC" type="string">
<column name="LTST_REL_IND_C" length="1" />
</property>
<property name="delIndC" type="string">
<column name="DEL_IND_C" length="1" />
</property>
<property name="updUsrC" type="string">
<column name="UPD_USR_C" length="12" />
</property>
<property name="updTsD" type="date">
<column name="UPD_TS_D" length="7" />
</property>
<property name="insUsrC" type="string">
<column name="INS_USR_C" length="12" />
</property>
<property name="insTsD" type="date">
<column name="INS_TS_D" length="7" />
</property>
</class>
</hibernate-mapping>
The method where the actual processing is as follows.
public boolean retrieveDataAndParseFile(IncidentDetailsForm incidentDetailsForm, BaseViewBean baseViewBean$Session,
ActionMessages errors) throws Exception {
boolean savedStatus = false;
boolean deletedstatus = false;
/*List<AccountDim> accountsList = new ArrayList<AccountDim>();
List<CerSecurityDim> cerSecuList = new ArrayList<CerSecurityDim>();
List<IncidentAcctSecFact> inciAcctSecFactList = new ArrayList<IncidentAcctSecFact>();
List<IncidentAcctFact> inciAcctFactList = new ArrayList<IncidentAcctFact>();
List<IncidentDim> incidentList = new ArrayList<IncidentDim>();*/
try {
double totalSecGL= 0.00;
double secTrdNetTotal= 0.00;
DecimalFormat twoDForm = new DecimalFormat("#.##");
String loginUser = baseViewBean$Session.getLoggedInUser().getUserId();
List<Long> addedElementList = new ArrayList<Long>();
CerSecurityDim cerSecDim = null;
AccountDim account = null;
IncidentAcctSecFact iasFact = null;
IncidentAcctFact iaFact = null;
long incidentId = baseViewBean$Session.getIncidentDim$Session().getIncidentDimIdN();
IncidentDim incident = (IncidentDim)incidentDimDao.findById(IncidentDim.class, incidentId);
ExcelListenerBean beanDetails;
List<AccountDim> acctList = new ArrayList<AccountDim>();
List <CerSecurityDim> cerSecList = new ArrayList<CerSecurityDim>();
List <IncidentAcctSecFact> iasFactList = new ArrayList<IncidentAcctSecFact>();
for (Map.Entry<Integer, ExcelListenerBean> entry : baseViewBean$Session.getExcelRecords().entrySet())
{
beanDetails = entry.getValue();
//Initialize the net amounts for incorrect trade and correction trade.
secTrdNetTotal= 0;
cerSecDim = new CerSecurityDim();
account = new AccountDim();
iasFact = new IncidentAcctSecFact();
iaFact = new IncidentAcctFact();
//
Object[] pycisDet = investmentDimDao.getPyCISIdByShrtName(beanDetails.getShortName());
if(pycisDet != null && pycisDet.length > 0){
account.setPycisInstnIdN((Long)pycisDet[0]);
account.setGdwIdN((Long)pycisDet[1]);
account.setTrdSysShrtNmC(beanDetails.getShortName());
if(!addedElementList.contains((Long)pycisDet[0])){
addedElementList.add((Long)pycisDet[0]);
}
}
//
cerSecDim.setFmrCusipC(beanDetails.getFmrCusip());
SecurityDim sec = getSecDetailsByCusip(beanDetails.getFmrCusip());
if(sec != null){
cerSecDim.setSecuNmC(sec.getSecuNmC());
cerSecDim.setTckrC(sec.getTckrC());
}else {
cerSecDim.setSecuNmC("UNKNOWN");
cerSecDim.setTckrC("UNKNOWN");
}
//
cerSecDim.setNumOfShrTrdN(beanDetails.getIncorrectTrdShares().longValue());
//
cerSecDim.setBuySellIndC(beanDetails.getIncorrectTrdBuySell().toUpperCase());
account.setBuySellIndC(beanDetails.getIncorrectTrdBuySell().toUpperCase());
//
secTrdNetTotal = Double.valueOf(twoDForm.format(beanDetails.getIncorrectTrdNet())) +
Double.valueOf(twoDForm.format(beanDetails.getCorrectionTrdNet()));
//
totalSecGL = totalSecGL + secTrdNetTotal;
boolean updatedStatus = false;
// create the relationship and then add to the respective lists.
cerSecDim.setInsUsrC(loginUser);
cerSecDim.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
cerSecDim.setDelIndC(AppGlobalConstants.HardCodedValues.No);
if(!acctList.isEmpty()){
for( AccountDim olderAccount :acctList){
if(olderAccount.getPycisInstnIdN().compareTo(account.getPycisInstnIdN()) == 0) {
double newAcctGainLossAmt=0;
double oldAcctGainLossAmt=0;
if(account.getAcctGainLossAmtN() != null){
newAcctGainLossAmt = account.getAcctGainLossAmtN();
}
if(olderAccount.getAcctGainLossAmtN() != null){
oldAcctGainLossAmt = olderAccount.getAcctGainLossAmtN();
}
double newGLAmt = newAcctGainLossAmt + oldAcctGainLossAmt;
account = olderAccount;
account.setAcctGainLossAmtN(newGLAmt);
updatedStatus = true;
}
}
}
if(!cerSecList.isEmpty()){
for(CerSecurityDim olderCerSecDim : cerSecList){
if(olderCerSecDim.getFmrCusipC().equals(cerSecDim.getFmrCusipC())) {
cerSecDim = olderCerSecDim;
double newSecuGainLoss = 0;
double oldSecuGainLoss = 0;
if(cerSecDim.getSecuGainLossN() != null){
newSecuGainLoss = cerSecDim.getSecuGainLossN();
}
if(olderCerSecDim.getSecuGainLossN() != null){
oldSecuGainLoss = olderCerSecDim.getSecuGainLossN();
}
cerSecDim.setSecuGainLossN(newSecuGainLoss + oldSecuGainLoss);
for(IncidentAcctSecFact olderIASFact : iasFactList){
if(olderIASFact != null && olderIASFact.getCerSecurityDim() != null
&& olderIASFact.getCerSecurityDim().getFmrCusipC().equals(cerSecDim.getFmrCusipC())){
iasFact = olderIASFact;
}
}
}
}
}
if(!deletedstatus){
deleteAllImpactedAccounts(baseViewBean$Session);
deletedstatus = true;
}
totalSecGL = Double.valueOf(twoDForm.format(totalSecGL));
account.setInsUsrC(loginUser);
account.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
account.setDelIndC(AppGlobalConstants.HardCodedValues.No);
accountDimDao.saveOrUpdate(account);
iasFact.setAccountDim(account);
iasFact.setIncidentDim(incident);
iasFact.setCerSecurityDim(cerSecDim);
iasFact.setInsUsrC(loginUser);
iasFact.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
iasFact.setDelIndC(AppGlobalConstants.HardCodedValues.No);
cerSecDim.getIncidentAcctSecFacts().add(iasFact);
account.getIncidentAcctSecFacts().add(iasFact);
incident.getIncidentAcctSecFacts().add(iasFact);
if(!updatedStatus){
iaFact.setAccountDim(account);
iaFact.setIncidentDim(incident);
iaFact.setInsUsrC(loginUser);
iaFact.setInsTsD(AppGlobalUtil.getCurrentTimeStamp());
iaFact.setDelIndC(AppGlobalConstants.HardCodedValues.No);
incident.getIncidentAcctFacts().add(iaFact);
account.getIncidentAcctFacts().add(iaFact);
}
incident.setTotGainLossN(totalSecGL);
cerSecurityDimDao.saveOrUpdate(cerSecDim);
incidentAcctSecFactDao.saveOrUpdate(iasFact);
if(!updatedStatus){
accountDimDao.saveOrUpdate(account);
}
if(!acctList.contains(account)){
acctList.add(account);
}
if(!cerSecList.contains(cerSecDim)){
cerSecList.add(cerSecDim);
}
if(!iasFactList.contains(iasFact)){
iasFactList.add(iasFact);
}
if(!updatedStatus){
incidentAcctFactDao.saveOrUpdate(iaFact);
}
incidentDimDao.saveOrUpdate(incident);
NumberFormat formatter = new DecimalFormat("#0.00");
incidentDetailsForm.setTotalGainLoss(formatter.format(totalSecGL));
savedStatus = true;
/*accountsList.add(account);
cerSecuList.add(cerSecDim);
inciAcctSecFactList.add(iasFact);
inciAcctFactList.add(iaFact);
incidentList.add(incident);*/
}
} catch (Exception e) {
logger.error(e.getMessage());
e.printStackTrace();
throw e;
}
finally{
baseViewBean$Session.getExcelRecords().clear();
baseViewBean$Session.setExcelRecords(null);
}
/*accountDimDao.saveOrUpdateAll(accountsList);
cerSecurityDimDao.saveOrUpdateAll(cerSecuList);
incidentAcctSecFactDao.saveOrUpdateAll(inciAcctSecFactList);
incidentAcctFactDao.saveOrUpdateAll(inciAcctFactList);
incidentDimDao.saveOrUpdateAll(incidentList);*/
return savedStatus;
}
The dao functions are accessed from another file.
Please let me know how i can increase my performance.
The problem is that you are trying to do this from a browser, where the default timeout for a page is 30 seconds. You should be doing this from an application so that you can control the amount of time you wait to upload the records.
I am having lookalike problems.
Make sure that you have all keys for join and search fields.
May be you can store your file in temporary location and then handle it by paralell thread.
Another option is to use Stateless Sessions (there is almost no info on the net, see hibernate manual) I am not sure if there is an option to fill ManyToMany collections.
Caching getOrCreate queries by saving copy of table in memory may help you (but you may run into OutOfMemory exception, so pass -Xmx param to your app).
All these may not solve your problem. I've decided to implement these inserts using native sql queries.
There are multiple issues that should be looked at:
Long-running operations should be run asynchronously. If you are using Spring, you can annotate #Async, for instance. Then your transaction is not beholden to network connectivity or browser/HTTP timeouts.
Batch operations in Hibernate can be very slow. Even if you set up JDBC batching, and even if you follow the instructions in the Hibernate documentation, you are still beholden to the fact that you are using an ORM. ORMS are best used for maintaining state for object-oriented operations, not for batch operations, where any individual object's state is less relevant.
Batch operations in Hibernate can be very finicky. For instance, the Hibernate batching documentation fails to note that you need to set additional flags in the configuration to make sure that it batches correctly. See this post for details.
At the end of the day, ORMs will always be slower than base SQL. Consider swtiching over to base SQL, maybe concatenating SQL statements so that you have fewer database trips, or using a stored proc, passing bactches of data to the proc and have it run the inserts.
when you open session use openStatelessSession and call session.update at the end. this way persistentcontext cannot have 10000 object in cache and all the updates happens in db.
I am looking into Hibernate's parent/child relationships.
I have 3 entities Employee Customers and Orders.
Their relationship is
Employee 1 <-> N Orders
Customer 1 <-> N Orders
I want to be able to save/update/delete Customer objects and Employees and Orders but I want to use some interface so that the calling code does not deal with any Hibernate or JPA stuff.
E.g. I tried something like the following:
class Utils{
public static void saveObject(Object o){
logger.debug(o.toString());
Session session = getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
session.save(o);
tx.commit();
session.close();
}
}
and in the calling code I do:
Employee employee = new Employee();
//set data on employee
Customer customer = new Customer();
//set data on customer
Order order = new Order();
//set data on order
employee.addOrder(order);//this adds order to its list, order gets a reference of employee as parent
customer.addOrder(order);//this adds order to its list, order gets a reference of customer as parent
Utils.saveObject(customer);
Utils.saveObject(employee);
Now I noticed that with this code, 2 records of employee are created instead of 1.
If I only do:
Utils.saveObject(customer);
Only 1 (correctly) record is created.
Why does this happen?
Does this happens because the same Order object is saved by both Customer and Employee? And the cascade="all" makes this side-effect?
Now if I do not use the DBUtils method and do directly:
Session session = DBUtil.getSessionFactory().openSession();
Transaction tx = session.beginTransaction();
session.save(employee);
session.save(customer);
tx.commit();
session.close();
Again, it works as expected. I.e. only 1 employee record is created.
What am I doing something wrong here?
UPDATE:
Hibernate mappings:
<hibernate-mapping>
<class name="database.entities.Associate" table="EMPLOYEE">
<id name="assosiateId" type="java.lang.Long">
<column name="EMPLOYEEID" />
<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="EMPLOYEEID" />
</key>
<one-to-many class="database.entities.Order" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="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="database.entities.Order" />
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="database.entities.Order" table="ORDERS">
<id name="orderId" type="java.lang.Long">
<column name="ORDERID" />
<generator class="identity" />
</id>
<property name="orderDate" type="java.util.Date">
<column name="ORDERDATE" />
</property>
<property name="quantity" type="java.lang.Integer">
<column name="QUANTITY" />
</property>
<property name="quantityMargin" type="java.lang.Long">
<column name="QUANTITYMARGIN" />
</property>
<property name="port" type="java.lang.String">
<column name="PORT" />
</property>
<property name="orderState" type="java.lang.String">
<column name="ORDERSTATE" />
</property>
<many-to-one name="customer" class="database.entities.Customer" cascade="all" fetch="join">
<column name="CUSTOMERID" />
</many-to-one>
<many-to-one name="associate" column="EMPLOYEEID" class="database.entities.Employee" cascade="all" fetch="join">
</many-to-one>
</class>
</hibernate-mapping>
UDATE 2:
class Employee{
//Various members
Set<Order> orders = new HashSet<Order>();
public void addOrder(Order order){
order.setEmployee(this);
orders.add(order);
}
}
Also:
class Customer{
//Various members
Set<Order> orders = new HashSet<Order>();
public void addOrder(Order order){
order.setCustomer(this);
orders.add(order);
}
}
It seems to me that in the DBUtils code, you are wrapping both saves in an outer transaction, whereas in the Utils code, you have them in two completely separate transactions without an outer one.
Depending on your cascading, Hibernate has to figure out which objects need to be saved. When you run the Utils code, with two separate transactions, it will save the Order first. Since you're cascading all, this means it will save the Order first, then the Customer. However, you've created the SAME Order for both the Customer and Employee. Therefore, the Employee also gets saved in the first transaction (due to cascading). The second transaction, since it is separate, will not be aware of this and save another Employee.
On the other hand, if you wrap them in an outer transaction, Hibernate can figure out the identities of all the objects and save them properly.
try saving only Order instead of saving Employee and Customer separately. With your existing cascade=all setting both parent object will get saved without creating any duplicates.