简体   繁体   中英

Hibernate one-to-one mapping problem

Hello I've the following class:

public class Movimenti implements java.io.Serializable {

private Integer id = null;
private Integer idCommessa = null;
private String nomemovimento = null;
private Movimento preventivato = null;
private Movimento effettivo = null;

public Movimento getEffettivo() {
    return effettivo;
}

public void setEffettivo(Movimento effettivo) {
    this.effettivo = effettivo;
}

public Movimento getPreventivato() {
    return preventivato;
}

public void setPreventivato(Movimento preventivato) {
    this.preventivato = preventivato;
}

public Movimenti() {
}

public Movimenti(Integer idCommessa, String nomemovimento) {
    this.idCommessa = idCommessa;
    this.nomemovimento = nomemovimento;
}

public Integer getId() {
    return this.id;
}

public void setId(Integer id) {
    this.id = id;
}

public Integer getIdCommessa() {
    return this.idCommessa;
}

public void setIdCommessa(Integer idCommessa) {
    this.idCommessa = idCommessa;
}

public String getNomemovimento() {
    return this.nomemovimento;
}

public void setNomemovimento(String nomemovimento) {
    this.nomemovimento = nomemovimento;
}

}

As you can see there are two Movimento references. Movimento looks like this:

public class Movimento {

    Integer id = null;
    Movimenti movimenti;
    String descrizione = null;

    public Movimenti getMovimenti() {
        return movimenti;
    }

    public void setMovimenti(Movimenti movimenti) {
        this.movimenti = movimenti;
    }

    public String getDescrizione() {
        return descrizione;
    }

    public void setDescrizione(String descrizione) {
        this.descrizione = descrizione;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }
}

there is a reference to Movimenti in movimento. Now movimento is a base class for other classes and that gives no problems as SchemaExport does his job correctly. What I want is to have a one-to-one relationship between Movimento and Movimenti, so that I can have automatic retrivial of Movimento when I load up a Movimenti instance and vice versa and automatic deletion of orphaned Movimento objects. So I thought of putting two one-to-one relationships in Movimenti towards Movimento and one backwards. But it doesn't work, it doesn't generate the correct database tables and it even gives out exceptions. These are the mappings (there are even the subclasses that I don't include).

Movimento.hbm.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class dynamic-insert="false" dynamic-update="false" mutable="true" name="persistence.beans.jCommesse.Movimento" optimistic-lock="version" polymorphism="implicit" select-before-update="false">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name = "descrizione" type="java.lang.String">
            <column name = "descrizione"></column>
        </property>
        <one-to-one name = "movimenti"  class = "persistence.beans.jCommesse.Movimento" constrained="true">

        </one-to-one>
        <joined-subclass name = "persistence.beans.jCommesse.Materiali" table = "Materiali">
            <key column="id"/>
            <property name = "consegnato" type="java.lang.Boolean">
                <column name = "consegnato"/>
            </property>
            <property name="costo" type = "java.lang.Double">
                <column name = "costo"/>
            </property>
            <property name = "costoTrasporto" type = "java.lang.Double">
                <column name = "costoTrasporto"/>
            </property>
            <property name = "quantita" type = "java.lang.Double">
                <column name = "quantita"/>
            </property>
            <property name = "riferimentoFattura" type = "java.lang.Integer">
                <column name = "riferimentoFattura"/>
            </property>
            <property name = "tipoQuantita" type = "java.lang.String">
                <column name = "tipoQuantita"/>
            </property>
        </joined-subclass>

        <joined-subclass name = "persistence.beans.jCommesse.RientroMateriali" table = "RientroMateriali">
            <key column="id"/>
            <property name = "costo" type = "java.lang.Double">
                <column name = "costo"/>
            </property>
            <property name = "costoDelTrasporto" type = "java.lang.Double">
                <column name = "costoDelTrasporto"/>
            </property>
            <property name = "quantita" type = "java.lang.Double">
                <column name = "quantita"/>
            </property>
            <property name = "riferimentoFattura" type = "java.lang.Integer">
                <column name = "riferimentoFattura"/>
            </property>
            <property name = "tipoQuantita" type = "java.lang.String">
                <column name = "tipoQuantita"/>
            </property>
        </joined-subclass>

        <joined-subclass name = "persistence.beans.jCommesse.CostiExtra" table = "CostiExtra">
            <key column = "id"/>
            <property name = "nota" type = "java.lang.String">
                <column name = "nota"/>
            </property>
            <property name = "prezzo" type = "java.lang.Double">
                <column name = "prezzo"/>
            </property>
        </joined-subclass>
    </class>
</hibernate-mapping>

and Movimenti.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 10-feb-2010 11.24.48 by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
    <class name="persistence.beans.jCommesse.Movimenti" table="movimenti" catalog="jcommesse">
        <id name="id" type="java.lang.Integer">
            <column name="id" />
            <generator class="identity" />
        </id>
        <property name="idCommessa" type="java.lang.Integer">
            <column name="idCommessa" />
        </property>
        <property name="nomemovimento" type="string">
            <column name="nomemovimento" length="250" />
        </property>


        <one-to-one name="preventivato" class="persistence.beans.jCommesse.Movimento" cascade="all" />



    </class>
</hibernate-mapping>

all this doesn't create the tables but instead comes out with this nasty exception:

    10-feb-2010 15.04.46 org.hibernate.tool.hbm2ddl.SchemaUpdate execute
INFO: schema update complete
Exception in thread "main" org.hibernate.PropertyValueException: not-null property references a null or transient value: persistence.beans.jCommesse.Materiali.movimenti
        at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
        at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:290)
        at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
        at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:187)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:172)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:94)
        at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
        at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:507)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:499)
        at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:495)
        at testgeneration.testSchema(testgeneration.java:34)
        at testgeneration.main(testgeneration.java:53)
Java Result: 1

as you can see it says "schema generation complete" (I'm using update for development).

Movimenti and Movimento come out like this on mySQL:

CREATE TABLE `movimenti` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `idCommessa` int(11) DEFAULT NULL,
  `nomemovimento` varchar(250) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

and

CREATE TABLE `movimento` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `descrizione` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FKBEB397FC4778E205` (`id`),
  CONSTRAINT `FKBEB397FC4778E205` FOREIGN KEY (`id`) REFERENCES `movimento` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=9 DEFAULT CHARSET=latin1

I've found a couple of issues:

  1. The exception is because of a bug in the use of the class Materiali (it also has a field movimenti that must be non-null but that's not related to your question and you're confused by it).

  2. In the mapping Movimenti.hbm.xml , you forgot to map the two fields preventivato and effettivo . You must map them with reverse=true .

  3. I really suggest to use annotations for the mapping. They are much more simple to use and keep all the information in one place.

  4. The reason why you don't see any references in the two tables is because Hibernate creates a many-to-many mapping (which needs a third table). I understand what you're trying to achieve but I'm not sure Hibernate is smart enough to do it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM