Hello -
I'd like to start development on that bug (which I suggested myself).
To recap, here is a (trivial consequence of the) problem in short
(this is from the source code in the attachment to NH-2583, which
would become a new unit test for NH):

The following 4 queries should all return the same result:

    var result = session.Query<MyBO>();

    var result = session.Query<MyBO>()
        .Where(bo => true);

    var result = session.Query<MyBO>()
        .Where(bo =>
                bo.BO1 != null && bo.BO1.I2 == 101
                || true);

    var result = session.Query<MyBO>()
        .Where(bo =>
                bo.BO1 != null && bo.BO1.I2 == 101
                || bo.Id == bo.Id + 0);

Actually, the latter two yield too small results. The reason is that
referenced classes are always joined via an inner join (or rather, a
"table" join). When there is a boolean or operator involved, such
joins must be replaced with left (outer) joins and some more logic.
For more details and a non-trivial example, see the NH-2583 JIRA
report.

So, now, I'd like to repair this - however, I'm not at all fluent in
the architecture+design of the Linq-->HqlTree generation machinery.
I'd appreciate if someone who knows that code could remotely pair with
me on this - or at least comment on my suggestions & attempts.

Here is my first suggestion where and how to repair this: In
AddLeftJoinsReWriter, add the following

        public override void VisitWhereClause(WhereClause whereClause,
QueryModel queryModel, int index) {
            base.VisitWhereClause(whereClause, queryModel, index);

            // 1. Collect all member expressions that are *above* an
boolean or operator.
            // These do not need new handling - they can be joined as
inner joins.
            ...

            // 2. Traverse all member expressions that are ONLY below
boolean or operators; and replace
            // the member access with a LeftJoin.
            // During this traversal, pull up the necessary PK checks
"just below" the boolean or operator -
            // this means that
            //      lhs -OR- rhs
            // is replaced with
            //      (lhs -AND- (AND of all paths and PK properties in
lhs: PK property IS NOT NULL)
            //      -OR
            //      (rhs -AND- (AND of all paths and PK properties in
rhs: PK property IS NOT NULL)
            ...

            // ??? 3. Replace all "table joins" with inner joins - at
least in SQL Server, mixing table joins
            // (the ones with , and an = in the where clause) and
outer joins can lead to nasty error messages
            // that names are not recognized (reason: each [comma-
separated] part of a from clause is sort of
            // separate name scope for joins).
            ...

        }

Of course, I'd have to convince you that the replacement of the
expressions as suggested in step 2. is
* necessary (isn't there a simpler way?); and
* sufficient (will all be ok afterwards?)
When we agree on this, I would appreciate a discussion and feedback on
* step 3. - I think it is necessary, but I'm not sure
* the placement of this code at all (e.g., should it be moved to a
separate ReWriter, because it muddles the code / responsibilites of
the current AddLeftJoinsReWriter?).

Many thanks and best regards!
Harald M.

Reply via email to