2009-08-17 6 views
3

J'essaie d'écrire une requête NHibernate HQL qui utilise des parenthèses dans la clause where. Cependant, l'analyseur HQL semble ignorer ma parenthèse, changeant ainsi la signification de ma déclaration. Quelqu'un peut-il faire la lumière sur le sujet?Problème de logique NHibernate HQL

La requête HQL suivante:

from WebUser u left join fetch u.WebUserProfile left join fetch 
u.CommunicationPreferences where (u.CommunicationPreferences.Email = 0 and 
u.SyncDate is not null) or u.DateDeleted is not null 

se traduit par:

from WebUser webuser0_ 
left outer join WebUserProfile webuserpro1_ 
on webuser0_.UserId = webuserpro1_.WebUserId 
left outer join WebUserCommunicationPreferences communicat2_ 
on webuser0_.UserId = communicat2_.UserId 
where communicat2_.Email = 0 
and (webuser0_.SyncDate is not null) 
or webuser0_.DateDeleted is not null 

Merci

Jon

Répondre

0

La jointure gauche que vous spécifiez dans la clause, doit être respectée dans tous les critères de la clause where. Vous devez prendre soin du cas null spécial dans toutes les parties de la requête, c'est ainsi que fonctionne SQL (et HQL).

Référence: http://en.wikipedia.org/wiki/Null_(SQL)

lorsque vous écrivez u.CommunicationPreferences.Email = 0, les CommunicationPreferences doit être non nulle, ou la ligne de base de données ne seront pas sélectionnés.

Je vous conseille d'essayer les éléments suivants (l'adapter à votre cas):

from WebUser u 
    left join fetch u.WebUserProfile w 
    left join fetch u.CommunicationPreferences c 
where ((c.Email = 0 or c is null) 
     and u.SyncDate is not null) 
or u.DateDeleted is not null 

Extrait des HQL meilleures pratiques sur nos projets:

  • donnent des alias à toutes les tables atteint
  • pour chaque alias Nullable (w et c dans ce cas), toute contrainte (c.Email = 0) doit être corrigée avec le cas nul (or c is null)

Ajouté: Pour expliquer plus:

La deuxième jointure gauche signifie que vous souhaitez sélectionner un WebUser même s'il n'y a pas CommunicationPreferences correspondant. Ceci est incompatible avec une sélection comme u.CommunicationPreferences.Email, qui exclut toute correspondance si u.CommunicationPreferences est null (bien lu, je ne me réfère pas à la colonne Email).

Une telle incompatibilité peut provoquer des traductions étranges, où vous ne comprenez pas pourquoi le SQL a été créé ainsi ... Corrigez le HQL et réessayez :-) Les parenthèses peuvent devenir correctes.

+1

Merci KLE. Un peu plus d'informations, CommunicationPreferences.Email n'est jamais nul. Le problème est que les parenthèses ont été déplacées des deux premières conditions vers la condition intermédiaire, modifiant ainsi la sémantique de la requête – Jon

+1

Je parle de la nullabilité de c.Email, mais c lui-même. Il peut être nul parce que vous écrivez une jointure à gauche. Cela signifie: s'il n'y a pas de ligne correspondante, remplacez toutes les valeurs par null. Ceci est incompatible avec toute sélection sur c.Email, ce qui a pour effet de NE PAS sélectionner une ligne c qui proviendrait de la partie externe. En résumé, la jointure externe et la sélection supplémentaire sont incompatibles. – KLE

2

Je sais que c'est une réponse tardive, mais j'ai dû ajouter mes deux cents.

En SQL, l'opérateur et prend la précendence sur l'opérateur ou. Ainsi

(u.CommunicationPreferences.Email = 0 et u.SyncDate est non nulle) ou u.DateDeleted est non nulle

est le même que

communicat2_ .Email = 0 et (webuser0_.SyncDate n'est pas nul) ou webuser0_.DateDeleted n'est pas nulle