web-dev-qa-db-fra.com

Comment mapper "insert = 'false' update = 'false'" sur une propriété-clé composite-id également utilisée dans un FK un-à-plusieurs?

Je travaille sur une base de code héritée avec un schéma de base de données existant. Le code existant utilise SQL et PL/SQL pour exécuter des requêtes sur la base de données. Nous avons été chargés de rendre agnostique une petite partie du projet, moteur de base de données (au début, tout changera éventuellement). Nous avons choisi d'utiliser les fichiers de mappage Hibernate 3.3.2.GA et "* .hbm.xml" (par opposition aux annotations). Malheureusement, il n'est pas possible de modifier le schéma existant car nous ne pouvons pas régresser les fonctionnalités héritées.

Le problème que je rencontre est lorsque je tente de mapper une relation unidirectionnelle, un-à-plusieurs où FK est également qui fait partie d'une PK composite. Voici les classes et le fichier de mapping ...

CompanyEntity.Java

public class CompanyEntity {
    private Integer id;
    private Set<CompanyNameEntity> names;
    ...
}

CompanyNameEntity.Java

public class CompanyNameEntity implements Serializable {
    private Integer id;
    private String languageId;
    private String name;
    ...
}

CompanyNameEntity.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-Orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

Ce code fonctionne très bien pour SELECT et INSERT d’une société avec des noms. J'ai rencontré un problème lorsque j'ai essayé de mettre à jour et l'enregistrement existant. J'ai reçu une exception BatchUpdateException et après avoir parcouru les journaux SQL, j'ai vu qu'Hibernate essayait de faire quelque chose stupid ...

update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?

Hibernate essayait de dissocier les enregistrements enfants avant de les mettre à jour. Le problème est que ce champ fait partie de la PK et n'est pas nullable. J'ai trouvé la solution rapide pour que Hibernate ne le fasse pas, c'est d'ajouter "not-null = 'true" "à l'élément" key "du mappage parent. SO maintenant peut mappage ressemble à ceci ...

CompanyNameEntity.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.jboss.org/dtd/hibernate/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="com.example">

    <class name="com.example.CompanyEntity" table="COMPANY">
        <id name="id" column="COMPANY_ID"/>
        <set name="names" table="COMPANY_NAME" cascade="all-delete-Orphan" fetch="join" batch-size="1" lazy="false">
            <key column="COMPANY_ID" not-null="true"/>
            <one-to-many entity-name="vendorName"/>
        </set>
    </class>

    <class entity-name="companyName" name="com.example.CompanyNameEntity" table="COMPANY_NAME">
        <composite-id>
            <key-property name="id" column="COMPANY_ID"/>
            <key-property name="languageId" column="LANGUAGE_ID"/>
        </composite-id>
        <property name="name" column="NAME" length="255"/>
    </class>

</hibernate-mapping>

Cette cartographie donne l'exception ...

org.hibernate.MappingException: Repeated column in mapping for entity: companyName column: COMPANY_ID (should be mapped with insert="false" update="false")

Mon problème maintenant est que j'ai essayé d'ajouter ces attributs à l'élément clé-propriété mais que cela n'est pas supporté par la DTD. J'ai également essayé de le changer en un élément clé-plusieurs-à-un, mais cela n'a pas fonctionné non plus. Alors...

Comment mapper "insert = 'false' update = 'false'" sur une propriété-clé composite-id également utilisée dans un FK un-à-plusieurs?

39
Jesse Webb

Je pense que l'annotation que vous recherchez est:

public class CompanyName implements Serializable {
//...
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", insertable = false, updatable = false)
private Company company;

Et vous devriez pouvoir utiliser des mappages similaires dans un fichier hbm.xml, comme indiqué ici (en 23.4.2):

http://docs.jboss.org/hibernate/core/3.3/reference/en/html/example-mappings.html

81
mcyalcin

"Dino TW" a fourni le lien vers le commentaire Exception de mappage Hibernate: colonne répétée dans le mappage pour l'entité qui contient les informations essentielles.

Le lien suggère de fournir "inverse = true" dans le mappage d'ensemble, je l'ai essayé et cela fonctionne réellement. C'est une situation rare dans laquelle un ensemble et une clé composite se rejoignent. Make inverse = true, on laisse l'insertion et la mise à jour de la table avec la clé Composite à prendre en charge par elle-même.

Ci-dessous peut être la cartographie requise, 

<class name="com.example.CompanyEntity" table="COMPANY">
    <id name="id" column="COMPANY_ID"/>
    <set name="names" inverse="true" table="COMPANY_NAME" cascade="all-delete-Orphan" fetch="join" batch-size="1" lazy="false">
        <key column="COMPANY_ID" not-null="true"/>
        <one-to-many entity-name="vendorName"/>
    </set>
</class>