28 votes

NHibernate Session.Flush () Envoi de requêtes de mise à jour lorsqu'aucune mise à jour ne s'est produite

J'ai un NHibernate session. Dans cette session, je m'exécute exactement 1 de l'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>();
}

Je suis appelant Session.Flush() à la fin de l' HttpRequest, et je reçois HibernateAdoException. NHibernate est de transmettre une instruction de mise à jour de la db, et entraînant une violation de clé étrangère. Si je n'ai pas exécuter l' flush, la demande se termine sans problème. Le problème ici est que j'ai besoin de la rincer en place dans le cas où il y a un changement qui se produit dans d'autres sessions, étant donné que ce code est réutilisé dans d'autres domaines. Est-il un autre paramètre de configuration je pourrais être absent?


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 pas affiché comme étant en cours de transmission.

43voto

zvolkov Points 9673

Toujours être prudent avec les valeurs null champs à chaque fois que vous faites affaire avec NHibernate. Si votre domaine est NULLable en DB, assurez-vous correspondant .NET utilise de type Nullable trop. Sinon, toutes sortes de choses étranges vont se produire. Le symptôme est généralement sera que NHibernate allons essayer de mettre à jour l'enregistrement dans la bd, même si vous n'avez pas modifié les champs puisque vous lisez l'entité de la base de données.

La séquence suivante explique pourquoi ce qui se passe:

  1. NHibernate extrait brut de l'entité de données de la DB à l'aide de ADO.NET
  2. NHibernate constructions de l'entité et définit ses propriétés
  3. Si la DB champ NULL, la propriété est définie à l'défaut de la valeur pour ses type:
    • propriétés de types de référence sera définie à null
    • propriétés des entiers et à virgule flottante types seront mis à 0
    • propriétés de type booléen sera définie sur false
    • propriétés de type DateTime sera la valeur DateTime.MinValue
    • etc.
  4. Maintenant, lorsque la transaction est validée, NHibernate compare la valeur de la propriété à l'origine une valeur de champ de lecture du formulaire de DB, et depuis le champ NULL, mais la propriété contient une valeur non nulle, NHibernate considère la propriété sale, et forcer la mise à jour de la enity.

Non seulement cela affecte les performances (vous obtenez supplémentaire de l'aller-retour dans la base de données et des mises à jour chaque fois que vous récupérez de l'entité), mais elle peut aussi entraîner dur pour résoudre les erreurs avec des colonnes DateTime. En effet, lorsque DateTime propriété est initialisée à sa valeur par défaut, il est mis à 1/1/0001. Lorsque cette valeur est enregistrée dans la base de données, ADO.NET's SqlClient ne pouvez pas convertir un valide SqlDateTime valeur depuis le plus petit possible SqlDateTime est 1/1/1753!!!

La meilleure solution est de faire la classe d'utilisation des biens de type Nullable, dans ce cas "DateTime?". Sinon, vous pouvez mettre en œuvre un type personnalisé mappeur par la mise en œuvre de IUserType avec sa méthode Equals correctement comparant DbNull.Valeur, quelle que soit la valeur par défaut de votre type de la valeur. Dans notre cas, est Égale aurait besoin de retourner la valeur true lorsque l'on compare les 1/1/0001 avec DbNull.De la valeur. Mise en œuvre d'un plein-fonctionnel IUserType n'est pas vraiment dur, mais il exige la connaissance de NHibernate trivia afin de préparer faire une bonne recherche sur google si vous choisissez d'aller de cette façon.

14voto

Ryan Duffield Points 7602

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

0voto

Richard Dingwall Points 1092

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X