Forum:  LLBLGen Pro Runtime Framework

Thread:  Group Join Problem

Rakes (User)   Posted on: 07-Aug-2019 02:42:24.
Same Linq query when written in VB.NET it is throwing "Unexpected expression type 'Unknown' found as source of DefaultIfEmpty(). Can't continue" exception in contrast to C# where it is working fine.


VB.NET (Not Working and throwing exception: Unexpected expression type 'Unknown' found as source of DefaultIfEmpty())

        Dim lnqQuery = New APHIM.Linq.LinqMetaData()
        Dim enumerable = (From ucs In lnqQuery.UnifiedCodeSet
                         Join domain In lnqQuery.V_Domain On ucs.Domain_ID Equals domain.ID
                         Group Join term In lnqQuery.TermDictionary On ucs.ID Equals term.TermCode_ID Into x = Group
                         From y In x.DefaultIfEmpty()
                         Where ucs.FullName = fullName AndAlso y.Name = termName
                         Select New With {.ID = ucs.ID})
        Dim result = enumerable.FirstOrDefault()

C#.NET (Working Fine)

            var lnqQuery = new APHIM.Linq.LinqMetaData();
            var enumerable = (from ucs in lnqQuery.UnifiedCodeSet
                             join domain in lnqQuery.V_Domain on ucs.Domain_ID equals domain.ID
                             join term in lnqQuery.TermDictionary on ucs.ID equals term.TermCode_ID into x
                             from y in x.DefaultIfEmpty()
                             where ucs.FullName==fullName && y.Name==termName
                             select new {ID = ucs.ID});
            var result = enumerable.FirstOrDefault();
daelmo (Support Team)   Posted on: 07-Aug-2019 08:09:16.
What LLBLGen version and runtime library version are you using? ( )

Any reason why you are using Group Join and not the normal Join?

Rakes (User)   Posted on: 07-Aug-2019 09:00:36.
I am using LLBLGenPro Version 5.4

Reason I wanted to have the Group join over the regular join because join to TermDictionary I need it to be left join.

Snippet I posted needs to be modified further.

The Query which I need to convert to Linq is as mentioned below:

SELECT TOP(@p2) [LPA_L1].[ID], [LPA_L1].[Code] FROM (([dbo].[UnifiedCodeSet] [LPA_L1]
INNER JOIN [dbo].[Domain] [LPA_L2] ON [LPA_L1].[domain_ID] = [LPA_L2].[ID])
LEFT JOIN [dbo].[TermDictionary] [LPA_L3] ON [LPA_L1].[ID] = [LPA_L3].[termCode_ID])
WHERE ( ( ( ( ( ( [LPA_L2].[Name] = @p3) AND ( ( [LPA_L3].[ID] = @p4) OR ( [LPA_L3].[active] = @p5)))))))
Otis (LLBLGen Pro Team)   Posted on: 07-Aug-2019 09:56:44.
We'll see why this happens. Might be the VB.NET compiler generates a different expression tree and therefore things go wrong. GroupJoin should work OK

Otis (LLBLGen Pro Team)   Posted on: 07-Aug-2019 10:23:47.
Well, the Expression trees are different (which is what the compilers generate and what the linq handler has to deal with): the GroupJoin in C#:

             <>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.c.ContactId,
             sc => sc.ContactId,
             (<>h__TransparentIdentifier0, csc) =>
                                    new <>f__AnonymousType1`2(<>h__TransparentIdentifier0 = <>h__TransparentIdentifier0, csc = csc))

and in VB.NET:

                $VB$It => $VB$It.c.ContactId,
                sc => sc.ContactId,
                ($VB$It, $VB$ItAnonymous) => new VB$AnonymousType_4`2($VB$It = $VB$It, x = $VB$ItAnonymous))

See the difference between csc=csc and x=$VB$ItAnonymous ? (property generated on the anonymous type has a name different from the argument)

Looking into it (as there should be code to deal with this)
Otis (LLBLGen Pro Team)   Posted on: 07-Aug-2019 11:25:45.
The main problem is indeed that in VB.NET, the target of the group join (whether you specify x=Group or just Group) is a member which name is unknown to the handler at this point: in VB.NET the value is passed on through an anonymous parameter in the lambda (as you can see above) and in C# it's passed on as a parameter with the same name.

Anonymous types at runtime get properties with the same name as mentioned in the constructor call. I have no idea why they do it this way, as e.g. in the SelectMany they do it OK. Dissapointed

Anyway, we have to add a visitor specifically for this to determine the name of the member a given parameter is assigned to in a constructor call of an anonymous type through a lambda, and this is specifically for this situation.

The VB.NET team did their users a huge disservice with their weird expression tree emitter as this mess is unnecessary (and it's not the only occasion things are specifically different for VB.NET only).

Otis (LLBLGen Pro Team)   Posted on: 07-Aug-2019 14:35:45.

See 5.4.7 hotfix build for the fix for 5.4. Also fixed in 5.5.4 hotfix.