Frans,

We try to keep the re-linq front-end as general as possible. The fact
that DefaultIfEmpty causes a GroupJoin to turn into a left-outer join
in your example is true, but it's not as simple generally speaking.
Consider the following slightly modified version of your query:

var q = from c in ctxt.Order
        join o in ctxt.Order on c.CustomerId equals
o.Customer.CustomerId
        into co // A
        from x in co.DefaultIfEmpty() //B
        from y in co //C
        select c;

Here, B uses the group join in a left-outer join fashion, but C uses
it in an ordinary cross join fashion. The simplification you suggested
(keeping A and flagging it as a left join) won't work here. And my
opinion is that if we can't apply it generally, we shouldn't apply it
at all. (As a predefined transformation in the re-linq front-end, that
is. Any LINQ provider can of course choose to build this
simplification if it helps.)

In addition, as Stefan said, DefaultIfEmpty can be applied to any
arbitrary sequence in a query, not only group joins. A LINQ provider
striving to support DefaultIfEmpty should try to find a solution that
works in all cases, no matter where the DefaultIfEmpty operator is
applied.

I've written a blog post about how I'd handle the DefaultIfEmpty query
operator in a SQL-translating LINQ provider here:
https://www.re-motion.org/blogs/mix/archive/2010/09/04/handling-the-defaultifempty-result-operator-in-a-re-linq-based-provider.aspx
. This describes more or less how we deal with DefaultIfEmpty in re-
linq's SQL backend, and I think you'll agree that with an approach
such as the one explained in the blog post, DefaultIfEmpty isn't any
longer difficult to implement.

Cheers,
Fabian

On Sep 4, 12:02 pm, "Frans Bouma" <[email protected]> wrote:
> > > from timeHeader in metaData.NonPresentTimeHeader where timeHeader.Id
> > > == 6 join time in metaData.NonPresentTime on timeHeader.Id equals
> > > time.HeaderId into timeJoin from joinedTime in
> > > timeJoin.DefaultIfEmpty() select joinedTime
>
> > > What might be a solution is to add a 'jointype' to the groupjoin class
> > > of re-linq and switch it to 'left join' when you handle the
> > > p=>DefaultIfEmpty() construct of a re-linq tree.
>
> > Hi Frans,
>
> > we could transform simple left-join-via-DefaultIfEmpty to left join
> clauses
> > in re-linq's QueryModel, but that would be a very simplistic solution that
> > could not support any but the most straightforward LINQ clauses. (i.e.
> only
> > those where someone implements left join as they found out via Google, but
> > for instance not any scenario where the query further references the
> > intermediate join clause (timeJoin in your sample).
>
>         A simple, stupid, but illustrative example: ('ctxt' is
> session.Linq... )
> var q = from c in ctxt.Order
>         join o in ctxt.Order on c.CustomerId equals o.Customer.CustomerId
> Into co // A
>         from x in co.DefaultIfEmpty() //B
>         select c;
>
> Lines A and B form a SelectMany, due to the from in B. At the left side,
> you'll have the group join in A and on the right side you have the right
> side of the group join in A.
>
> This can be transformed into keeping A, and using B to adjust the group
> join. The main advantage is that the group join contains the selectors and
> in C#'s case also the projection.
>
> So if re-linq could transform this into (pseudo code!)
> var q = from c in ctxt.Order
>         (left) join o in ctxt.Order on c.CustomerId equals
> o.Customer.CustomerId Into co            select c;
>
> it would be a big win. Big problem is the code which references the
> DefaultIfEmpty result as that has to be changed to references to the
> right-side of the join.
>
> It would help a lot, because it would make a join handler in a linq provider
> much easier, in fact, an existing join handler (which can handle the normal,
> 'join') would likely already work.
>
> > We think that DefaultIfEmpty is best solved in each back-end individually,
> > but of course nothing stops anyone from extending the front-end to create
> > that kind of QueryModel via an optional transformation step. Just be aware
> > that this only takes you so far, it would probably result in the LINQ
> > provider rejecting every use of DefaultIfEmtpy in joins that cannot be
> > reduced to that pattern.
>
>         You mean:
> var q = from c in ctxt.Order
>         from o in c.Orders.DefaultIfEmpty()
>         select c;
>
>         ?
>
>                 FB- Hide quoted text -
>
> - Show quoted text -

Reply via email to