I've got an optional many-to-one relationship between two classes. Hibernate translates the property to be optional by setting the foreign keys to null.
My db-schema does not allow the columns to be null. The property to be optional is represented by the default-value of these columns.
<class name="sth.Alpha" ...>
....
<many-to-one name="beta" not-found="ignore" class="sth.Beta" insert="true" update="true">
<column name="a1/>
<column name="a2/>
</many-to-one>
</class>
<class name="sth.Alpha" ...>
<composite-id>
<key-property name="b1" type="int">
<column name="b1" precision="8" scale="0"/>
</key-property>
<key-property name="b2" type="int">
<column name="b2" precision="8" scale="0"/>
</key-property>
</composite-id>
</class>
selecting data is no problem because of not-found="ignore" in the may-to-one-tag it will result in a null-beta-object. But if I want to insert an Alpha? with beta set to null. I get an Exception, that it is not possible to insert null to a1 and a2.
I get rid of that problem if I set insert and update to false. But this results in not saving the relationship if it is set.
Database-Schema cannot be changed and Hibernate-version is fixed to 3.5
I would also be happy if you tell me, that it is not possible
how to use 0 instead of null in conjunction with <id unsavedvalue="whatever"> might help
or
other solution
Related
I have hibernate entity with two many-to-one associations and composite foreign keys, each with 3 fields. Two fields are common for both keys. There are mapping:
<class dynamic-insert='true' dynamic-update='true' entity-name='...' table='...'>
<composite-id>
<key-property name='FaultId' type='long' column='FAULT_ID'/>
<key-property name='RowVersion' type='long' column='ROWVERSION'/>
</composite-id>
<many-to-one name='Pot' class='Pot'>
<column name='SMELTER_ID' not-null='true'/>
<column name='ROOM_ID' not-null='true'/>
<column name='POT_ID' not-null='true'/>
</many-to-one>
<many-to-one name='Event' class='PotEventRef_NonGui'>
<column name='EVENT_ID' not-null='true'/>
</many-to-one>
<many-to-one name='Shift' class='TimeShift' insert='false' update='false'>
<column name='SMELTER_ID' not-null='true'/>
<column name='ROOM_ID' not-null='true'/>
<column name='TIMESHIFT' not-null='true'/>
</many-to-one>
</class>
Code for inserting entity:
session.persist(entry.getName(), entry.getData());
where session - org.hibernate.Session, entry.getName() - String, entry.getData() - Map<String, Object>.
When i try to insert entity of this class, TIMESHIFT field is not inserted. (Shift object is set and all values are correct). What can be source of problem?
try by changing update value to true & by removing insert='false' in the XML.
<many-to-one name='Shift' class='TimeShift' update='true'>
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.
Problem Summary
I am trying to map a many-to-one with a composite key. So far I haven't been able to locate another question that helps. I know how to map to a composite key with one-to-one, but it is not allowing me to map many-to-one.
Below you will see bhrvJournalDAO has a store_nbr column, that maps to transAcctgBuTxtDAO acctg_bu_id. How can I hit the composite key and tell it to only use the acctgBuId? I do not have a country code (which is the second part of the composite key).
From Here
<hibernate-mapping>
<class name="com.acctg.BhrvJournalDAO" table="transpo_acctg:bhrv_journal">
<id name="jeId" column="je_id">
<generator class="native"/>
</id>
<property name="bhrvInvoiceId" column="bhrv_invoice_id"/>
<property name="storeNbr" column="store_nbr"/>
<property name="loadId" column="load_id"/>
<many-to-one name="transAcctgBuTxt" class="TransAcctgBuTxtDAO" insert="false" update="false" cascade="all">
<column name="store_nbr"></column>
</many-to-one>
</class>
To Here
<hibernate-mapping>
<class name="TransAcctgBuTxtDAO" table="transpo_acctg:trans_acctg_bu_txt">
<composite-id name="transAcctgBuTxtPKDAO" class="TransAcctgBuTxtPKDAO">
<key-property name="acctgBuId" column="acctg_bu_id"/>
<key-property name="languageCode" column="language_code"/>
</composite-id>
<property name="acctgBuAbbr" type="java.lang.String">
<column name="acctg_bu_abbr" />
</property>
<property name="acctgBuDesc" type="java.lang.String">
<column name="acctg_bu_desc" />
</property>
<many-to-one name="transAcctgBuDAO" class="TransAcctgBuDAO" not-null="false"
insert="false" update="false" not-found="ignore" fetch="select">
<column name="acctg_bu_id" />
</many-to-one>
</class>
Mapping
<many-to-one name="transAcctgBuTxt" class="TransAcctgBuTxtDAO"
insert="false" update="false" cascade="all">
<column name="store_nbr"></column>
</many-to-one>
Composite Key Example
<one-to-one name="transAcctgBuTxt" class="TransAcctgBuTxtDAO" property-
ref="transAcctgBuTxtPKDAO.acctgBuId">
<column name = "store_nbr">
</one-to-one>
Error
Foreign key (FK47A121BB6617227C:transpo_acct:bhrv_journal [store_nbr]))
must have same number of columns as the referenced primary
key (transpo_acct:trans_acctg_bu_txt [acctg_bu_id,language_code])
Thanks in advance
Since TransAcctgBuTxtDAO has the composite id of 2 columns, you NEED to provide both values to uniquely identify one entity, period. Maybe you could reconsider if it is really a many-to-one relation between BhrvJournalDAO and TransAcctgBuTxtDAO. Mabye it is actually many-to-many.
I have run my own tests and don't believe this is possible but was hoping to get some confirmation.
I have two objects that are being persisted using hibernate, Child and Parent. A Child always has a reference to a single Parent and and Parent has a Set of Child Objects. On top of this a parent has a List of favorites which consists of Child objects.
This is mapped using the following HBM definitions:
<class name="Parent" table="parent">
<id name="id" column="id">
<generator class="increment"/>
</id>
<set cascade="all,delete-orphan" inverse="true" name="children">
<cache usage="nonstrict-read-write"/>
<key column="parent_id"/>
<one-to-many class="Child"/>
</set>
<list cascade="none" name="favorites">
<cache usage="nonstrict-read-write"/>
<key>
<column name="parent_id" not-null="false"/>
</key>
<index>
<column name="fav_index"/>
</index>
<one-to-many class="Child"/>
</list>
</class>
<class name="Child" table="child">
<id name="id" column="id">
<generator class="increment"/>
</id>
<many-to-one column="parent_id" name="parent" not-null="false"/>
</class>
The trouble I am having is with the column parent_id in the child table. It works fine when I persist Child objects that have references to a parent and when I persist Parent objects that have a list of favorites. However, when I try and remove a child from a parents list of favorites, the column child.parent_id gets set to null, even though I have not removed the Parent Object from the Child before it is persisted.
From my tests, I don't think there is anyway around this other than using a different column name for the favorites key column in the Parent mapping. It just seems a bit of a shame to do that since these two columns will always have the same value.
Does anyone if this is possible or will I have to use two columns?
Thanks
I have 2 classes Tema(Homework) and Disciplina (course), where a Course has a Set of homeworks.
In Hibernate i have mapped this to a one-to-many associations like this:
<class name="model.Disciplina" table="devgar_scoala.discipline" >
<id name="id" >
<generator class="increment"/>
</id>
<set name="listaTeme" table="devgar_scoala.teme">
<key column="Discipline_id" not-null="true" ></key>
<one-to-many class="model.Tema" ></one-to-many>
</set>
</class>
<class name="model.Tema" table="devgar_scoala.teme" >
<id name="id">
<generator class="increment" />
</id>
<property name="titlu" type="string" />
<property name="cerinta" type="binary">
<column name="cerinta" sql-type="blob" />
</property>
</class>
The problem is that it will add (insert rows in the table 'Teme') but it won't delete any rows and i get no exceptions thrown.
Im using the merge() method.
Although your question is unclear (how do you save and delete?), I'd suggest you need to set cascade:
<set cascade="all-delete-orphan">
As a sidenote - avoid names in your native language.
According to your description, I understand that a Tema cannot exist without its Disciplina: if you remove a Tema from the collection, you want it to be deleted. To tell Hibernate to do this, you must use cascade="all-delete-orphan".
<set name="listaTeme" table="devgar_scoala.teme" cascade="all-delete-orphan">
<key column="Discipline_id" not-null="true" ></key>
<one-to-many class="model.Tema" ></one-to-many>
</set>
Refer to the online documentation.