I think I found a bug!

Posts   
1  /  2  /  3
 
    
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 00:20:55   

I think I found a bug in the latest LLBLGenPro 2.6 Beta. Just made sure it happens with today's release as well.

The following Linq / C# code

public static IQueryable<OrderLogEntryEntity>
    LastOrderStateRelevantOrderLogEntries(DateTime ReportingDate) {

    var metaData = new LinqMetaData();

    var lastOrderStateRelevantOrderLogEntryIds = 
        from entries in metaData.OrderLogEntry
        where entries.EventDate <= ReportingDate &&
        entries.OrderEvent.OrderStateId != null
        group entries by entries.OrderId into g
        select new { LastEntryId = g.Max(d => d.Id) };

    var latestOrderLogEntries =
        from logEntries in metaData.OrderLogEntry
        join ids in lastOrderStateRelevantOrderLogEntryIds
        on logEntries.Id equals ids.LastEntryId
        select logEntries;

        return latestOrderLogEntries;
}

will result in the following sql being created for the latestOrderLogEntries query:

SELECT DISTINCT [LPA_L2].[Id],
                                [LPA_L2].[OrderId],
                                [LPA_L2].[OrderEventId],
                                [LPA_L2].[EventDate],
                                [LPA_L2].[UserId],
                                [LPA_L2].[UserIP] AS [UserIp],
                                [LPA_L2].[OrderErrorId],
                                [LPA_L2].[OrderErrorDescription]
FROM   ((SELECT [LPA_L3].[LPAV_]
                 FROM   (SELECT   [LPA_L5].[OrderId],
                                                    MAX([LPA_L5].[Id]) AS [LPAV_]
                                 FROM    ([KIS2008].[dbo].[OrderEvent] [LPA_L4]
                                                     INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L5]
                                                         ON [LPA_L4].[Id] = [LPA_L5].[OrderEventId])
                                 WHERE  (((([LPA_L5].[EventDate] <= @EventDate1)
                                                         AND ([LPA_L4].[OrderStateId] IS NOT NULL))))
                                 GROUP BY [LPA_L5].[OrderId]) LPA_L3) [LPA_L1]
                INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L2]
                    ON [LPA_L2].[Id] = [LPA_L1].[LastEntryId])
WHERE  (((([LPA_L2].[Id] = [LPA_L1].[LastEntryId]))))

Either the last line ON [LPA_L2].[Id] = [LPA_L1].[LastEntryId]) needs to be replaced with ON [LPA_L2].[Id] = [LPA_L1].[LPAV]) or all instances of [LPAV] have to be replaced with [LastEntryId].

Otherwise the query will fail with an "Invalid column name" exception.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 09:21:16   

Will look into it simple_smile

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 09:34:01   

Thank you Frans!

Apart from that bug your implementation of Linq is just cool! sunglasses

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 09:52:50   

kamiwa wrote:

Apart from that bug your implementation of Linq is just cool! sunglasses

Thanks! smile

Btw, I don't understand where the last 'where' comes from... it's not in your query... will try to repro it here.

(edit) When I try to reproduce it, I use this query:


LinqMetaData metaData = new LinqMetaData(adapter);

var q1 = from o in metaData.Order
         where o.OrderDate <= new DateTime(1997, 8, 1)
         && o.EmployeeId != null
         group o by o.CustomerId into g
         select new { LastId = g.Max(x => x.OrderId) };

var q = from o in metaData.Order
        join ids in q1
        on o.OrderId equals ids.LastId
        select o;

which IMHO comes down to the same query as you have. I run into a different issue: the select clause for q has the plain table name, not a reference to the alias, however I don't have the problem with the dangling where. Could you check again if you have copied the right query ?

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 11:59:10   

Sorry Frans,

you're right indeed. I had problems formatting the SQL in the forum editor. So I reformatted it in SQL Server Management Studio, copied and pasted again. Apparently something went wrong there. rage

The right query reads:

