Hello Stackeroverflowers,
i'd like to ask how i can solve the following problem:
I have 3 Tables:
Hardware
PC
Software
They have a Many-to-Many Relation. So N Hardware Entries can have M Hardware Entries.
When im Calling my Hibernate stuff then i get all Pc's with the chosen Software. In Software i have a Mappign on Hardware to get the specified Hardware of a Pc.
So far so good.
The Problem im facing is that i have to make this compatible from the other side to allow to get all Pc's with the specified Hardware and then from the Pc's the software.
When i have a mapping that links from Software over Pc to Hardware its ok. When i put a mapping into Hardware to get Pc's. Im getting a Stackoverflow because Hibernate tries to create everytime i initialize a Hardware to initialize a Pc and Pc tries then to initialize a Hardware so i get a Loop that never ends.
Can someone give me a hint to Solve this problem ?
I heard of that the attribute inverse can solve this but i dont know where ro place it and how it works.
I'm thankful for every Comment.
Hardware.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 04.11.2013 17:30:12 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
<class name="de.test.database.pojo.Hardware" table="object" schema="XXX">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="fkserialId" type="int">
<column name="fk_serial_id" not-null="true" />
</property>
<property name="name" type="string">
<column name="name_id" not-null="true" />
</property>
<set name="linkHardwareToSoftware" table="pc_link" inverse="true" lazy="true" fetch="select">
<key foreign-key="none">
<column name="fk_serial_id" not-null="true" />
</key>
<one-to-many class="de.test.database.pojo.PC" />
</set>
</class>
</hibernate-mapping>
PC.hbm.xml
<hibernate-mapping>
<class name="de.test.database.pojo.pc" table="pc_link" schema="xxx">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="sort" type="int">
<column name="sort" not-null="true" />
</property>
<property name="owner" type="string">
<column name="owner" not-null="true" />
</property>
<many-to-one name="hardware" class="de.test.database.pojo.hardware" fetch="select">
<column name="fk_serial_id" not-null="true" />
</many-to-one>
<many-to-one name="software" class="de.test.database.pojo.Software" fetch="select">
<column name="fk_sw_id" not-null="true" />
</many-to-one>
</class>
</hibernate-mapping>
Software.hbm.xml
<hibernate-mapping>
<class name="de.test.database.pojo.Software" table="object" schema="xxx">
<id name="id" type="int">
<column name="id" />
<generator class="assigned" />
</id>
<property name="fkswId" type="int">
<column name="fk_sw_id" not-null="true" />
</property>
<property name="name" type="java.lang.Integer">
<column name="name" />
</property>
<property name="company" type="java.lang.Integer">
<column name="company" />
</property>
<set name="linkSWToHardware" table="pc_link" inverse="true" lazy="true" fetch="select">
<key foreign-key="none">
<column name="fk_sw_id" not-null="true" />
</key>
<one-to-many class="de.test.database.pojo.pc" />
</set>
</class>
</hibernate-mapping>
HibernateCode.java
try
{
String obj =" AND t.fkHWtypeId =:otid";
if(objectType==0)
obj="";
Session ses = getSession();
Query query = ses.createQuery(
" FROM hardware t"+
" WHERE t.deleted = 0 AND t.Id =:pid"+obj
);
query.setParameter("pid", HardwareId);
if(objectType!=0){
System.out.println("Reading HWtypeid...");
query.setParameter("HWtypeid", HardwareType);
}
List<Tree> list = query.list();
return list;
} catch (HibernateException e)
{
return null;
}
Stacktrace:
org.codehaus.jackson.map.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: de.test.database.pojo.Pc["hardware"]->de.test.database.pojo.Hardware_$$_javassist_109["linkHardwareToSoftware"]->org.hibernate.collection.internal.PersistentSet[0]->de.test.database.pojo.pc["object"]->de.test.database.pojo.Hardware_$$_javassist_109["linkHardwareToSoftware"]
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:164)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:72)
at org.codehaus.jackson.map.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:23)
at org.codehaus.jackson.map.ser.std.AsArraySerializerBase.serialize(AsArraySerializerBase.java:86)
at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
at org.codehaus.jackson.map.ser.BeanSerializer.serialize(BeanSerializer.java:112)
at org.codehaus.jackson.map.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:446)
at org.codehaus.jackson.map.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:150)
As the stack trace indicates, the problem has nothing to do with the mapping and with loading data from the database with Hibernate. The problem happens when you're serializing your beans with Jackson, because you have bidirectional associations and thus cyclic references which cause Jackson to loop endlessly.
So, you should choose how you want to serialize your objects, and use Jackson annotations or use DTOs to serialize them and break the cycles between objects. You could, for example, add a #JsonIgnore on the linkHardwareToSoftware field, so that the collection of software is not serialized when serializing a Hardware instance.
Related
I am getting following issue while saving entity in hibernate -
It duplicates the record with null values -
(2661956,2601555,'Chloe','Chloe','Thooks',null,null,null,null,null,null,'Y','N','XYZ',to_date('15-NOV-16','DD-MON-RR'),null,null)
with a duplicate -
(2661946,2601555,null,null,null,null,null,null,null,null,null,'Y','N','XYZ',to_date('15-NOV-16','DD-MON-RR'),null,null) -
We have the following mapping -
Parent -
<?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 default-lazy="false">
<class name="com.sm.persistence.LOADetailBO" table="LOADETAILS">
<id name="loaDetailsId" type="long">
<column name="LOA_ID" precision="38" scale="0"/>
<generator class="com.sm.persistence.dao.seqgen.LOADetailSeqGen">
</generator>
</id>
<many-to-one name="reregistration" class="com.sm.persistence.RerBO" fetch="join">
<column name="RER_ID" precision="38" scale="0"/>
</many-to-one>
<property name="relatedPlanManager" type="string">
<column name="RELATED_PLAN_MANAGER"/>
</property>
<property name="relatedPlanManagerCode" type="string">
<column name="RELATED_PLAN_MANAGER_CODE"/>
</property>
<set name="relatedPlanManagerAddress" inverse="true" cascade="all-delete-orphan">
<key>
<column name="LOA_ID" precision="38" scale="0" not-null="false"/>
</key>
<one-to-many class="com.sm.persistence.AddressBO" />
</set>
<set name="corporateCustomers" inverse="true" cascade="all-delete-orphan">
<key>
<column name="LOA_ID" precision="38" scale="0" not-null="false"/>
</key>
<one-to-many class="com.sm.persistence.CorporateCustomerBO" />
</set>
<set name="privateCustomers" inverse="true" cascade="all-delete-orphan">
<key>
<column name="LOA_ID" precision="38" scale="0" not-null="false" />
</key>
<one-to-many class="com.sm.persistence.PrivateCustomerBO"/>
</set>
<set name="unwrappedAccount" inverse="true" cascade="all-delete-orphan">
<key>
<column name="LOA_ID" precision="38" scale="0" not-null="false"/>
</key>
<one-to-many class="com.sm.persistence.UnwrappedAccountBO" />
</set>
<set name="wrappedAccount" inverse="true" cascade="all-delete-orphan">
<key>
<column name="LOA_ID" precision="38" scale="0" not-null="false" />
</key>
<one-to-many class="com.sm.persistence.WrappedAccountBO"/>
</set>
</class>
</hibernate-mapping>
Child -
<?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 default-lazy="false">
<class name="com.sm.persistence.PrivateCustomerBO" table="RER_CUSTOMER_DETAIL">
<id name="privateCustomerId" type="long">
<column name="RERE_CUSTOMER_ID" precision="38" scale="0"/>
<generator class="com.sm.persistence.dao.seqgen.PrivateCustomerSeqGen">
</generator>
</id>
<many-to-one name="loaDetail" class="com.sm.persistence.LOADetailBO" fetch="join">
<column name="LOA_DETAILS_ID" precision="38" scale="0"/>
</many-to-one>
<property name="title" type="string">
<column name="TITLE"/>
</property>
<property name="firstName" type="string">
<column name="FIRST_NAME"/>
</property>
<property name="surname" type="string">
<column name="SURNAME"/>
</property>
<set name="address" inverse="false" cascade="all-delete-orphan">
<key>
<column name="PRIVATE_CUSTOMER_ID" precision="38" scale="0" not-null="false"/>
</key>
<one-to-many class="com.sm.persistence.AddressBO" />
</set>
<property name="primary" type="string">
<column name="IS_PRIMARY"/>
</property>
<property name="corporate" type="string">
<column name="IS_CORPORATE"/>
</property>
<!--<property name="dateofBirth" type="string">
<column name="DATE_OF_BIRTH"/>
</property>-->
<property name="nationalInsurance" type="string">
<column name="NINO"/>
</property>
</class>
</hibernate-mapping>
I checked parent object both pre and post save and can't find any object with null value populated. However, when I fetch the object hierarchy with criteria api it returns duplicate record with null.
Please guide.
Quick answer:
PrivateCustomerBO is a child of LOADetailBO. So when your java code
saves a PrivateCustomerBO object it will write to all tables
specified against these 2 objects: RER_CUSTOMER_DETAIL = primary
table for PrivateCustomerBO, LOADETAILS = primary table for
LOADetailBO, plus all tables referenced by these two objects via
many-to-one or one-to-many mappings. CORRECT BEHAVIOUR
Expanding the bolded bit above, LOADetailBO is referenced by
PrivateCustomerBO via:
<many-to-one name="loaDetail" class="com.sm.persistence.LOADetailBO" fetch="join">
<column name="LOA_DETAILS_ID" precision="38" scale="0"/>
</many-to-one>
This means that LOADETAILS is additionally referenced as a related
table, not just a parent and a second row is written (in this case
there is some data missing (NULL) because your program hasn't
populated it for the referenced entity). INCORRECT BEHAVIOUR.
Fix: remove the many-to-one mapping shown above (it's redundant and covered by parent).
Please have a look at the below XML code
<?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 Feb 17, 2015 10:01:43 PM by Hibernate Tools 4.3.1 -->
<hibernate-mapping>
<class name="model.main.Family" table="family" catalog="****" optimistic-lock="version">
<id name="idFamily" type="int">
<column name="idFamily" />
<generator class="assigned" />
</id>
<many-to-one name="employee" class="model.main.Employee" fetch="select">
<column name="idEmployee" not-null="true" />
</many-to-one>
<property name="firstName" type="string">
<column name="FirstName" length="45" />
</property>
<property name="middleName" type="string">
<column name="MiddleName" length="45" />
</property>
<property name="lastName" type="string">
<column name="LastName" length="45" />
</property>
<property name="dob" type="date">
<column name="DOB" length="10" />
</property>
<property name="passportNumber" type="string">
<column name="PassportNumber" length="45" not-null="true" />
</property>
<property name="dateLeft" type="date">
<column name="DateLeft" length="10" />
</property>
<property name="lastUpdated" type="timestamp">
<column name="LastUpdated" length="19" not-null="true" />
</property>
<set name="visas" table="visa" inverse="true" lazy="true" fetch="select">
<key>
<column name="idFamily" />
</key>
<one-to-many class="model.main.Visa" />
</set>
</class>
</hibernate-mapping>
It is the Hibernate mapping class of my database table Family. We create the database separately using MySQL Work bench and then generate the mapping classes. We auto generated the mapping files using netbeans as mentioned in "Generating Hibernate Mapping Files and Java Classes" section of netbeans tutorial.
Now we have a problem. That is, we changed the primary key (idFamily) of our table Family to an auto generated field inside MySQL. Now, how can we change the above hibernate code so it identifies the idFamily as an auto generated one?
The other question is, manually editing one mapping class without regenerating all the mappings via a tool can "break" the system? For an example, like messing up with relationships?
In Annotation It work for me as
#GeneratedValue(strategy= GenerationType.IDENTITY)
for you hope it works
<generated-value strategy="IDENTITY" />
You're looking for an identity column. That indicates that the column value is auto-generated as an identity for the row by the RDBMS.
<generator class="identity" />
See the these Hibernate docs for more information. According to it:
Identity
supports identity columns in DB2, MySQL, MS SQL Server, Sybase and HypersonicSQL. The returned identifier is of type long, short or int.
Just replace your generator class to increment it will treat it as autoincrement
<generator class="increment"/>
<?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="com.tech.spring4.model.User" table="Customer">
<id name="id" type="long">
<column name="USERID" unique="true"/>
<generator class="increment"/>
</id>
<property name="username"><column name="username" length="30" not-null="true"></column></property>
<property name="email"><column name="email" length="100" not-null="true"></column></property>
<property name="address"><column name="address" length="100" not-null="true"></column></property>
</class>
</hibernate-mapping>
I have two tables stock and category having many-to-many relationship each other.
Stock.hbm.xml
<hibernate-mapping>
<class name="hibernate.mapping.manytomany.Stock" table="stock">
<id name="stockId" type="java.lang.Integer">
<column name="STOCK_ID" />
<generator class="identity" />
</id>
<property name="stockCode" type="string">
<column name="STOCK_CODE" length="10" not-null="true" unique="true" />
</property>
<property name="stockName" type="string">
<column name="STOCK_NAME" length="20" not-null="true" unique="true" />
</property>
<set name="categories" table="stock_category"
inverse="false" lazy="true" fetch="select" cascade="all" >
<key>
<column name="STOCK_ID" not-null="true" />
</key>
<many-to-many entity-name="hibernate.mapping.manytomany.Category">
<column name="CATEGORY_ID" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Category.hbm.xml
<hibernate-mapping>
<class name="hibernate.mapping.manytomany.Category" table="category">
<id name="categoryId" type="java.lang.Integer">
<column name="CATEGORY_ID" />
<generator class="identity" />
</id>
<property name="name" type="string">
<column name="NAME" length="10" not-null="true" />
</property>
<property name="desc" type="string">
<column name="[DESC]" not-null="true" />
</property>
<set name="stocks" table="stock_category" inverse="true" lazy="true"
fetch="select">
<key>
<column name="CATEGORY_ID" not-null="true" />
</key>
<many-to-many entity-name="hibernate.mapping.manytomany.Stock">
<column name="STOCK_ID" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
And this is my criteria query,
Criteria c = session.createCriteria(Category.class, "c");
c.createAlias("c.stocks", "s");
c.add(Restrictions.eq("c.categoryId", 1));
c.setProjection(Projections.projectionList()
.add(Projections.property("s.stockId"))
.add(Projections.property("s.stockName")));
I need equivalent HQL for this scenario..I've tried this but it gives different result,
String query = "select c.stocks.stockId, c.stocks.stockName from Category c where
c.categoryId=1"
Let me know if you need more details.
OK, so apparently, you missed the section about joins in the documentation:
select s.stockId, // equivalent to the s.stockId projection
s.stockName // equivalent to the s.stockName projection
from Category c // equivalent to the root criteria creation
join c.stocks s // equivalent to the alias creation
where c.categoryId = 1 // equivalent to the restriction addition
I am planning to investigate this issue thoroughly. What i doubt from previous answer for now is there should be ON Clause in join statement. Pardon me if my expectation is wrong.
select s.stockId,s.stockName from Category c join c.stocks s
on c.stockId=s.stockId where c.categoryId = 1 ;
//it might be on c.CATEGORY_ID=s.CATEGORY_ID also
I am trying to update a field in the database to null for an integer field. I am trying to do that using hibernate. I can set object field like String and any other object to null but no integer.
<?xml version="1.0" encoding="UTF-8"?>
<class name="App_Users" table="app_users" schema="bidtool">
<id name="userId" type="int" column="user_id">
<generator class="assigned"/>
</id>
<property name="username" type="string">
<column name="username" length="20" not-null="true" />
</property>
<property name="password" type="string">
<column name="password" length="20" not-null="true" />
</property>
<property name="firstname" type="string">
<column name="firstname" length="20" />
</property>
<property name="lastname" type="string">
<column name="lastname" length="20" />
</property>
<property name="userType" type="int">
<column name="user_type" />
</property>
<many-to-one class="MasterOrg" fetch="select" name="masterOrg">
<column name="master_org_id" />
</many-to-one>
<many-to-one class="CarrierScac" fetch="select" name="carrierScac">
<column name="scac" />
</many-to-one>
<one-to-one class="AppUserDetails" fetch="select" name="details" constrained="true"/>
<set name="profiles" inverse="true">
<key>
<column name="user_id" />
</key>
<one-to-many class="Profiles" />
</set>
<set name="boilerPlates" inverse="true">
<key>
<column name="user_id" />
</key>
<one-to-many class="BoilerPlate" />
</set>
<set name="rates" inverse="true" >
<key>
<column name="user_id" />
</key>
<one-to-many class="BidToolRates" />
</set>
</class>
In the above hibernate mapping code, I want to set MasterOrg field as null.
It is best to use the object wrappers for the primitive types i.e. Integer for int, Double for double, ... etc because primitive types don't allow for the possibility of null which is always possible in a database design.
Even if a value is declared not null in the database an Object type is still useful. Consider the follow scenario as an example.
#Entity
public class ExampleEntity {
#Column(name="some_column") // assume this column is defined not null in the database
private int someProperty;
getttes settters other fields go here
}
Assume you write the following code
ExampleEntity t = new ExampleEntity();
entityManager.persist(t);
In this example t.someProperty has a value of 0 because that is the default value for an int therefore entityManager.persist works but maybe 0 is not a valid value for that column. If you have database constraints on that column then you get an error otherwise you have bad data in the database.
If someProperty was declared with wrapper type of Integer and the developer forgets to set the somePorpety value then you will get a not null exception.
A second reason to always use wrappers is simplicity as a developer I want consistent structure across entities because code is read more often that it is written so universally using wrapper types on entities makes things predictable for some one maintaining the code 5 years from now.
The configuration for User class :
<class name="User" table="users" lazy="false">
<id name="id" column="id">
<generator class="native"/>
</id>
<property name="type" column="type"/>
<many-to-one name="parent" column="parent"/>
<property name="loginName" column="login_name" unique="true" not-null="true" index="idx_users_login_name" length="50"/>
<property name="name" column="name" length="50"/>
<property name="password" column="password"/>
<property name="email" column="email" length="50"/>
<property name="locale" column="locale" length="20"/>
<property name="locked" column="locked"/>
<many-to-one name="metadata" column="metadata_id"/>
<set name="userSpaceRoles" cascade="all" inverse="true" lazy="false">
<key column="user_id"/>
<one-to-many class="UserSpaceRole"/>
</set>
</class>
and for the class MeetingItem is:
<class name="MeetingItem" table="meeting_item">
<id name="id" column="meeting_item_id" type="long">
<generator class="native"/>
</id>
<property name="summary" column="summary" type="string"/>
<property name="detail" column="detail" type="string"/>
<many-to-one name="space" column="space_id"/>
<property name="date" column="date" type="date"/>
<list name="users" cascade="all" lazy="false">
<key column="meeting_item_id"/>
<index column="idx"/>
<one-to-many class="User"/>
</list>
</class>
The problem is I am getting the exception:
org.hibernate.MappingException: Association references unmapped class: info.domain.User
at org.hibernate.cfg.HbmBinder.bindCollectionSecondPass(HbmBinder.java:2380)
at org.hibernate.cfg.HbmBinder.bindListSecondPass(HbmBinder.java:2231)
at org.hibernate.cfg.HbmBinder$ListSecondPass.secondPass(HbmBinder.java:2729)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:43)
at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1130)
at org.hibernate.cfg.Configuration.generateSchemaUpdateScript(Configuration.java:936)
at org.hibernate.tool.hbm2ddl.SchemaUpdate.execute(SchemaUpdate.java:140)
The mapping of the list is creating the problem. What I am doing wrong?
Edit:
This two configuration resides in different file, if these two are placed in same xml then the problem is not occurring.
please add a reference to the mapping file (which maps info.domain.User) into hibernate.cfg.xml.
Please add class level annotations to register the class as a Spring bean, i.e #Entity in this case since you are not using xml configuration.