Come posso mappare "insert= 'false' update= 'false'" su una proprietà chiave con id composito che viene utilizzata anche in un FK uno-a-molti?
-
28-10-2019 - |
Domanda
Sto lavorando su una base di codice legacy con uno schema DB esistente. Il codice esistente utilizza SQL e PL / SQL per eseguire query sul DB. Ci è stato assegnato il compito di rendere una piccola parte del motore di database del progetto agnostico (all'inizio, cambiare tutto alla fine). Abbiamo scelto di utilizzare i file di mappatura Hibernate 3.3.2.GA e "* .hbm.xml" (al contrario delle annotazioni). Sfortunatamente, non è possibile modificare lo schema esistente perché non siamo in grado di regredire alle funzionalità precedenti.
Il problema che riscontro è quando cerco di mappare una relazione unidirezionale uno-a-molti in cui l'FK è anche parte di una PK composita. Ecco le classi e il file di mappatura ...
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>
Questo codice funziona perfettamente per SELECT e INSERT di una società con nomi. Ho riscontrato un problema quando ho provato ad aggiornare un record esistente. Ho ricevuto una BatchUpdateException e dopo aver esaminato i log SQL ho visto che Hibernate stava cercando di fare qualcosa di stupido ...
update COMPANY_NAME set COMPANY_ID=null where COMPANY_ID=?
Hibernate stava tentando di disassociare i record figlio prima di aggiornarli. Il problema è che questo campo fa parte della PK e non annulla i valori. Ho trovato che la soluzione rapida per impedire a Hibernate di farlo è aggiungere "not-null= 'true'" all'elemento "key" nella mappatura genitore. Quindi ora la mappatura potrebbe assomigliare a questa ...
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>
Questa mappatura fa l'eccezione ...
org.hibernate.MappingException: Repeated column in mapping for entity: companyName column: COMPANY_ID (should be mapped with insert="false" update="false")
Il mio problema ora è che ho provato ad aggiungere questi attributi all'elemento chiave-proprietà, ma non è supportato dal DTD. Ho anche provato a cambiarlo in un elemento chiave molti a uno, ma neanche quello ha funzionato. Quindi ...
Come posso mappare "insert= 'false' update= 'false'" su una proprietà chiave con id composto che viene utilizzata anche in un FK uno-a-molti?
Soluzione
Penso che l'annotazione che stai cercando sia:
public class CompanyName implements Serializable {
//...
@JoinColumn(name = "COMPANY_ID", referencedColumnName = "COMPANY_ID", insertable = false, updatable = false)
private Company company;
E dovresti essere in grado di usare mappature simili in un hbm.xml come mostrato qui (in 23.4.2):
http://docs.jboss.org / hibernate / core / 3.3 / reference / en / html / example-mappings.html
Altri suggerimenti
"Dino TW" ha fornito il collegamento al commento Eccezione mappatura ibernazione: colonna ripetuta nella mappatura dell'entità che contiene le informazioni vitali.
Il collegamento suggerisce di fornire "inverse= true" nella mappatura del set, l'ho provato e funziona davvero.È una situazione così rara in cui una chiave Set e Composite si uniscono.Rendi inverse= true, lasciamo che l'inserimento e l'aggiornamento della tabella con la chiave Composite si occupi da solo.
Di seguito può essere la mappatura richiesta,
<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>