NHibernate ne lance pas d’exception StaleObjectStateException lorsque < Version > utilisé et données modifiées dans la base de données
-
22-07-2019 - |
Question
Une entité mappée dans NHibernate avec un contrôle d'accès concurrentiel optimiste utilise une colonne d'horodatage SQL comme numéro de version. Le mappage est le suivant:
<class name="Entity" optimistic-lock="version" discriminator-value="0">
<id name="id">
<generator class="native" />
</id>
<version name="Version" column="Version" generated="always" unsaved-value="null" type="System.Byte[], mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
...
<subclass name="ChildEntity" discriminator-value="1" />
</class>
Je teste ce qui se passe lorsque les données d’une ligne de la base de données changent entre l’obtention et la mise à jour de l’enregistrement. Pour ce faire, j'exécute une instruction update directement sur l'un des enregistrements de la table en cours de mise à jour par NHibernate. Cette mise à jour directe modifie le numéro de version de l'enregistrement dans la table.
Comme prévu, la mise à jour gérée de NHibernate ne se produit pas sur la ligne en question (ce qui est une bonne chose). Cependant, aucune exception n'est levée lors de la validation. Je m'attendais à ce qu'une exception StaleObjectStateException se produise lors de la validation de la transaction afin de pouvoir l'annuler et d'informer l'utilisateur. N'est-ce pas le comportement attendu? Est-ce que je manque quelque chose?
Mon code pour valider la transaction ressemble à ceci:
_session.BeginTransaction();
...
// load objects in session
IList<ChildEntity> toChange = _session.Find('some condition');
foreach ( var itemToChange in toChange )
{
itemToChange.Status = Status.Updated;
}
...
_session.Transaction.Commit();
Les éléments appartiennent à la même session et tout le travail est terminé au sein d'une seule transaction. ChildEntity est une sous-classe de la classe de base Entity, pour laquelle le verrou optimiste est défini sur la version.
La solution 2
Il semble que mes tests étaient inexacts. Lors du test, je faisais le get APRÈS que l’autre transaction mette à jour l’enregistrement. Cette autre mise à jour a rendu la ligne inadmissible à la mise à jour. Aucune mise à jour n'a donc été tentée. Lorsque j'ai modifié le test pour effectuer la mise à jour concurrente APRÈS la commande Get, l'exception StaleObjectStateException a été levée comme prévu.
Désolé pour la confusion.
Autres conseils
Comment modifiez-vous les données? L'exception StaleObjectException est levée uniquement lorsque NHibernate tente de mettre à jour la ligne et que le numéro de version n'est plus le même. Les autres colonnes ne sont pas pertinentes. Est-il possible que lors de vos tests, vous ne mettiez pas à jour le numéro de version?
La prémisse est la suivante:
A. Utilisateur A & amp; B obtenir un objet de la base de données avec la version = 1
SQL: SELECT [objet] FROM [TABLE] où id = [id] et Version = 1
B. Utilisateur Un objet de mise à jour qui modifie la version en 2
SQL: UPDATE [TABLE] SET [objet] (& Set Version = 2) où id = [id] et Version = 1
renvoie 1 ligne mise à jour
C. L’utilisateur B tente de mettre à jour l’objet mais obtient une exception StaleObjectException en tant qu’objet update avec version = 1 (la version qu’il a obtenue étape 1) met à jour 0 enregistrements dans la base de données.
SQL: UPDATE [TABLE] SET [objet] où id = [id] et Version = 1
renvoie 0 ligne mise à jour et une exception StaleObjectException levée.