J'ai créé un cas simple pour tester et je n'obtiens pas le comportement attendu. Je m'intéresse pourquoi hibernate choisit de mettre à jour la table parente (Country) bien que je fournisse l'attribut update = "false" à la relation many-to-one (dans le fichier Address.hbm.xml)?Pourquoi hibernate permet-il la mise à jour d'une table parent bien que update = "false" soit fourni à la relation many-to-one?
DDLS:
CREATE TABLE Country (
`id` smallint NOT NULL auto_increment,
`name` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) TYPE=InnoDB AUTO_INCREMENT=0;
CREATE TABLE Address (
`id` bigint NOT NULL auto_increment,
`firstName` varchar(100) NOT NULL,
`lastName` varchar(100) NOT NULL,
`countryId` smallint NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (countryId)
REFERENCES Country(id)
ON UPDATE CASCADE ON DELETE RESTRICT
) TYPE=InnoDB AUTO_INCREMENT=0;
Les xmls de mise en veille prolongée:
<class name="Country" table="Country" lazy="false">
<id name="id" column="id" type="integer">
<generator class="native" />
</id>
<property name="name" type="string" not-null="true" length="100"/>
</class>
<class name="Address" table="Address" >
<id name="id" column="id" type="long" unsaved-value="-1">
<generator class="native" />
</id>
<property name="addressFirstName" column="firstName" type="string" not-null="true" length="100"/>
<property name="addressLastName" column="lastName" type="string" not-null="true" length="100"/>
<!-- Country is parent table, Address is child table (holds the FK countryId).
From MySQL:
CASCADE: Update the row from the parent table and automatically update the matching rows in the child table.
RESTRICT: Rejects the delete operation for the parent table.
From hibernate:
1. cascade (optional): specifies which operations should be cascaded from the parent object to the associated object.
2. 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" association whose value is initialized
from another property that maps to the same column(s), or by a trigger or other application.
-->
<many-to-one name="country" class="Country" column="countryId"
not-null="true" cascade="persist,merge,save-update" update="false" />
<many-to-one name="state" class="State" column="stateId"
cascade="persist,merge,save-update" update="false" />
</class>
Ma table de pays a une ligne (id = 1):
INSERT INTO Country (name) VALUES ("United States");
Si je suit:
Country country = getCountryFrom("US");
Address address = new Address();
address.setAddressFirstName("Deksa");
address.setAddressLastName("Jakim");
country.setName("Slovenia");
address.setCountry(country);
address.setId(-1);
saveAddress(address);
session.saveOrUpdate(address);
Je m'attends à avoir une nouvelle ligne insérée dans la table Adresse, mais je reçois également une mise à jour sur la table Pays - la seule ligne, le nom du pays devient Slovénie, au lieu de rester aux États-Unis (comportement attendu < = update = "false"):
Hibernate: select country0_.id as id6_, country0_.name as name6_ from Country country0_ where country0_.stringId='US'
Hibernate: insert into Address (firstName, lastName, countryId) values (?, ?, ?)
Hibernate: update Country set name=? where id=?
Alors, pourquoi veille prolongée mettre à jour la table parent lorsqu'il reçoit des instructions de ne pas?
Cordialement,
Despot
Edit: Peu de temps après avoir écrit ce post, je compris que je confonds la cascade de la DB avec la cascade de la mise en veille prolongée et qui a résolu tous mes problèmes.
La chose est la suivante: Hibernate dit clairement:
update, insert (optionnel - par défaut true): spécifie que les cartographiés colonnes devraient être inclus dans SQL UPDATE et/ou INSERT. La définition de both à false permet une association "dérivée" pure dont la valeur est initialisée à partir d'une autre propriété que correspond à la ou aux mêmes colonnes, ou par un déclencheur ou une autre application.
. Cela signifie que lorsque vous utilisez update = "false" sur la propriété country (sur le countryId), je dis hibernate vous ne pouvez pas faire UPDATE Adresse SET firstName = "x", lastName = "y", countryId = 123 où condition; Seulement faire une mise à jour sans le countryId. Puis j'ai vu que la CASCADE ON UPDATE de la BD fait référence à la table parente (Country) - si le pays a été mis à jour, alors mettez à jour la table enfant (la colonne countryId dans la table Address). Contrairement à ce que je pensais que la mise à jour d'hibernate ferait, j'ai réalisé qu'en fournissant cascade = "save-update", je dis hibebernate, quelles que soient les valeurs de l'objet Country dans l'objet Address les mettent à jour dans sa propre table Country. Donc la solution était d'avoir cascade = "persister, fusionner" sans la partie save-update!
Je voulais interdire la mise à jour du pays (objet enfant), ne pas interdire un enfant propriété de l'objet. Dans votre cas, si j'ai une autre Classe (par exemple Continent), cela a le Pays comme objet enfant/membre, et si je voulais permettre à cette classe parente (Continent) de mettre à jour le Pays, ce ne serait pas possible. En d'autres termes, je pense que de cette façon, vous allez désactiver la mise à jour de la propriété du nom du pays de partout, ce qui n'est pas ce que je veux. En tout cas merci pour la réponse! – despot