Hibernate Mapping List - Index - java

Hi I have problem with my hibernate. When i try to save List to SQLite database it crashes on ID of object stored in the list ... in the database first element gets number 0. The first element of list is succesfully saved but another gives ERROR.
Now what the netbeans says:
SEVERE: Could not synchronize database state with session
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1 ......
And now my mapped class
WITH LIST
<class dynamic-insert="false" table="users" dynamic-update="false" mutable="true" name="DataClasses.User" optimistic-lock="version" polymorphism="implicit" select-before-update="false">
<id name="ID" column="ID">
<generator class="increment" />
</id>
<list name="notebooks" outer-join="true" lazy="false" cascade="all" >
<key column="userID"/>
<list-index column="ID"/>
<one-to-many class="DataClasses.Notebook"/>
</list>
</class>
OBJECT STORED IN LIST
<class dynamic-insert="true" table="notebooks" dynamic-update="false" mutable="true" name="DataClasses.Notebook" optimistic-lock="version" polymorphism="implicit" select-before-update="false">
<id name="ID" column="ID">
<generator class="increment"/>
</id>
<property name="name" type="string" />
<property name="text" type="string" />
<many-to-one name="subject" lazy="false" outer-join="true" class="DataClasses.Subject" column="subject" cascade="all"/>
<property name="lastModified"/>
</class>

I think you need to change the generator class to "native" - then let the database increment the keys.

Related

A different object with the same identifier value was already associated with the session, even when evicting the objects