SELECT DISTINCT [KIS2008].[dbo].[OrderLogEntry].[Id],
                                [KIS2008].[dbo].[OrderLogEntry].[OrderId],
                                [KIS2008].[dbo].[OrderLogEntry].[OrderEventId],
                                [KIS2008].[dbo].[OrderLogEntry].[EventDate],
                                [KIS2008].[dbo].[OrderLogEntry].[UserId],
                                [KIS2008].[dbo].[OrderLogEntry].[UserIP] AS [UserIp],
                                [KIS2008].[dbo].[OrderLogEntry].[OrderErrorId],
                                [KIS2008].[dbo].[OrderLogEntry].[OrderErrorDescription]
FROM   ((SELECT [LPA_L3].[LPAV_]
                 FROM   (SELECT   [LPA_L5].[OrderId],
                                                    MAX([LPA_L5].[Id]) AS [LPAV_]
                                 FROM    ([KIS2008].[dbo].[OrderEvent] [LPA_L4]
                                                     INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L5]
                                                         ON [LPA_L4].[Id] = [LPA_L5].[OrderEventId])
                                 WHERE  (((([LPA_L5].[EventDate] <= @EventDate1)
                                                         AND ([LPA_L4].[OrderStateId] IS NOT NULL))))
                                 GROUP BY [LPA_L5].[OrderId]) LPA_L3) [LPA_L1]
                INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L2]
                    ON [LPA_L2].[Id] = [LPA_L1].[LastEntryId])

However, the issues remains. The last join operation still tries to join the non existent LastEntryId column.

BTW: The difference btw. your first LINQ query and mine is, that my query joins an additional OrderEvent table which it checks for the null values.

But basically: Yeah, your LINQ statement does the same than mine. simple_smile

EDIT: Corrected typo copy => copied!

EDIT2: Just found out why the query was different from yours!

Originally my 2nd LINQ statement was:


var latestOrderLogEntries =
                from logEntries in metaData.OrderLogEntry
                join ids in lastOrderStateRelevantOrderLogEntryIds
                on logEntries.Id equals ids.LastId
                where logEntries.Id == ids.LastId
                select logEntries;

This produced the following SQL:

SELECT DISTINCT [LPA_L2].[Id],
                                [LPA_L2].[OrderId],
                                [LPA_L2].[OrderEventId],
                                [LPA_L2].[EventDate],
                                [LPA_L2].[UserId],
                                [LPA_L2].[UserIP] AS [UserIp],
                                [LPA_L2].[OrderErrorId],
                                [LPA_L2].[OrderErrorDescription]
FROM   ((SELECT [LPA_L3].[LPAV_]
                 FROM   (SELECT   [LPA_L5].[OrderId],
                                                    MAX([LPA_L5].[Id]) AS [LPAV_]
                                 FROM    ([KIS2008].[dbo].[OrderEvent] [LPA_L4]
                                                     INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L5]
                                                         ON [LPA_L4].[Id] = [LPA_L5].[OrderEventId])
                                 WHERE  (((([LPA_L5].[EventDate] <= @EventDate1)
                                                         AND ([LPA_L4].[OrderStateId] IS NOT NULL))))
                                 GROUP BY [LPA_L5].[OrderId]) LPA_L3) [LPA_L1]
                INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L2]
                    ON [LPA_L2].[Id] = [LPA_L1].[LastId])
WHERE  (((([LPA_L2].[Id] = [LPA_L1].[LastId]))))

That's where the additionally WHERE comes from. Somehow I seem to have mixed the two versions, when trying to produce some readable SQL. Sorry again.

Anyway, the interesting thing is, that when you use the redundant WHERE clause, the main SELECT statement will correctly reference the ALIAS instead of the table name. Without it, the SELECT statement will reference the table name and additionally will have the naming conflict for the LastId column.

Seems sommin' is rotten in the state of Denmark. simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 12:53:41   

Heh simple_smile Thanks for the new query simple_smile

I found the issue. The code in the runtime which traverses the derived tables to see if there are fields targeting the derived table but aren't derived table targeting fields (see example below) are corrected. This 'correction' is a bit overreacting, as it can't express itself well enough and therefore the alias in the derived table targeting field (which pulls the MAX value) loses its alias of LastEntryId and is reset to its name LPAV_, which is of course wrong.

