NHibernate Session.Flush() Envoi de requêtes de mise à jour lorsqu'aucune mise à jour n'a eu lieu

StackOverflow https://stackoverflow.com/questions/34852

  •  09-06-2019
  •  | 
  •  

Question

J'ai une session NHibernate.Dans cette session, j'effectue exactement 1 opération, qui consiste à exécuter ce code pour obtenir une liste :

public IList<Customer> GetCustomerByFirstName(string customerFirstName)
{
return _session.CreateCriteria(typeof(Customer))
    .Add(new NHibernate.Expression.EqExpression("FirstName", customerFirstName))
    .List<Customer>();
}

j'appelle Session.Flush() à la fin de HttpRequest, et j'obtiens un HibernateAdoException.NHibernate transmet une instruction de mise à jour à la base de données et provoque une violation de clé étrangère.Si je ne lance pas le flush, la demande se termine sans problème.Le problème ici est que j'ai besoin du vidage en place au cas où un changement se produirait au cours d'autres sessions, car ce code est réutilisé dans d'autres domaines.Y a-t-il un autre paramètre de configuration qui pourrait me manquer ?


Voici le code de l'exception :

[SQL: UPDATE CUSTOMER SET first_name = ?, last_name = ?, strategy_code_1 = ?, strategy_code_2 = ?, strategy_code_3 = ?, dts_import = ?, account_cycle_code = ?, bucket = ?, collector_code = ?, days_delinquent_count = ?, external_status_code = ?, principal_balance_amount = ?, total_min_pay_due = ?, current_balance = ?, amount_delinquent = ?, current_min_pay_due = ?, bucket_1 = ?, bucket_2 = ?, bucket_3 = ?, bucket_4 = ?, bucket_5 = ?, bucket_6 = ?, bucket_7 = ? WHERE customer_account_id = ?]

Aucun paramètre n'est affiché comme étant transmis.

Était-ce utile?

La solution

J'ai déjà vu cela une fois lorsqu'un de mes modèles n'était pas mappé correctement (n'utilisait pas correctement les types nullables).Pouvez-vous s'il vous plaît coller votre modèle et votre cartographie ?

Autres conseils

Soyez toujours prudent avec les champs NULLable chaque fois que vous traitez avec NHibernate.Si votre champ est NULLable dans la base de données, assurez-vous que la classe .NET correspondante utilise également le type Nullable.Sinon, toutes sortes de choses étranges se produiront.Le symptôme est généralement que NHibernate essaiera de mettre à jour l'enregistrement dans la base de données, même si vous n'avez modifié aucun champ depuis que vous avez lu l'entité dans la base de données.

La séquence suivante explique pourquoi cela se produit :

  1. NHibernate récupère les données brutes de l'entité de la base de données à l'aide d'ADO.NET
  2. NHibernate construit l'entité et définit ses propriétés
  3. Si le champ DB contenait NULL, la propriété sera définie sur la valeur par défaut pour son type :
    • les propriétés des types de référence seront définies sur null
    • les propriétés des types entiers et à virgule flottante seront définies sur 0
    • les propriétés de type booléen seront définies sur false
    • les propriétés de type DateTime seront définies sur DateTime.MinValue
    • etc.
  4. Désormais, lorsque la transaction est validée, NHibernate compare la valeur de la propriété à la valeur du champ d'origine qu'elle a lue dans la base de données, et puisque le champ contenait NULL mais que la propriété contient une valeur non nulle, NHibernate considère la propriété comme sale et force une mise à jour de l'entité.

Non seulement cela nuit aux performances (vous obtenez un aller-retour supplémentaire vers la base de données et une mise à jour supplémentaire à chaque fois que vous récupérez l'entité), mais cela peut également rendre difficile la résolution des erreurs avec les colonnes DateTime.En effet, lorsque la propriété DateTime est initialisée à sa valeur par défaut, elle est définie sur 1/1/0001.Lorsque cette valeur est enregistrée dans la base de données, SqlClient d'ADO.NET ne peut pas la convertir en une valeur SqlDateTime valide puisque la plus petite valeur SqlDateTime possible est 1/1/1753 !!!

La solution la plus simple consiste à faire en sorte que la propriété de classe utilise le type Nullable, dans ce cas "DateTime?".Vous pouvez également implémenter un mappeur de type personnalisé en implémentant IUserType avec sa méthode Equals en comparant correctement DbNull.Value avec la valeur par défaut de votre type de valeur.Dans notre cas, Equals devrait renvoyer true lors de la comparaison de 1/1/0001 avec DbNull.Value.Implémenter un IUserType entièrement fonctionnel n'est pas vraiment si difficile, mais cela nécessite une connaissance des anecdotes de NHibernate, alors préparez-vous à faire des recherches approfondies sur Google si vous choisissez de suivre cette voie.

J'ai également rencontré ce problème dans NH 2.0.1 en essayant de masquer les extrémités inverses de plusieurs sacs à l'aide de access="noop" (indice :ça ne marche pas).

Les convertir en access="field" + ajouter un champ sur la classe a résolu le problème.Mais c'est assez difficile de les retrouver.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top