I have a mapping for a set with a composite-element where a property has the attribute insert="false" set. However, upon saving of the parent object, this attribute seems to be ignored as Hibernate tries to insert it anyway.
What am I missing here? How can I get this to work as expected?
<set name="deals" cascade="all,save-update" >
<subselect>
...some select statement...
</subselect>
<key column="user_id" />
<composite-element class="UserDeal">
<property name="dealId" column="deal_id" type="string" />
<property name="dealName" column="deal_name" type="string" update="false" insert="false" />
</composite-element>
</set>
In the example above, I don't want the INSERT statement to include the deal_name property, but it's still included for some reason.
Related
I downloaded and installed the source code for the Perseus Project (Open Source Code) on to Ubuntu 14.04, and Tomcat 6. The project hasn't been modified in years, so it must be some new feature in hibernate that is doing this.
I see the solutions here on very many threads, but they address the issue of debugging code as it is being written as opposed to migrating a project that quite certainly worked "at one time". The code that I am working with hasn't been modified since 2008-2011. (I've determined that they are running it now on "Mandriva Linux 2010.2") Therefore, I need to be able to fix this issue on a large scale - either a search/replace method or a configuration file change. I have never used hibernate myself, so I don't understand the full meaning of the posted answers.
Thanks.
Also, the files don't use the # annotated syntax, but the mappings seem to be done via XML files. At this point, I would not mind just to update all these files if I knew what to change.
<?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 package="perseus.document.dao">
<class name="HibernateChunkDAO$ChunkRow" table="hib_chunks" batch-size="10">
<id name="id" type="int" column="id" unsaved-value="null">
<generator class="native" />
</id>
<property name="documentID" column="document_id" type="string"
length="50" index="doc_idx doc_type_idx doc_type_value_idx
doc_cid_idx doc_so_eo_idx doc_so_eo_type_idx doc_dq_idx
doc_so_eo_type_val_idx" />
<property name="elementName" column="element" type="string"
length="20" />
<property name="type" column="type" type="string" length="30"
index="doc_type_idx doc_type_value_idx doc_so_eo_type_idx
doc_so_eo_type_val_idx" />
<property name="value" column="value" type="string" length="250"
index="doc_type_value_idx doc_so_eo_type_val_idx" />
<property name="position" column="position" type="int" />
<property name="absolutePosition" column="abs_position" type="int" />
<property name="chunkID" column="chunk_id" type="string"
length="255" index="doc_cid_idx" />
<property name="openTags" column="open_tags" type="text" />
<property name="closeTags" column="close_tags" type="text" />
<property name="startOffset" column="start_offset" type="int"
index="doc_so_eo_idx doc_so_eo_type_idx doc_so_eo_type_val_idx" />
<property name="endOffset" column="end_offset" type="int"
index="doc_so_eo_idx doc_so_eo_type_idx doc_so_eo_type_val_idx" />
<property name="displayQuery" column="display_query" type="string"
length="100" index="doc_dq_idx" />
<property name="head" column="head" type="text" />
<property name="headLanguage" column="head_lang" type="string"
length="10" />
<property name="hasCustomHead" column="custom_head" type="boolean" />
<set name="frequencies" inverse="true" cascade="all-delete-orphan"
lazy="true" batch-size="30">
<key column="chunk_id" on-delete="cascade" />
<one-to-many class="perseus.ie.freq.Frequency" />
</set>
<many-to-one name="lemma" column="lemma_id" cascade="all" lazy="false" />
<!--
<list name="senses" inverse="false" cascade="all-delete-orphan"
lazy="false" batch-size="30">
<key column="chunk_id" />
<list-index column="position" />
<one-to-many class="perseus.voting.Sense" />
</list>
-->
</class>
</hibernate-mapping>
This is happening due to below reason:
You have defined a association in your entity which is not yet persisted in the database and before persisting this association you are trying to flush the Session.For example you have a collection association which has collection of transient instances, so you have to persist this collection first before flushing.
For resolving this issue, you have 2 options:
Either manually persist the collection in your code by calling Session.save() method.
If you want to use tags in Hibernate XML file or want to use annotations make use of cascade="all" (for xml) or cascade=CascadeType.ALL (for annotations) on your collection association.
everyone. I'm brand new using Hibernate.
So here I face a question, I have an entity like below:
<class name="cn.edu.scau.librarica.dao.MessageSession" table="msg_session">
<id name="msid" type="long" unsaved-value="null">
<generator class="identity"/>
</id>
<list name="msgs" cascade="all">
<key column="msid"
update="false" unique="true" not-null="true"/>
<list-index column="list_index"/>
<one-to-many class="Message" />
</list>
</class>
And now what I want to achieve is:
select Message m where msid=# and m.t<## and m.t>###
How can I represent it with Criteria?
Thank you for your attentions and advices, in advance.
UPDATE
As one of the answer guide, I have got the point that composite-element is not queryable, so I made a both-sid one-to-many map(changed are above)
And now I can query but now I found another problem:
How can I mapped the composite-id with foreign-key
Message are map like this:
<class name="Message">
<composite-id>
<generator class="foreign">
<!-- What here??? -->
</generator>
</composite-id>
</class>
As instructed, one-to-many may use set rather than list, so I can hardly find sample meets my need(due to Message should be ordered).
Any advice? I am still searching for that.
Thanks for help.
You can't directly select the Message as it is a component and not an entity. Components don't have an independent life cycle. They cannot be queried, created or deleted on their own, they always have to be accessed via the entity in which they are embedded (MessageSession in your case).
To make it into an Entity the table should have it's own primary key. In your case that doesn't seem to be so. You will need to change the schema so that the table corresponding to Message has a primary key and change the mapping to use one-to-many instead of composite-element.
If you can't do that you will have to query the MessageSession and get message out of it.
P.S: Hibernate is quite complex, I haven't see too many people being able to just pick it up along the way just trying things out. You are more likely to succeed if you spend some time studying the underlying concepts (which are more important than just mapping & querying).
here is the author of question.
After several days of research, I found the way to satisfied my require somehow.
Maping Message
<class name="cn.edu.scau.librarica.dao.Message" table="message">
<id name="id" type="long">
<generator class="identity" />
</id>
<many-to-one name="ms" class="cn.edu.scau.librarica.dao.MessageSession"
column="msid" not-null="true" insert="false" update="false" />
<property name="s" type="long" />
<property name="t" type="timestamp" />
<property name="m" type="string" />
</class>
Mapping MessageSession
<class name="cn.edu.scau.librarica.dao.MessageSession" table="msg_session">
<id name="msid" type="long" unsaved-value="null">
<generator class="identity"/>
</id>
<property name="latest" type="timestamp" />
<list name="msgs" table="msg_session_msgs" cascade="all">
<key column="msid"
update="false" not-null="true"/>
<list-index column="list_index"/>
<one-to-many class="cn.edu.scau.librarica.dao.Message" />
</list>
</class>
Among them, the unimportant are neglected.
Things go quite well while I can find the "one" with restrictions of "many" or inversely. just like this:
DetachedCriteria dc = DetachedCriteria.forClass(Message.class)
.createCriteria("ms")
.add(Restrictions.eq("msid", msid));
if (after != null)
dc.add(Restrictions.gt("t", after));
if (before != null)
dc.add(Restrictions.lt("t", before));
...can search out Message during the specified period from specified MessageSession.
So the trick is objects can't be returned by Criteria unless match them as entity.
On the underlaying database, it will be a little redundant, since Message can be uniquely identified by (msid,list_index), so I am finding a way to match <-this as the primary key for Message.
I am developing a database connector in order to retrieve data from a Oracle database. I have used the Hibernate tool included as a plug-in in Eclipse for the generation of the Hibernate mapping files because I have a lot of classes and tables to map. However, when I run the application, I have just get the following Exception:
java.lang.ClassCastException: org.hibernate.type.StringType cannot be cast to org.hibernate.type.VersionType
at org.hibernate.tuple.PropertyFactory.buildVersionProperty(PropertyFactory.java:107)
at org.hibernate.tuple.entity.EntityMetamodel.<init>(EntityMetamodel.java:181)
at org.hibernate.persister.entity.AbstractEntityPersister.<init>(AbstractEntityPersister.java:485)
at org.hibernate.persister.entity.SingleTableEntityPersister.<init>(SingleTableEntityPersister.java:133)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:84)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:286)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1845)
at eu.cartif.dwhconn.database.DBManager.checkDWHStatus(DBManager.java:57)
at eu.cartif.dwhconn.database.DBManager.main(DBManager.java:24)
I think the problem could be the type of the property of the hbm file:
<hibernate-mapping>
<class name="eu.cartif.dwhconn.database.Ifcactorrole" table="IFCACTORROLE">
<id name="role" type="string">
<column name="ROLE" length="50" />
<generator class="assigned" />
</id>
<property name="userdefinedrole" type="string">
<column name="USERDEFINEDROLE" />
</property>
<property name="description" type="string">
<column name="DESCRIPTION" length="3000" />
</property>
<set name="ifcpersons" table="IFCPERSON" inverse="true" lazy="true" fetch="select">
<key>
<column name="ROLES" length="50" />
</key>
<one-to-many class="eu.cartif.dwhconn.database.Ifcperson" />
</set>
<set name="ifcpersonandorganizations" table="IFCPERSONANDORGANIZATION" inverse="true" lazy="true" fetch="select">
<key>
<column name="ROLES" length="50" />
</key>
<one-to-many class="eu.cartif.dwhconn.database.Ifcpersonandorganization" />
</set>
</class>
</hibernate-mapping>
However, I am not sure about it and I would not like to change all the types in all the hbms if that is not the solution. Anyone could help me, please.
Thank you very much in advance,
May you have a nice day
In my case, I generated entity from DB and some entities column name has "version". Generator for this names add "#Version" annotation, but this column type is String - for #Version annotation unacceptable
This types of problem occurs
if there are column name as "version" of "VARCHAR" (string) type in any table, means in hibernate "property" becomes "version" and "type" becomes "string", like-
in .hbm.xml file
<version name="xyz" type="string">
<column name="xyz" length="30" not-null="true" />
</version>
if there are any missing getter or setter method for a particular attribute.
if there are mismatch between .hbm.xml file and POJO class file.
I have checked several times all the mapping classes. Finally, the problem came from a mapping class which had not the proper type for an attribute... :(
Thank you for your responses
Missing length field on
<property name="userdefinedrole" type="string">
<column name="USERDEFINEDROLE" />
</property>
I faced this problem with working on an ancient, hibernate3 software.
The solution is this: until hibernate3.5, StringType was a child class of NullableType.
In hibernate 3.6, this relation was ended.
Thus, StringType was convertable to a NullableType only until hibernate 3.5, from hibernate 3.6 it is not so any more.
The simplest solution is, now decades away from the future: switch back to hibernate 3.5.
My Hibernate hbm file looks something like this with a mysql DB:
<hibernate-mapping>
<class name="com.company.common.bo.position.Parent" table="Parents"
abstract="true">
<id name="id">
<generator class="increment" />
</id>
<property name="date" not-null="true" />
<property name="milliseconds" not-null="true" />
<property name="shares">
<column name="shares" precision="19" scale="6" not-null="true" />
</property>
<many-to-one name="ticker" column="tickerID" not-null="true" index="_tickerID_date_milliseconds_idx" />
<many-to-one name="auditTrail" column="auditTrailID"
not-null="false" cascade="save-update" lazy="false" fetch="select" />
<union-subclass name="com.company.common.bo.position.SubclassA"
table="SubclassAs">
<many-to-one name="account" column="accountID" not-null="true" foreign-key="SubclassA_accountID_fk" />
<many-to-one name="portfolio">
<column name="portfolioID" not-null="true"/>
</many-to-one>
<many-to-one name="individualTrade">
<column name="individualTradeID" not-null="false"/>
</many-to-one>
<many-to-one name="positionTransfer" column="positionTransferID"
cascade="save-update" not-null="false"/>
</union-subclass>
<union-subclass
name="com.company.common.bo.position.SubclassB" table="SubclassBs">
<many-to-one name="individualTrade">
<column name="individualTradeID" not-null="false" />
</many-to-one>
<many-to-one name="account" column="accountID" not-null="true" foreign-key="SubclassBs_accountID_fk"/>
<many-to-one name="internalExecution" column="executionID"
cascade="save-update" not-null="false" />
</union-subclass>
<union-subclass name="com.company.common.bo.position.SubclassC"
table="SubclassCs">
</union-subclass>
</class>
So basically i have an abstract class Parent and 3 subclasses (SubclassA, B, C) that extend it. In the database there are 3 tables (for the 3 subclasses). The id generator is "increment" because the union subclass mapping doesn't allow me to use native. So it looks like with increment, the ID is unique among the 3 tables. When I look at the hibernate sql, it basically finds the max ID from all 3 tables, and uses that as the next ID. But the query it uses seems very inefficient. This is what I see it doing:
select max(ids_.id) from ( select id from SubclassAs union select id from SubclassBs union select id from SubclassCs ) ids_
Which takes over 12 seconds to run. Each of those tables has more than a million records each. It's unioning every single ID together and then selecting the max out of that.
If i do something like this:
select max(ids_.id) from ( select max(id) as id from SubclassAs union select max(id) as id from SubclassBs union select max(id) as id from SubclassCs ) ids_
It is much faster, less than one millisecond, because the inner union only gets the max from each table, and then i select just the max out of those 3 records.
Is there a way to tell hibernate to do this instead, or is there a better way of using a generator for the ID across these 3 tables?
Thanks
If increment doesn't satisfy you, you can use some other generator strategy, and, since MySQL doesn't support sequences, the next suitable option is a hilo strategy.
I'm a hibernate newbie and I'm not entirely sure how to get the cascade behavior I'm looking for.
I have two classes Student and Class with unidirectional many-to-many mapping. When I delete a Student, I've this exception
Cannot delete or update a parent row: a foreign key constraint fails (projet.T_CLASS_STUDENT, CONSTRAINT FK5DBF3D8967BCDD8B FOREIGN KEY (PERSON_ID) REFERENCES T_STUDENT (PERSON_ID))
I don't understand why, I set cascade to "delete" but it's doesn't work !
In fact, when I delete a student I want to delete all Student which are in the association table.
My mapping files are:
<class name="persistenceClass.Class" table="T_CLASS">
<id name="Id" column="CLASS_ID">
<generator class="native" />
</id>
<many-to-one name="Formation" column="CLASS_FORMATION" class="persistenceClass.Formation" />
<many-to-one name="Year" column="CLASS_YEAR" class="persistenceClass.Year" />
<set name="Students" table="T_CLASS_STUDENT" cascade="delete" >
<key column="CLASS_ID" />
<many-to-many class="persistenceClass.Student" column="PERSON_ID" />
</set>
</class>
and:
<class name="persistenceClass.Person" table="T_PERSON" >
<id name="Id" column="PERSON_ID" >
<generator class="native" />
</id>
<property name="FirstName" column="PERSON_FIRST_NAME" not-null="true" />
<property name="LastName" column="PERSON_LAST_NAME" not-null="true" />
<property name="Type" column="PERSON_TYPE" not-null="true" />
<property name="BirthDate" column="PERSON_BIRTH_DATE" />
<property name="BirthCity" column="PERSON_BIRTH_CITY" />
<property name="PhoneNumber" column="PERSON_PHONE_NUMBER" />
<property name="MobileNumber" column="PERSON_MOBILE_NUMBER" />
<property name="Mail" column="PERSON_MAIL" />
<property name="Address" column="PERSON_ADDRESS_ADDRESS" />
<property name="ZipCode" column="PERSON_ADDRESS_ZIPCODE" />
<property name="City" column="PERSON_ADDRESS_CITY" />
<property name="Image" column="PERSON_IMAGE" type="image" />
<many-to-one name="Country" column="PERSON_ADDRESS_COUNTRY" class="persistenceClass.Country" />
<many-to-one name="BirthCountry" column="PERSON_BIRTH_COUNTRY" class="persistenceClass.Country" />
<many-to-one name="Civility" column="PERSON_CIVILITY" class="persistenceClass.Civility" />
<many-to-one name="Sex" column="PERSON_SEX" class="persistenceClass.Sex" />
<joined-subclass name="persistenceClass.Student" table="T_STUDENT">
<key column="PERSON_ID" />
</joined-subclass>
<joined-subclass name="persistenceClass.Teacher" table="T_TEACHER">
<key column="PERSON_ID" />
</joined-subclass>
</class>
As you described, you have an unidirectional many-to-many relationship between class and student with a cascade on delete. That means cascade on delete only works if you delete a class and not a student. If you want to delete a student, you have to first remove it from the collection in the corresponding class object. Otherwise you get the exception described in your question.
If you delete a class all students in that class should be deleted as well - unless these students participate in other associations.
I dont know, if I fully understand your code (I am using annotations in my project). But you have an unidirected association class => student with implicit join table. When you delete student, there is no way for the person entity to delete itself from the association.
This way of making many to many isnt recomended in documentation. Recomended is to explicitly specify the joining entity, bacause its more flexible. You can then easily query or delete the association, and you cas assign association parameters.