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'>
Related
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.
Hibernate is giving me the following exception
org.hibernate.MappingException: Repeated column in mapping for entity: Pricelist column: ID_OFFER (should be mapped with insert="false" update="false")
but I really cannot find the duplicate reference to ID_OFFER. Here they are the two mapping files involved.
Offer.hbm.xml
<hibernate-mapping>
<class name="Offer" table="OFFERS">
<id name="idOffer" type="java.lang.Long">
<column name="ID_OFFER" not-null="true" precision="10" scale="0"
sql-type="NUMBER" unique="true"/>
<generator class="native">
<param name="sequence">OFFERS_SEQ</param>
</generator>
</id>
<property generated="never" lazy="false" name="name" type="string">
<column name="name" not-null="true" sql-type="VARCHAR2" unique="true"/>
</property>
<set name="pricelists" sort="unsorted" table="PRICELISTS">
<key not-null="true">
<column name="ID_OFFER" not-null="true" precision="10" scale="0" sql-type="NUMBER"/>
</key>
<one-to-many class="Pricelist"/>
</set>
</class>
</hibernate-mapping>
Pricelist.hbm.xml
<hibernate-mapping>
<class name="Pricelist" table="PRICELISTS">
<id name="idPricelist" type="java.lang.Long">
<column name="ID_PRICELIST" not-null="true" precision="10" scale="0" sql-type="NUMBER"/>
<generator class="native">
<param name="sequence">PRICELISTS_SEQ</param>
</generator>
</id>
<property name="name" type="string">
<column length="255" name="NAME" not-null="true" sql-type="VARCHAR2"/>
</property>
<property name="versionMajor" type="integer">
<column name="VERSION_MAJOR" not-null="true" precision="5" scale="0" sql-type="NUMBER"/>
</property>
<property name="versionMinor" type="integer">
<column name="VERSION_MINOR" not-null="true" precision="5" scale="0" sql-type="NUMBER"/>
</property>
<many-to-one class="Offer" name="offer">
<column name="ID_OFFER" not-null="true" precision="10" scale="0" sql-type="NUMBER"/>
</many-to-one>
<many-to-one class="PricelistStatus" name="status">
<column name="ID_STATUS_PRICELIST" not-null="true" precision="10"
scale="0" sql-type="NUMBER"/>
</many-to-one>
<property name="validFrom" type="calendar">
<column name="INIT_TIMESTAMP" not-null="true" scale="6" sql-type="TIMESTAMP"/>
</property>
<property name="validUntil" type="calendar">
<column name="END_TIMESTAMP" not-null="false" scale="6" sql-type="TIMESTAMP"/>
</property>
</class>
</hibernate-mapping>
I am going crazy. Can anybody see where is it supposed to be duplicated the reference to the column ID_OFFER? Please note: two tables of my schema have a column named like that: OFFERS.ID_OFFER, which is the primary key of the table OFFERS and PRICELIST.ID_OFFER which has a foreign key constraint referencing, obviously, OFFERS.ID_OFFER.
You forgot about map this column as owning side (Offer.hbm.xml file)
<set name="pricelists" sort="unsorted" table="PRICELISTS">
<key not-null="true">
<column name="ID_OFFER" not-null="true" precision="10" scale="0" sql-type="NUMBER"/>
</key>
<one-to-many class="Pricelist"/>
</set>
it should look like (look at inverse="true"):
<set name="pricelists" sort="unsorted" table="PRICELISTS" inverse="true">
<key not-null="true">
<column name="ID_OFFER" not-null="true" precision="10" scale="0" sql-type="NUMBER"/>
</key>
<one-to-many class="Pricelist"/>
</set>
What #zxcf said, actually made the exception disappear, but made another question appear in my mind. Why doesn't the following mapping creates the same problem?
ServiceElement.hbm.xml
<hibernate-mapping>
<class name="ServiceElement" table="SERVICE_ELEMENTS">
<id name="idServiceElement" type="java.lang.Long">
<column name="ID_SERVICE_ELEMENT" not-null="true" precision="10"
scale="0" sql-type="NUMBER" unique="true"/>
<generator class="native">
<param name="sequence">SERVICE_ELEMENTS_SEQ</param>
</generator>
</id>
<set name="prices" table="PRICES">
<key>
<column name="ID_SERVICE_ELEMENT" not-null="true" precision="10"
scale="0" sql-type="NUMBER"/>
</key>
<one-to-many class="Price"/>
</set>
</class>
</hibernate-mapping>
Price.hbm.xml
<hibernate-mapping>
<class name="Price" table="PRICES">
<id name="idPrice" type="java.lang.Long">
<column name="ID_PRICE" not-null="true" precision="10" scale="0"
sql-type="NUMBER" unique="true"/>
<generator class="native">
<param name="sequence">PRICES_SEQ</param>
</generator>
</id>
<many-to-one class="ServiceElement" name="serviceElement">
<column name="ID_SERVICE_ELEMENT" not-null="true" precision="10"
scale="0" sql-type="NUMBER"/>
</many-to-one>
</class>
</hibernate-mapping>
Isn't it the exact same mapping? But it does not throw any exception. Here they go the DDLs:
CREATE TABLE "CE_PRICELIST"."OFFERS"
( "ID_OFFER" NUMBER(10,0),
"NAME" VARCHAR2(255 CHAR));
CREATE UNIQUE INDEX "CE_PRICELIST"."OFFERS_PK" ON "CE_PRICELIST"."OFFERS" ("ID_OFFER");
ALTER TABLE "CE_PRICELIST"."OFFERS" ADD CONSTRAINT "OFFERS_PK" PRIMARY KEY ("ID_OFFER");
CREATE TABLE "CE_PRICELIST"."PRICELISTS"
( "ID_PRICELIST" NUMBER(10,0),
"ID_OFFER" NUMBER(10,0));
CREATE UNIQUE INDEX "CE_PRICELIST"."PRICELISTS_PK" ON "CE_PRICELIST"."PRICELISTS" ("ID_PRICELIST");
ALTER TABLE "CE_PRICELIST"."PRICELISTS" ADD CONSTRAINT "PRICELISTS_PK" PRIMARY KEY ("ID_PRICELIST");
ALTER TABLE "CE_PRICELIST"."PRICELISTS" ADD CONSTRAINT "PRICELISTS_OFFER_ID_FK" FOREIGN KEY ("ID_OFFER") REFERENCES "CE_PRICELIST"."OFFERS" ("ID_OFFER") ENABLE;
CREATE TABLE "CE_PRICELIST"."SERVICE_ELEMENTS"
( "ID_SERVICE_ELEMENT" NUMBER(10,0));
CREATE UNIQUE INDEX "CE_PRICELIST"."SERVICE_ELEMENTS_PK" ON "CE_PRICELIST"."SERVICE_ELEMENTS" ("ID_SERVICE_ELEMENT");
ALTER TABLE "CE_PRICELIST"."SERVICE_ELEMENTS" ADD CONSTRAINT "SERVICE_ELEMENTS_PK" PRIMARY KEY ("ID_SERVICE_ELEMENT");
CREATE TABLE "CE_PRICELIST"."PRICES"
( "ID_PRICE" NUMBER(10,0),
"ID_SERVICE_ELEMENT" NUMBER(10,0));
CREATE UNIQUE INDEX "CE_PRICELIST"."PRICES_PK" ON "CE_PRICELIST"."PRICES" ("ID_PRICE");
ALTER TABLE "CE_PRICELIST"."PRICES" ADD CONSTRAINT "PRICES_SERVICE_ELEMENT_ID_FK" FOREIGN KEY ("ID_SERVICE_ELEMENT")
REFERENCES "CE_PRICELIST"."SERVICE_ELEMENTS" ("ID_SERVICE_ELEMENT") ENABLE;
OFFERS has a PK on ID_OFFER, which is referenced by PRICELISTS.ID_OFFER; Offer has a Set< Pricelist >;
SERVICE_ELEMENTS has a PK on ID_SERVICE_ELEMENT, which is referenced by PRICES.ID_SERVICE_ELEMENT; ServiceElement has a Set< Price >;
So why is the inverse attribute needed in one case and not in another one?
I'm having this error at Netbeans in my Java code:
org.hibernate.MappingException: Foreign key (FK12A711396456CA10:devolucion_master [devolucion_consecutivo])) must have same number of columns as the referenced primary key (devolucion [detalle_ticket_id,detalle_ticket_ticket_id,detalle_ticket_fondo_fijo_id,detalle_ticket_caja_id,consecutivo]
I made a foreign key from DevolucionMaster to Devolucion, using "consecutivo" from Devolucion to my variable "consecutivo" for DevolucionMaster, the problem is that for Devolucion the "key" is composite key, and I only use for the foreign key one element of the key, maybe that's why (that it needs to be used the 5 that makes the primary key).
Here's the DevolucionMaster.hbm.mxl:
<hibernate-mapping>
<class catalog="pos" name="dunosusa.pos.model.DevolucionMaster" table="devolucion_master">
<composite-id class="dunosusa.pos.model.DevolucionMasterId" name="id">
<key-property name="id" type="int">
<column name="id"/>
</key-property>
<key-property name="detalleTicketTicketId" type="int">
<column name="detalle_ticket_ticket_id"/>
</key-property>
<key-property name="detalleTicketFondoFijoId" type="int">
<column name="detalle_ticket_fondo_fijo_id"/>
</key-property>
<key-property name="detalleTicketCajaId" type="int">
<column name="detalle_ticket_caja_id"/>
</key-property>
</composite-id>
<many-to-one class="dunosusa.pos.model.Devolucion" fetch="select" name ="devolucion">
<column name="devolucion_consecutivo" not-null="true"/>
</many-to-one>
<many-to-one class="dunosusa.pos.model.Usuario" fetch="select" name="usuario">
<column length="6" name="usuario_clave_autorizo"/>
</many-to-one>
<many-to-one class="dunosusa.pos.model.Ticket" fetch="select" insert="false" name="ticket" update="false">
<column name="detalle_ticket_ticket_id" not-null="true"/>
<column name="detalle_ticket_fondo_fijo_id" not-null="true"/>
<column name="detalle_ticket_caja_id" not-null="true"/>
</many-to-one>
<property name="total" type="big_decimal">
<column name="total" not-null="true" precision="10"/>
</property>
<property name="fecha" type="timestamp">
<column length="19" name="fecha"/>
</property>
</class>
</hibernate-mapping>
here the Devolucion.hbm.xml:
<hibernate-mapping>
<class catalog="pos" name="dunosusa.pos.model.Devolucion" table="devolucion">
<composite-id class="dunosusa.pos.model.DevolucionId" name="id">
<key-property name="detalleTicketId" type="int">
<column name="detalle_ticket_id"/>
</key-property>
<key-property name="detalleTicketTicketId" type="int">
<column name="detalle_ticket_ticket_id"/>
</key-property>
<key-property name="detalleTicketFondoFijoId" type="int">
<column name="detalle_ticket_fondo_fijo_id"/>
</key-property>
<key-property name="detalleTicketCajaId" type="int">
<column name="detalle_ticket_caja_id"/>
</key-property>
<key-property name="consecutivo" type="int">
<column name="consecutivo"/>
</key-property>
</composite-id>
<many-to-one class="dunosusa.pos.model.MotivoDevolucion" fetch="select" name="motivoDevolucion">
<column name="motivo_devolucion_id" not-null="true"/>
</many-to-one>
<many-to-one class="dunosusa.pos.model.DetalleTicket" fetch="select" insert="false" name="detalleTicket" update="false">
<column name="detalle_ticket_id" not-null="true"/>
<column name="detalle_ticket_ticket_id" not-null="true"/>
<column name="detalle_ticket_fondo_fijo_id" not-null="true"/>
<column name="detalle_ticket_caja_id" not-null="true"/>
</many-to-one>
<many-to-one class="dunosusa.pos.model.ControlCorte" fetch="select" name="controlCorte">
<column name="control_corte_fondo_fijo_id" not-null="true"/>
<column name="control_corte_caja_id" not-null="true"/>
</many-to-one>
<property name="cantidad" type="big_decimal">
<column name="cantidad" precision="8"/>
</property>
<property name="fecha" type="timestamp">
<column length="19" name="fecha"/>
</property>
<property name="comentario" type="string">
<column length="150" name="comentario"/>
</property>
<property name="controlDevolucion" type="boolean">
<column name="control_devolucion" not-null="true"/>
</property>
<set name="devolucionMasters" inverse="true">
<key>
<column name="devolucion_consecutivo" not-null="true" />
</key>
<one-to-many class="dunosusa.pos.model.DevolucionMaster" />
</set>
</class>
</hibernate-mapping>
DevolucionMaster.java: (only the variables, not the set and get)
public class DevolucionMaster implements java.io.Serializable {
private DevolucionMasterId id;
private Devolucion devolucion;
private Usuario usuario;
private Ticket ticket;
private BigDecimal total;
private Date fecha;
}
Devolucion.java: (same as for DevolucionMaster)
public class Devolucion implements java.io.Serializable {
private DevolucionId id;
private MotivoDevolucion motivoDevolucion;
private DetalleTicket detalleTicket;
private ControlCorte controlCorte;
private BigDecimal cantidad;
private Date fecha;
private String comentario;
private boolean controlDevolucion;
private Set devolucionMasters = new HashSet(0);
}
I don't know what's my error, I've searched over internet about similar errors but no one solution I've read has worked (forgive my bad english).
Thanks a lot!
Yes, you have a composite primary key for the Devolucion class, and you are trying to refer to it by just one simple column/field devolucion_master.devolucion_consecutivo.
I don't know of a way to easily tell Hibernate that devolucion_consecutivo column is actually of type dunosusa.pos.model.DevolucionId.
That's why I have never used composite primary keys. I always have one primary key of type Long (bigint) and enforce uniqueness for a composition of foreign keys where it's needed. It's easier to work with, no issues like the one you're having.
APPENDIX:
I just did some digging and, actually, there is a way to do it :-)
But as I said it's not as easy as using single column PK/FK keys.
Instead of this:
<hibernate-mapping>
<class catalog="pos" name="dunosusa.pos.model.DevolucionMaster" table="devolucion_master">
...
<many-to-one class="dunosusa.pos.model.Devolucion" fetch="select" name="devolucion">
<column name="devolucion_consecutivo" not-null="true"/>
</many-to-one>
...
You should list all PK columns in the FK like this:
<hibernate-mapping package="dunosusa.pos.model">
<class catalog="pos" name="DevolucionMaster" table="devolucion_master">
...
<many-to-one class="Devolucion" fetch="select" name="devolucion">
<column name="devolucion_detalle_ticket_id" not-null="true"/>
<column name="devolucion_detalle_ticket_ticket_id" not-null="true"/>
<column name="devolucion_detalle_ticket_fondo_fijo_id" not-null="true"/>
<column name="devolucion_detalle_ticket_caja_id" not-null="true"/>
<column name="devolucion_consecutivo" not-null="true"/>
</many-to-one>
...
A little advice - use the package attribute of the hibernate-mapping element so you don't have to type it in everywhere - it makes it more readable.
Good luck.
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'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