I am using Spring HibernateTemplate, OpenSessionInViewFilter(actually I extended this class and created my own to switch to FLUSH.AUTO Mode) and Mysql for implementing hibernate many-to-many association. However when I save an object, corresponding many-to-many table's values are not inserted. Does anybody can help me? Thank you.
here is the mapping xml
<hibernate-mapping>
<class name="com.intelli.epub.domain.Content" table="CONTENT">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="title" type="java.lang.String">
<column name="TITLE" />
</property>
<property name="text" type="java.lang.String">
<column name="TEXT" />
</property>
<many-to-one name="writer" class="com.intelli.epub.domain.User" fetch="join">
<column name="WRITER" />
</many-to-one>
<property name="createdDate" type="java.util.Date">
<column name="CREATEDDATE" />
</property>
<set name="menus" table="MENU_CONTENT" cascade="all">
<key column="CONTENT_ID"></key>
<many-to-many column="MENU_ID" class="com.intelli.epub.domain.Menu"/>
</set>
</class>
</hibernate-mapping>
another one:
<hibernate-mapping>
<class name="com.intelli.epub.domain.Menu" table="MENU">
<id name="id" type="java.lang.Long">
<column name="ID" />
<generator class="native" />
</id>
<property name="text" type="java.lang.String">
<column name="TEXT" />
</property>
<set name="contents" table="MENU_CONTENT" inverse="true">
<key column="MENU_ID"></key>
<many-to-many column="CONTENT_ID" class="com.intelli.epub.domain.Content"/>
</set>
</class>
and when saving like this:
Content content = new Content();
content.setCreatedDate(new Date());
content.setWriter(some user here);
content.setText("some text here");
Menu menu1 = new Menu("menu1");
Menu menu2 = new Menu("menu2");
Set<Menu> menus = new HashSet();
menus.add(menu1);
menus.add(menu2);
content.setMenus(menus);
contentDao.saveOrUpdate(content);
Now menu1 and menu2 would be saved in the MENU table, However nothing happens to MENU_CONTENT table; MENU_CONTENT table doesn't have a primary key field, instead MENU_ID and CONTENT_ID are primary key together. I don't know if it's the problem. Please help me. Thank you.
I found a solution. Instead of using Spring HibernateTemplate. I wrapped it in regular session and transaction like this.
Session session = contentDao.getHibernateTemplate().getSessionFactory().getCurrentSession();
transaction = session.beginTransaction();
Content content = new Content();
content.setCreatedDate(new Date());
content.setWriter(some user here);
content.setText("some text here");
Menu menu1 = new Menu("menu1");
Menu menu2 = new Menu("menu2");
Set<Menu> menus = new HashSet();
menus.add(menu1);
menus.add(menu2);
content.setMenus(menus);
session.save(content);
transaction.commit();
session.close();
And here is my session filter which inherited from OpenSessionInViewFilter
public class SessionFilter extends OpenSessionInViewFilter {
protected Session getSession(SessionFactory sessionFactory)
throws DataAccessResourceFailureException {
Session session = super.getSession(sessionFactory);
session.setFlushMode(FlushMode.AUTO);
return session;
}
}
Does anybody know a way to handle this without bothering to write session management myself?
Related
I have a sql query like below,
SELECT patient.*,
contact.telephone
from patient
INNER JOIN contact ON patient.`idPatient` = contact.`idPatient`
These are my works,
Patient.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 8, 2016 1:55:08 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="db.Patient" table="patient" catalog="example_hibernate" optimistic-lock="version">
<id name="idPatient" type="java.lang.Integer">
<column name="idPatient" />
<generator class="identity" />
</id>
<property name="title" type="string">
<column name="title" length="45" />
</property>
<property name="firstName" type="string">
<column name="firstName" length="45" />
</property>
<property name="lastName" type="string">
<column name="lastName" length="45" />
</property>
<property name="middleName" type="string">
<column name="middleName" length="45" />
</property>
<property name="dob" type="date">
<column name="dob" length="10" />
</property>
<property name="martitalStatus" type="java.lang.Boolean">
<column name="martitalStatus" />
</property>
<property name="gender" type="string">
<column name="gender" length="45" />
</property>
<property name="nic" type="string">
<column name="nic" length="45" />
</property>
<property name="dateCreated" type="timestamp">
<column name="dateCreated" length="19" />
</property>
<property name="lastUpdated" type="timestamp">
<column name="lastUpdated" length="19" not-null="true" />
</property>
<set name="contacts" table="contact" inverse="true" lazy="true" fetch="select">
<key>
<column name="idPatient" not-null="true" />
</key>
<one-to-many class="db.Contact" />
</set>
</class>
</hibernate-mapping>
Contact.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<!-- Generated Sep 8, 2016 1:55:08 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="db.Contact" table="contact" catalog="example_hibernate" optimistic-lock="version">
<id name="idContact" type="java.lang.Integer">
<column name="idContact" />
<generator class="identity" />
</id>
<many-to-one name="patient" class="db.Patient" fetch="select">
<column name="idPatient" not-null="true" />
</many-to-one>
<property name="telephone" type="string">
<column name="telephone" length="45" />
</property>
<property name="address" type="string">
<column name="address" length="45" />
</property>
</class>
</hibernate-mapping>
Then I used above sql like below,
SessionFactory sessionFactory = new HibernateUtil().getSessionFactory();
Session session = sessionFactory.openSession();
List<Object[]> africanContinents = session.createQuery(
"SELECT patient.*,\n"
+ "contact.telephone\n"
+ "from patient\n"
+ "INNER JOIN contact ON patient.`idPatient` = contact.`idPatient`")
.list();
HibernateUtil.shutdown();
But this bought me following exception
org.hibernate.QueryException: unexpected char: '`' [SELECT patient.*,
contact.telephone
from patient
INNER JOIN contact ON patient.`idPatient` = contact.`idPatient`]
I have no idea about how to handle this exception . Because this sql query is correct.
Have any ideas about this exception ?
The query in createQuery should be written in HQL or JPQL.
So you could rewrite your query in HQL (something 'like select p,c.telephone from patient inner join contact') see documentation here
Or you could use your SQL query by calling session.createSQLQuery instead of session.createQuery
Hope this helps.
Sebastien
Please find my two tables
CREATE TABLE "DBS_P2P"."KW_PAYMENT_IMAGEE_TEST"(IMAGE_KEY INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH +1 INCREMENT BY +1 MINVALUE +1 MAXVALUE +2147483647 NO CYCLE CACHE 20 NO ORDER),REQUEST_ID INTEGER,IMAGE_CONTENT CLOB(5120000),FOREIGN KEY(REQUEST_ID) REFERENCES KW_PAYMENT_LINK_MASTER_TEST(REQUEST_ID))
CREATE TABLE "DBS_P2P"."KW_PAYMENT_IMAGEE_TEST"(IMAGE_KEY INTEGER PRIMARY KEY NOT NULL GENERATED ALWAYS AS IDENTITY ( START WITH +1 INCREMENT BY +1 MINVALUE +1 MAXVALUE +2147483647 NO CYCLE CACHE 20 NO ORDER),REQUEST_ID INTEGER,IMAGE_CONTENT CLOB(5120000),FOREIGN KEY(REQUEST_ID) REFERENCES KW_PAYMENT_LINK_MASTER_TEST(REQUEST_ID))
<hibernate-mapping>
<class name="xyz" table="KW_PAYMENT_LINK_MASTER_TEST" catalog="xyz">
<id name="requestId" type="int">
<column name="REQUEST_ID"/>
<generator class="identity" />
</id>
<property name="referenceWalletId" type="string">
<column name="REFERENCE_ID"/>
</property>
</class>
<hibernate-mapping>
<class name="com.kony.p2p.bo.KwPaymentImagetest" table="KW_PAYMENT_IMAGEE_TEST" catalog="DBS_P2P">
<id name="imageKey" type="int">
<column name="IMAGE_KEY" />
<generator class="identity" />
</id>
<many-to-one name="KwPaymentLinkMastertest" class="com.kony.p2p.bo.KwPaymentLinkMastertest" fetch="select" lazy="false">
<column name="REQUEST_ID" not-null="false" />
</many-to-one>
<property name="imageContent" type="string">
<column name="IMAGE_CONTENT" not-null="false" />
</property>
</class>
<filter-def name="myFilter">
Im able to insert but not able to retrieve the result .
session.createCriteria(KwPaymentLinkMastertest.class).add(Restrictions.eq("requestId", Integer.parseInt(transactionReferenceNumber) )).uniqueResult();
KwPaymentImagetest image = (KwPaymentImagetest) session.createCriteria(KwPaymentImagetest.class).add(Restrictions.eq("kwPaymentLinkMastertest", kwPaymentLinkMastertest)).uniqueResult();
Getting the following error
org.hibernate.QueryException: could not resolve property: kwPaymentLinkMastertest of: com.kony.p2p.bo.KwPaymentImagetest
Please help fix
I think you have typing mistake here.
<many-to-one name="KwPaymentLinkMastertest" with K is upper case
while Restrictions.eq("kwPaymentLinkMastertest" with k is lower case.
Ya,
You are right .
The problem was with small letter and capital letter , this helped to fix my problem.
Thanks.
I am a beginner in hibernate. Basically I want to make UserId1 and UserId2 foreign keys of UserId. I Know I need to use many to one and one to many, but I can't seem to understand how to use them because my columns have different names. Any help is appreciated!
This is my hibernate.hbm.xml 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="objects.UserProfile" table="userProfiles">
<id name="UserId" column="UserProfileId">
<generator class="native"/>
</id>
<set name="userTracks" table="userTrack"
inverse="true" lazy="true" fetch="select">
<key>
<column name="UserProfileId" not-null="true" />
</key>
<one-to-many class="objects.UserTrack" />
</set>
</class>
<class name="objects.UserTrack" table="userTrack">
<composite-id>
<key-property name="UserId1" column="UserProfileId1" type="integer" />
<key-property name="UserId2" column="UserProfileId2" type="integer" />
</composite-id>
</class>
</hibernate-mapping>
So basically both ids in my track class should point to the id in the profile class
my userTrack class:
public class UserTrack implements Serializable {
private int UserProfileId1;
private int UserProfileId2;
public int getUserProfileId1() {
return UserProfileId1;
}
public void setUserProfileId1(int userProfiletId1) {
UserProfiletId1 = userProfileId1;
}
public int getUserProfileId2() {
return UserProfileId2;
}
public void setUserProfileId2(int userProfileId2) {
UserProfileId2 = userProfileId2;
}
}
My profile class:
public class UserProfile {
private int UserProfileId;
public int getUserProfileId() {
return UserProfileObjectId;
}
public void setUserProfileId(int userProfileId) {
UserProfileId = userProfileId;
}
}
The mappings should be as follows.
Since there is a One to Many relation between UserProfile and UserTrack,
you can use a Set<UserTracks> userTracks in UserProfile to keep track of the UserTracks for each UserProfile
For UserProfile Class
<hibernate-mapping>
<class name="objects.UserProfile" table="userProfiles">
<id name="userProfileId" column="UserProfileId">
<generator class="native"/>
</id>
<!-- other property definitions should come here -->
<set name="userTracks" table="userTrack"
inverse="true" lazy="true" fetch="select">
<key>
<column name="UserProfileId" not-null="true" />
</key>
<one-to-many class="objects.UserTrack" />
</set>
</class>
</hibernate-mapping>
For UserTrack class
<hibernate-mapping>
<class name="objects.UserTrack" table="userTrack">
<id name="userId" type="java.lang.String">
<column name="userTrackName" />
</id>
<many-to-one name="userProfile" class="objects.UserProfile" fetch="select">
<column name="UserProfileId" not-null="true" />
</many-to-one>
<!-- other property definitions should come here -->
</class>
</hibernate-mapping>
These two xml config files can be integrated to the main hibernate.cfg.cml file as follows.
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">xxxxxxxxxx</property>
<property name="hibernate.connection.url">xxxxxxxx</property>
<property name="hibernate.connection.username">username</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.dialect">xxxxxx</property>
<property name="show_sql">true</property>
<property name="format_sql">true</property>
<mapping resource="path to this file/UserProfile.hbm.xml" />
<mapping resource="path to this file/UserTrack.hbm.xml" />
</session-factory>
</hibernate-configuration>
Hope this helps.
More info here
EDIT : I think Your Entity Classes should be like something similar to the following.
public class UserTrack implements Serializable {
// consider this as the primary key for UserTrack or feel free to change.
private String userTrackName;
// private int UserProfileId1;
// private int UserProfileId2;
// other attributes related to UserTrack
}
And
public class UserProfile {
// you could keep track of the UserTracks that belongs to a
//particular UserProfile in the Set.
// Now a UserProfile can belong to many UserTracks. Not just 2.
private Set<UserTrack> userTracks = new HashSet<>();
private int UserProfileId;
public int getUserProfileId() {
return UserProfileObjectId;
}
public void setUserProfileId(int userProfileId) {
UserProfileId = userProfileId;
}
}
I have an interesting use-case where I'd like Hibernate to manage multiple one-to-many relationships to the same entity type.
For example: BookShelf fictionBooks relationship to Book(s), but also BookShelf nonFictionBooks mapped to Book(s). The Hibernate mapping would look something like this:
<class name="com.example.BookStore" table="BOOK_SHELF">
<id name="id" type="long" column="bookShelfId">
<generator class="native" />
</id>
<set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
<set name="nonFictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
</class>
<class name="com.example.Book" table="SHELF_BOOK">
<id name="id" type="long" column="shelfBookId">
<generator class="native" />
</id>
<property name="name" not-null="true" unique="true"/>
</class>
Is there a way for the relationship owner BookShelf to specify some discriminator value which could be used to differentiate between Fiction and Non-Fiction books? If possible, the discriminator would be stored as an additional column in SHELF_BOOK table and Hibernate would automatically filter on that.
Is there a way to do this without resorting to either a many-to-many association or extending the Book entity with a Table per class strategy?
Ideally you should have a "type" or "flag" column in SHELF_BOOK table indicating the book is fiction or non-fiction.
Suppose you have added this "type" column, then I think you could specify a filter statement in the set:
<set name="fictionBooks" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<filter name="myfilter" condition=":type = 'FICTION'"/>
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
You can refer to http://docs.jboss.org/hibernate/core/3.6/reference/en-US/html_single/#objectstate-filters
From what you posted, I can say that in order to achieve what you wanted you need to modify your relationship owner BookShelf to only store reference to Book and add the property, say bookType, to Book entity.
<class name="com.example.BookStore" table="BOOK_SHELF">
<id name="id" type="long" column="bookShelfId">
<generator class="native" />
</id>
<set name="books" table="SHELF_BOOK" cascade="all-delete-orphan" lazy="false">
<key column="bookShelfId" />
<one-to-many class="com.example.Book" />
</set>
</class>
<class name="com.example.Book" table="SHELF_BOOK">
<id name="id" type="long" column="shelfBookId">
<generator class="native" />
</id>
<property name="name" not-null="true" unique="true"/>
<property name="bookType" not-null="true"/>
</class>
There is no other(except ManytoMany) way by which you can find out the type of book by looking into BookShelf entity. You can also use Single Table Strategy which will automatically add the discriminator to the inserted values but in order to do that you need to create two separate classes for FictionalBook and NonFictionalBook .
I have a bi-directional relationship between 2 objects - EvalMasterEvaluation (one) and EvalMasterEvalDetail (many). I've tried a number of different solutions, but I must be implementing them wrong. My goal is to return a list of details for a given eval id.
I'm using Jackson 2.2 (with databind and datatype-hibernate3 libs), hibernate 3.6 and spring 3.2.1. Some code omitted to make this easier to read.
The parent class:
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
public class EvalMasterEvaluation implements java.io.Serializable {
private BigDecimal id;
#JsonManagedReference private Set<EvalMasterEvalDetail> evalMasterEvalDetails = new HashSet<EvalMasterEvalDetail>(
0);
}
The child class:
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
#JsonIdentityInfo(generator=ObjectIdGenerators.IntSequenceGenerator.class, property="#id")
public class EvalMasterEvalDetail implements java.io.Serializable {
private BigDecimal id;
#JsonBackReference private EvalMasterEvaluation evalMasterEvaluation;
private String active;
}
My Hibernate Criteria query:
Criteria criteria = session.createCriteria(EvalMasterEvalDetail.class)
.add(Restrictions.eq("active", "Y"))
.setFetchMode("evalMasterEvaluation", FetchMode.JOIN)
.createAlias("evalMasterEvaluation", "eval")
.add(Restrictions.eq("eval.id", evalId))
.addOrder(Order.asc("detailOrder"));
details = criteria.list();
ObjectMapper mapper = new ObjectMapper();
json = mapper.writeValueAsString(details);
EvalMasterEvaluation mapping
<hibernate-mapping>
<class name="org.anes.surveys.domain.EvalMasterEvaluation" table="EVAL_MASTER_EVALUATION">
<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="sequence-identity" >
<param name="sequence">EVAL_MASTER_EVALUATION_SEQ</param>
</generator>
</id>
<set name="evalMasterEvalDetails" table="EVAL_MASTER_EVAL_DETAIL" inverse="true" lazy="true" fetch="select">
<key>
<column name="MASTER_EVAL_ID" precision="22" scale="0" not-null="true" />
</key>
<one-to-many class="org.anes.surveys.domain.EvalMasterEvalDetail" />
</set>
</class>
</hibernate-mapping>
EvalMasterEvalDetail mapping
<hibernate-mapping>
<class name="org.anes.surveys.domain.EvalMasterEvalDetail" table="EVAL_MASTER_EVAL_DETAIL">
<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="sequence-identity" >
<param name="sequence">EVAL_MASTER_EVAL_DETAIL_SEQ</param>
</generator>
</id>
<many-to-one name="evalMasterEvaluation" class="org.anes.surveys.domain.EvalMasterEvaluation" fetch="select">
<column name="MASTER_EVAL_ID" precision="22" scale="0" not-null="true" />
</many-to-one>
<property name="active" type="string">
<column name="ACTIVE" length="1" not-null="true" />
</property>
</class>
</hibernate-mapping>
AYE! After 2 days I finally found my mistake. I forgot to register the Hibernate3Module. My criteria/mapper code is now:
Criteria criteria = session.createCriteria(EvalMasterEvalDetail.class)
.add(Restrictions.eq("active", "Y"))
.setFetchMode("evalMasterEvaluation", FetchMode.JOIN)
.createAlias("evalMasterEvaluation", "eval")
.add(Restrictions.eq("eval.id", evalId))
.addOrder(Order.asc("detailOrder"));
details = criteria.list();
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Hibernate3Module());
json = mapper.writeValueAsString(details);
evalMasterEvaluation values are missing, but it's a step in the right direction.