tags:

views:

669

answers:

2

Hi

I'm trying to write an NHibernate HQL query that makes use of parenthesis in the where clause. However, the HQL parser seems to be ignoring my parenthesis, thus changing the meaning of my statement. Can anyone shed any light on the matter?

The following HQL query:

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

translates to:

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

Thanks

Jon

A: 

The left join that you specify in the from clause, must be respected in all criterias in the where clause. You must take care of the special null case in all parts of the query, this is the way SQL (and HQL) works.

Reference : http://en.wikipedia.org/wiki/Null_(SQL)

when you write u.CommunicationPreferences.Email = 0, the CommunicationPreferences must be not null, or the database row will not be selected.

I suggest trying the following (adapt it to your own case) :

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

Extract from the HQL Best-practices on our projects :

  • give aliases to all tables reached
  • for each nullable alias (w and c in this case), any constraint (c.Email = 0) must be or-ed with the null case (or c is null)

Added: To explain more :

The second LEFT join means that you want to select a WebUser even if there is no CommunicationPreferences that match. This is incompatible with a selection like u.CommunicationPreferences.Email, that excludes any match if u.CommunicationPreferences is null (read well, I don't refer to the Email column).

Such an incompatibility may cause strange translations, where you don't understand why the SQL was created that way ... Fix the HQL and try again :-) The parenthesis may become correct.

KLE
Thanks KLE. A bit more info, CommunicationPreferences.Email is never null. The problem is that the parenthesis have been moved from around the first two conditions to around the middle condition, thus altering the semantics of the query
Jon
I'm talking about the nullability of c.Email, but c itself. It can be null because you write a left join. It means : if there is no corresponding row, replace all values with null. This is incompatible with any selection on c.Email, which has the effect of NOT selecting any c row that would come from the outer part. In short, outer join and further selection are incompatible.
KLE
+1  A: 

I know this is a late answer but I had to add my two cents.

In SQL the and operator takes precendence over the or operator. So

(u.CommunicationPreferences.Email = 0 and u.SyncDate is not null) or u.DateDeleted is not null

is the same as

communicat2_.Email = 0 and (webuser0_.SyncDate is not null) or webuser0_.DateDeleted is not null