I am using Hibernate 5.6 and have user Profile with Groups, which have Columns, which have ColumnProperties. I'd like to clone a column of a profile and attach it to the column group.
Profile -> Groups -> Columns -> ColumnProperties
I get this error:
10:58:39,793 ERROR
[com.myApp.core.rmgt.profile.service.RmgtProfileServiceImpl] (default
task-2) javax.persistence.EntityExistsException: A different object
with the same identifier value was already associated with the session
:
[com.myApp.core.rmgt.profile.business.object.RmgtColumnPropertyBVOImpl#124320]
Here's my mapping files:
<hibernate-mapping>
<class name="com.myapp.core.rmgt.profile.business.object.RmgtProfileBVOImpl" table="rmgt_t_profile" proxy="com.myapp.core.rmgt.profile.common.business.object.RmgtProfileBVO">
<id name="rowguid" column="rowguid" type="java.lang.Long">
<generator class="sequence">
<param name="sequence_name">rmgt_t_profile_rowguid_seq</param>
</generator>
</id>
...
<set name="groups" table="rmgt_t_group" lazy="false" cascade="all-delete-orphan" order-by="rmgtg_group_order asc">
<key column="rmgtg_fk_profile_id" not-null="true"/>
<one-to-many class="com.myapp.core.rmgt.profile.business.object.RmgtGroupBVOImpl"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.myapp.core.rmgt.profile.business.object.RmgtGroupBVOImpl" table="rmgt_t_group" proxy="com.myapp.core.rmgt.profile.common.business.object.RmgtGroupBVO">
<id name="rowguid" column="rowguid" type="java.lang.Long">
<generator class="sequence">
<param name="sequence_name">rmgt_t_group_rowguid_seq</param>
</generator>
</id>
...
<set name="columns" table="rmgt_t_column" lazy="false" cascade="all-delete-orphan" order-by="rmgtc_column_order asc">
<key column="rmgtc_fk_group_id" not-null="true"/>
<one-to-many class="com.myapp.core.rmgt.profile.business.object.RmgtColumnBVOImpl"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.myapp.core.rmgt.profile.business.object.RmgtColumnBVOImpl" table="rmgt_t_column" proxy="com.myapp.core.rmgt.profile.common.business.object.RmgtColumnBVO">
<id name="rowguid" column="rowguid" type="java.lang.Long">
<generator class="sequence">
<param name="sequence_name">rmgt_t_column_rowguid_seq</param>
</generator>
</id>
...
<set name="columnProperties" table="rmgt_t_column_property" lazy="false" cascade="all-delete-orphan" order-by="rmgtcp_order asc">
<key column="rmgtcp_fk_column_id" not-null="true"/>
<one-to-many class="com.myapp.core.rmgt.profile.business.object.RmgtColumnPropertyBVOImpl"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.myapp.core.rmgt.profile.business.object.RmgtColumnPropertyBVOImpl" table="rmgt_t_column_property" proxy="com.myapp.core.rmgt.profile.common.business.object.RmgtColumnPropertyBVO">
<id name="rowguid" column="rowguid" type="java.lang.Long">
<generator class="sequence">
<param name="sequence_name">rmgt_t_column_property_rowguid_seq</param>
</generator>
</id>
<property name="key" type="java.lang.String" column="rmgtcp_key" not-null="true" />
<property name="value" type="java.lang.String" column="rmgtcp_value" not-null="true" />
<property name="order" type="java.lang.Integer" column="rmgtcp_order" not-null="true" />
</class>
</hibernate-mapping>
What I do is i fetch a Profile from DB, then I use Spring's BeanUtils.copyProperties() to create a copy of the column that I want to clone. I made sure to evict all columnProperties before I proceed.
RmgtColumnBVO column = columnService.findLazyById(columnId);
// Evict all properties to force hibernate write new instances to DB
column.getColumnProperties().stream().forEach(x -> profileDAO.getSession().evict(x));
RmgtColumnBVO columnClone = new RmgtColumnBVOImpl();
BeanUtils.copyProperties(column, columnClone);
columnClone.setRowguid(null);
columnClone.setProfileId(profileId);
columnClone.setGroupId(groupId);
Then I null all rowguids of columnProperties objects of the columnClone:
// clone properties
Set<RmgtColumnPropertyBVO> propertys = column.getColumnProperties();
Set<RmgtColumnPropertyBVO> propertysClone = new HashSet<RmgtColumnPropertyBVO>();
for (RmgtColumnPropertyBVO property : propertys) {
RmgtColumnPropertyBVO propertyClone = new RmgtColumnPropertyBVOImpl();
BeanUtils.copyProperties(property, propertyClone);
propertyClone.setRowguid(null);
propertysClone.add(propertyClone);
}
columnClone.setColumnProperties(propertysClone);
After that, I fetch the profile and attach the cloned column to it and save the profile again:
RmgtProfileBVO profile = profileService.findById(column.getProfileId());
profile.getGroup(groupId).getColumns().add(columnClone);
profileService.saveOrUpdate(profile, object.getCreationUser());
What can I do to fix the problem? I don't understand why Hibernate is still complaining about the properties when I evicted every original one.
I found a solution for my problem. I replaced the profileService.saveOrUpdate() with profileService.merge() which did the job (although I do not fully understand why saveOrUpdate() does not).
In my opinion, saveOrUpdate should
Check if profile exists and check if there are changes (new elements in collections, new attribute values).
Check for every mapped collection (in my case: columns) if there are attribute changes or new items
Traverse the mapping tree and check for every mapped collection (columnProperties) of a mapped collection (columns) if value changes or new items (which was the case for me) and update/insert accordingly.

How to create multiple version of one entity using hibernate xml?

I have one entity, customer for example, this entity is mapped with table. So, this entity is used in different places of application. In each case we need different sets of fields. Some data to display it on view, some service data (different flags and statuses for example) and sometimes all data stored in database. For now I do it like
<class name="Customer" table="customer" entity-name="CustomerFull">
<id name="id">
<property name="property 1"
<property name="property 2"
<property name="property 3"
<property name="property 4"
...
<class name="Customer" table="customer" entity-name="CustomerLight">
<id name="id">
<property name="property 1"
<property name="property 2"
...
<class name="Customer" table="customer" entity-name="OneMoreCustomer">
<id name="id">
<property name="property 3"
<property name="property 4"
...
Is it correct way to solve my task like this?
Yes It is possible, You have to add these code in your hibernate.xml file where you are mapping models or hbm files, in this technique we don't have to create any extra files for models or hbm we can add all entities in single hibernate file
<hibernate-mapping>
<class name="Employee" table="employee">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="name" type="java.lang.String">
<column name="name"/>
</property>
</class>
<class name="Address" table="address">
<id name="id" type="java.lang.Integer">
<column name="id"/>
<generator class="native"/>
</id>
<property name="address" type="java.lang.String">
<column name="address"></column>
</property>
</class></hibernate-mapping>

Java Hibernate Mapping File not working

The error I get is " org.hibernate.MappingException: Repeated column in mapping for entity: cdd.model.Answer column: answer_id (should be mapped with insert="false" update="false") ". However when I put those as attributes I get the error: "Attribute "insert" must be declared for element type "id"."
Any help would be appreciated.
Class:
public class Answer {
UUID answerID;
String content;
//constructors and getters and setters
}
Table:
CREATE TABLE IF NOT EXISTS answer (
answer_id uuid NOT NULL ,
content text NOT NULL,
primary key(answer_id)
);
Hibernate Mapping File:
<!-->==== Answer ====<!-->
<class name="cdd.model.Answer" table="answer" >
<id column="answer_id" name="answerID"
type="org.hibernate.type.PostgresUUIDType"
insert="false" update="false">
<generator class="org.hibernate.id.UUIDGenerator"/>
</id>
<property column="content" name="content" type="org.hibernate.type.TextType"/>
</class>
Note
I have a Question class where a question has a set of answers. This is the mapping I used. I am posting it because the error I'm gettng may be because of how I mapped this one-to-many relationship (I'm not sure).
<!-- ==== Question ==== -->
<class name="cdd.model.Question" table="question">
<id column="question_id" name="questionID" type="org.hibernate.type.PostgresUUIDType">
< generator class="org.hibernate.id.UUIDGenerator"/>
</id>
<many-to-one column="submitted_by" name="submittedBy" not-null="true"/>
<many-to-one column="parentCategory" name="parentCategory" not-null="true"/>
<property column="title" name="title" type="org.hibernate.type.TextType"/>
<property column="correct_answer" name="correctAnswer" type="org.hibernate.type.TextType"/>
<property column="date_submitted" name="dateSubmitted" type="org.hibernate.type.TimestampType"/>
<set cascade="all" name="answers" table="answer">
<key column="answer_id" not-null="true"/>
<one-to-many class="cdd.model.Answer"/>
</set>
<join inverse="true" optional="true" table="category_questions">
<key column="question_id"/>
</join>
<join inverse="true" optional="true" table="accepted_questions_by_user">
<key column="question_id"/>
</join>
</class>
Question Entity:
<id column="question_id" name="questionID" type="org.hibernate.type.PostgresUUIDType">
<generator class="org.hibernate.id.UUIDGenerator"/>
</id>
Answer Entity:
<id column="answer_id" name="answerID" type="org.hibernate.type.PostgresUUIDType"
insert="false" update="false">
<generator class="org.hibernate.id.UUIDGenerator"/>
</id>
remove insert="false" update="false" from Answr entity
should look someting like this
<id column="answer_id" name="answerID" type="org.hibernate.type.PostgresUUIDType" >
<generator class="org.hibernate.id.UUIDGenerator"/>
</id>
update, insert (optional - defaults to true): specifies that the mapped columns should be included in SQL UPDATE and/or INSERT statements. Setting both to false allows a pure "derived" property whose value is initialized from some other property that maps to the same column(s), or by a trigger or other application.