The routine which finds these fields, can find all fields in all elements, so also the filter fields.

Hopefully I have a fix in a few hours simple_smile

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 13:05:14   

That's what I call First Class Customer support! And that although it is a Beta version which is bound to have bugs!

Thank you so much Frans! I appreciate it!

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 13:34:10   

kamiwa wrote:

That's what I call First Class Customer support! And that although it is a Beta version which is bound to have bugs!

smile Well, I hate to have bugs in my code, and the more bugs there are in a current build of a beta, the less people are interested in keep testing it. simple_smile

I've fixed it btw. simple_smile

See attached files.

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 14:52:39   

Sorry Frans,

I can only give you 99 points out of 100. simple_smile

It sure fixed the original problem but it seems that it doesn't do it 100%!


public static IQueryable<StoreArticleWithOpenOrderAmountEntiy> StoreArticlesWithOpenOrderAmount(DateTime ReportingDate) {
    
    var metaData = new LinqMetaData();

    //Retries the Data from first sample. Working fine now!
    IQueryable<OrderLogEntryEntity> logs = LastOrderStateRelevantOrderLogEntries(ReportingDate);

    var orderlogs = from entries in logs
                                join events in metaData.OrderEvent
                                on entries.OrderEventId equals events.Id
                                join orderstates in metaData.OrderState
                                on events.OrderStateId equals orderstates.Id
                                where orderstates.Name == "Open" 
                                select entries;


    var items = from orderItems in metaData.OrderItem
                        join order in orderlogs 
                        on orderItems.OrderId equals order.OrderId
                        group orderItems by orderItems.StoreArticleId
                        into grp select new {
                        StoreArticleId = grp.Key,
                        OpenOrderAmount = grp.Sum(l => l.Amount)
        };

    return items.Cast<StoreArticleWithOpenOrderAmountEntiy>();
}

will now produce the following SQL:


SELECT [LPA_L1].[StoreArticleId],
             [LPA_L1].[LPAV_] AS [OpenOrderAmount]
FROM   (SELECT   [LPA_L4].[StoreArticleId],
                                 SUM([LPA_L3].[Amount]) AS [LPAV_]
                FROM     ((SELECT [LPA_L5].[Id],
                                                    [LPA_L5].[OrderId],
                                                    [LPA_L5].[OrderEventId],
                                                    [LPA_L5].[EventDate],
                                                    [LPA_L5].[UserId],
                                                    [LPA_L5].[UserIp],
                                                    [LPA_L5].[OrderErrorId],
                                                    [LPA_L5].[OrderErrorDescription]
                                     FROM   (((SELECT [LPA_L9].[Id],
                                                                        [LPA_L9].[OrderId],
                                                                        [LPA_L9].[OrderEventId],
                                                                        [LPA_L9].[EventDate],
                                                                        [LPA_L9].[UserId],
                                                                        [LPA_L9].[UserIP] AS [UserIp],
                                                                        [LPA_L9].[OrderErrorId],
                                                                        [LPA_L9].[OrderErrorDescription]
                                                         FROM   ((SELECT [LPA_L10].[LPAV_] AS [LastId]
                                                                            FROM   (SELECT   [LPA_L12].[OrderId],
                                                                                                             MAX([LPA_L12].[Id]) AS [LPAV_]
                                                                                            FROM     ([KIS2008].[dbo].[OrderEvent] [LPA_L11]
                                                                                                                INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L12]
                                                                                                                    ON [LPA_L11].[Id] = [LPA_L12].[OrderEventId])
                                                                                            WHERE   (((([LPA_L12].[EventDate] <= @EventDate1)
                                                                                                                    AND ([LPA_L11].[OrderStateId] IS NOT NULL))))
                                                                                            GROUP BY [LPA_L12].[OrderId]) [LPA_L10]) [LPA_L8]
                                                                         INNER JOIN [KIS2008].[dbo].[OrderLogEntry] [LPA_L9]
                                                                             ON [LPA_L9].[Id] = [LPA_L8].[LastId])
                                                         WHERE  ((([LPA_L9].[Id] = [LPA_L8].[LastId])))) [LPA_L5]
                                                        INNER JOIN [KIS2008].[dbo].[OrderEvent] [LPA_L6]
                                                            ON [LPA_L5].[OrderEventId] = [LPA_L6].[Id])
                                                     INNER JOIN [KIS2008].[dbo].[OrderState] [LPA_L7]
                                                         ON [LPA_L6].[OrderStateId] = [LPA_L7].[Id])
                                     WHERE  ((([LPA_L7].[Name] = @Name2)))) [LPA_L3]
                                    INNER JOIN [KIS2008].[dbo].[OrderItem] [LPA_L4]
                                        ON [LPA_L4].[OrderId] = [LPA_L3].[OrderId])
                GROUP BY [LPA_L4].[StoreArticleId]) [LPA_L1]