How to tell Hibernate to not Load a Object?

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.

MultipleBagFetchException with two hbm.xml files

I'm using three java objects that are mapped with Hibernate with this pattern :
TaskModel.class -> 1:N -> TaskModelPropertiesGroup.class -> 1:N -> TaskModelProperty.class
At the project deployment I get this exception :
org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
Yes, I've done my homework, I've seen couple of answers about that, but no one about how to modify hbm.xml files according.
1 #LazyCollection(LazyCollectionOption.FALSE)
Don't know how to change that in my mappings since I am already using lazy="false".
2 Changing List to Set
I've tried to change List<> to Set<> inside my classes but I don't think this is the way...
Here are my mappings :
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="com.spectotechnologies.website.projects.helper.TaskModel" entity-name="com.spectotechnologies.website.projects.helper.TaskModelComplete" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="projects_tasksModels">
<id name="keyTaskModel">
<generator class="native"/>
</id>
<property name="name"/>
<property name="description"/>
<!-- Complete -->
<bag name="propertiesGroups" table="projects_tasksModelsPropertiesGroups" lazy="false" fetch="join" cascade="all">
<key column="keyTaskModel"/>
<one-to-many class="com.spectotechnologies.website.projects.helper.TaskModelPropertiesGroupComplete" />
</bag>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class dynamic-insert="false" dynamic-update="false" mutable="true" name="com.spectotechnologies.website.projects.helper.TaskModelPropertiesGroup" entity-name="com.spectotechnologies.website.projects.helper.TaskModelPropertiesGroupComplete" optimistic-lock="version" polymorphism="implicit" select-before-update="false" table="projects_tasksModelsPropertiesGroups">
<id name="keyTaskModelPropertiesGroup">
<generator class="native"/>
</id>
<property name="keyTaskModel"/>
<property name="name"/>
<property name="description"/>
<!-- Complete -->
<bag name="properties" table="projects_tasksModelsProperties" lazy="false" fetch="join" cascade="all">
<key column="keyTaskModelPropertiesGroup"/>
<one-to-many class="com.spectotechnologies.website.projects.helper.TaskModelProperty" />
</bag>
</class>
</hibernate-mapping>

Categories