This time it's the Amount column which is undefined!

Well, I hate to have bugs in my code, and the more bugs there are in a current build of a beta, the less people are interested in keep testing it.

Guess we all hate those darn bugs in our code. But after all it reminds us that we all are only humans. Even those with a MVP award for C#. simple_smile Congratulations btw.

And ppl. using Beta versions, should be clearly aware that the purpose of them is bug squeezing.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 15:46:11   

kamiwa wrote:

Sorry Frans,

I can only give you 99 points out of 100. simple_smile

It sure fixed the original problem but it seems that it doesn't do it 100%!


public static IQueryable<StoreArticleWithOpenOrderAmountEntiy> StoreArticlesWithOpenOrderAmount(DateTime ReportingDate) {
    
    var metaData = new LinqMetaData();

    //Retries the Data from first sample. Working fine now!
    IQueryable<OrderLogEntryEntity> logs = LastOrderStateRelevantOrderLogEntries(ReportingDate);

    var orderlogs = from entries in logs
                                join events in metaData.OrderEvent
                                on entries.OrderEventId equals events.Id
                                join orderstates in metaData.OrderState
                                on events.OrderStateId equals orderstates.Id
                                where orderstates.Name == "Open" 
                                select entries;


    var items = from orderItems in metaData.OrderItem
                        join order in orderlogs 
                        on orderItems.OrderId equals order.OrderId
                        group orderItems by orderItems.StoreArticleId
                        into grp select new {
                        StoreArticleId = grp.Key,
                        OpenOrderAmount = grp.Sum(l => l.Amount)
        };

    return items.Cast<StoreArticleWithOpenOrderAmountEntiy>();
}

will now produce the following SQL: (snip)

This time it's the Amount column which is undefined!

Weird. The main thing is that 'Amount' should be a property of orderItem. Is that the case? If so, the alias is wrong: it then should be LPA_L4 instead of LPA_L3. I'll see if I can create a reproducing query

Well, I hate to have bugs in my code, and the more bugs there are in a current build of a beta, the less people are interested in keep testing it.

Guess we all hate those darn bugs in our code. But after all it reminds us that we all are only humans. Even those with a MVP award for C#. simple_smile Congratulations btw.

Thanks simple_smile

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 16:05:36   

Weird. The main thing is that 'Amount' should be a property of orderItem. Is that the case? If so, the alias is wrong: it then should be LPA_L4 instead of LPA_L3. I'll see if I can create a reproducing query

Confirmed. Amount is a property in OrderItem.

Amount gets summed as LPAV_ (SUM([LPA_L3].[Amount]) AS [LPAV_]) but appart from that it doesn't get selected at all. So it's neither a member of LPA_L3 nor LPA_L4. cry

Would it help if I attached a few CREATE TABLE statements? Might be easier to reproduce the bugs.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 16:57:20   

One of the things which goes wrong is that when you have joins with queries you already produced, you can have a join tree at the right side of the JOIN expression, and the code doesn't anticipate on that, as with normal queries like: var q = from c in metaData.Customer join o in metaData.Order on c.CustomerId equals o.CustomerId join od in metaData.OrderDetail on o.OrderId equals od.OrderId where c.Country=="Germany" select o;

the join tree is at the left side of the upper join expression. However a query with a dummy select (as the linq designers thought it would be 'great' to have a projection merged into the join statement disappointed ) gets its select removed by the compiler and the projection is merged into the join, so the query is just a 'join' statement. if that query is then used at the RIGHT side of another join (as you do), this goes wrong as that would effectively make the join have a join tree at the right side.

I think this is one of reasons the alias goes wrong (my repro query dies with no join available at all, so there's another issue I've to fix first)

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 17:34:32   

I managed to get my query running, and I indeed see that the SUM field is picked from the wrong side of the relation (from the query, while the field is in the entity joined). I'll dig deeper into this (as soon as I've fixed the dumb alias issue I have ran into as well... aliases... they're not my friends wink )

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 18:08:09   

I've been playing around with some more LINQ statements, and must say it's currently not all too obvious what LINQ expressions will work and which ones won't. Intellisense and compiler say it's fine but the resulting query still won't worked.

Had expected a bit more from LINQ. I still think that once you found out what works and what doesn't it'll proove to be pretty time saving and its awesome that it has been implemented into LLBLGen.

Having used SQL for so many years, a LINQ statement still seems to be more natural, than all the predicate, filter and order expressions you normally would have had to specify in your LLBLGen code to retrieve the data you want.

So just keep up the good work, and lets hope that Microsoft's implementation of LINQ doesn't become too powerful.

If you read Scott Gu's latest blog entry about the beta release of Visual Studio 2008 SP 1, it makes you wonder how much longer it will take till Microsoft has finally integrated all the great features that formerly where the domain of 3rd party add ons.

Regards,

Kai alias kamiwa simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 18:10:22   

GOT IT! smile

Maaan.. this was a deep one. The toughest things with debugging linq queries is that the tree is changed so many times and you've to track down teh root of a particular result in the tree. But it's fixed now.

I'll attach a tempbuild to this post. There are some small other issues left (see other threads) so expect some updates on this code wink

(edit) see attachment

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 18:12:21   

Will try it and keep you posted.

Thanks Frans.

kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 13-May-2008 19:03:40   

I'm now getting an error "Value mustn't be NULL. Parametername: key" from the second LINQ statement in the second sample.

Can't seem to find a way to access the SQL in this case.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 13-May-2008 19:18:18   

Hmm.

In that case I do need the table DDL SQL so I can setup the exact query as you have. Also explain if you have inheritance implemented on these tables / entities.

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 14-May-2008 10:55:01   

Ok, I've received your email. I get a different error though. I've commented out the for loops on the intermediate queries which don't do anything.

I do: var q = KIS2008.Data.Linq.DataRetrieval.StoreArticlesWithOpenOrderAmount(DateTime.Now);

(I don't have any data in the db, just your schema) and I get: Unhandled Exception: SD.LLBLGen.Pro.ORMSupportClasses.ORMQueryConstructionException: The property 'OrderEvent' isn't mapped to a field or database construct of entity type 'OrderLogEntryEntity'. Did you mean to call an extension method instead? ('Count' vs. 'Count()') ? at D.LLBLGen.Pro.LinqSupportClasses.LinqUtils.GetFieldObjectAndSetObjectAlias(IEntityCore entityInstance, String fieldName, SetAlias obj ectAlias) in C:\Myprojects\VS.NET Projects\LLBLGen Pro v2.0\LinqSupport\LinqSupportClasses .NET 3.5\LinqUtils.cs:line 383

which is a similar error as this thread: http://www.llblgen.com/tinyforum/Messages.aspx?ThreadID=13327

When I enable the for loops, I get the error you reported. Will look into both simple_smile (though the for loops shouldn't be necessary, in fact you shouldn't use these, as you're re-using a query.)

Frans Bouma | Lead developer LLBLGen Pro
Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 14-May-2008 11:15:33   

The main problem I run into now is that the cast you specify is seen as part of the query, which means that the cast has to be done by our framework. As the type to cast to isn't an entity, it simply returns the complete expression, which isn't good either.

When I change the query to return an IQueryable instead (so not strongly typed), it ends up in the key is null error. If you want to have it strongly typed, you should write the last projection in StoreArticlesWithOpenOrderAmount as:


select new StoreArticleWithOpenOrderAmountEntiy {
    StoreArticleId = grp.Key,
    OpenOrderAmount = grp.Sum(l => l.Amount)
};

Looking into preventing this cast misuse and also to solve the key==null issue.

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 14-May-2008 11:20:28   

Otis wrote:

I get: Unhandled Exception: SD.LLBLGen.Pro.ORMSupportClasses.ORMQueryConstructionException: The property 'OrderEvent' isn't mapped to a field or database construct of entity type 'OrderLogEntryEntity'. Did you mean to call an extension method instead? ('Count' vs. 'Count()') ?

Yeah, I ran into that one as well!

When I enable the for loops, I get the error you reported. Will look into both simple_smile (though the for loops shouldn't be necessary, in fact you shouldn't use these, as you're re-using a query.)

No, the loops aren't necessary. I just used them for debugging purpose.

kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 14-May-2008 11:28:48   

Otis wrote:

The main problem I run into now is that the cast you specify is seen as part of the query, which means that the cast has to be done by our framework. As the type to cast to isn't an entity, it simply returns the complete expression, which isn't good either.

It seems that in general the whole casting thing isn't a good idea at all! You always should return etities from your LINQ statements.

This has been discussed in Rick Strahl's Web Log as well and seems to be a problem which is LINQ specific and not LLBLGen related.

If you got time for it, take a look at these two blog entries and the user comments:

http://www.west-wind.com/weblog/posts/33570.aspx http://www.west-wind.com/weblog/posts/143814.aspx

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 14-May-2008 11:58:50   

I'll now throw an exception if a cast like the one in your code is encountered, as there's no other way to handle it.

The error with the null type is caused by the fact that the left side of the join is a query but it's seen as a normal join. This will result in the left side ending up like a set of relations without a projection. However the on clause refers to the whole left side as its source, and with just a bunch of relations that's not possible, as it has to refer to the REAL table inside the left side, which is impossible, as it's a full query (black box). The solution is to detect if its a full query and then simply set a flag which will make sure it ends up as a query. You can work around this now by switching left and right in the orderlogs query. So instead of having 'logs' at the left side, place it on the right side of the join. This works as the code assumes that if a join ends up at the right side it's always a query.

I'll add proper code which makes it work regardless where the query is placed, left or right.

kamiwa wrote:

Otis wrote:

The main problem I run into now is that the cast you specify is seen as part of the query, which means that the cast has to be done by our framework. As the type to cast to isn't an entity, it simply returns the complete expression, which isn't good either.

It seems that in general the whole casting thing isn't a good idea at all! You always should return etities from your LINQ statements. This has been discussed in Rick Strahl's Web Log as well and seems to be a problem which is LINQ specific and not LLBLGen related.

The cast statement you specified would, if it would be executed as the IEnumerable<U>.Cast<T>(), be running over the resultset, cast every element to T into a new IEnumerable<T>. so basicly would do: foreach(U u in source) { yield return (T)u; }

Not something you'd do normally. 'Cast' is indeed a weird statement. I also had some problems with it in the provider, as well as with the 'as' keyword, as they simply can't be converted to the target platform (SQL) so the behavior they SHOULD show isn't there..

If you got time for it, take a look at these two blog entries and the user comments: http://www.west-wind.com/weblog/posts/33570.aspx http://www.west-wind.com/weblog/posts/143814.aspx

Thanks for the links. Yes I agree with Rick on this (but that's not hard, Rick is mostly right on many things wink )

Frans Bouma | Lead developer LLBLGen Pro
kamiwa avatar
kamiwa
User
Posts: 164
Joined: 12-Jun-2007
# Posted on: 14-May-2008 12:05:32   

OK. Thanks again. simple_smile

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39588
Joined: 17-Aug-2003
# Posted on: 14-May-2008 12:50:50   

Fixed it. See attached assembly.

Frans Bouma | Lead developer LLBLGen Pro
1  /  2  /  3