AldousA (4) [Avatar] Offline
#1
Intro

Hi I am trying to get to grips with Linq in VB and love the idea at compile time that I can see my mistakes before building and then things breaking.

I am doing some work trying to do Linq to SQL, I have a nice database DBML and things look great until... I try to do multiple aggregates of a selection of fields in a table. When I select a Group all the knowledge of its members somehow disappears!

I even looked at the examples in the source code and it suffers from the same problem... but this is not the case for the C# examples, they still know the members of the Group.

See the following book example for VB and C#.

VB:
Public Sub Aggregates_6_15()
Dim dataContext As New DataContext(My.Settings.liaConnectionString)

dataContext.Log = Console.Out

Dim books As Table(Of LinqInAction.Chapter06to08.Common.SampleClasses.Ch6.Book) = dataContext.GetTable(Of LinqInAction.Chapter06to08.Common.SampleClasses.Ch6.Book)()

Dim query = From book In books _
Group By key = book.SubjectId Into Group _
Select id = key, _
BookCount = Group.Count, _
TotalPrice = Group.Sum(Function(_book) _book.Price), _
LowPrice = Group.Min(Function(_book) _book.Price), _
HighPrice = Group.Max(Function(_book) _book.Price), _
AveragePrice = Group.Average(Function(_book) _book.Price)

ObjectDumper.Write(query, 1)
End Sub

C#
public void Aggregates_6_15()
{
DataContext dataContext =
new DataContext(Properties.Settings.Default.liaConnectionString);

dataContext.Log = Console.Out;

Table<LinqInAction.Chapter06to08.Common.SampleClasses.Ch6.Book> books = dataContext.GetTable<LinqInAction.Chapter06to08.Common.SampleClasses.Ch6.Book>();
var query =
from book in books
group book by book.SubjectId into groupedBooks
select new
{
groupedBooks.Key,
TotalPrice = groupedBooks.Sum(b => b.Price),
LowPrice = groupedBooks.Min(b => b.Price),
HighPrice = groupedBooks.Max(b => b.Price),
AveragePrice = groupedBooks.Average(b => b.Price)
};

ObjectDumper.Write(query, 1);

}

Continuation of thought
So if I in the VB example I look at the line

TotalPrice = Group.Sum(Function(_book) _book.Price)

I do not have any members of _book that are from class book, i.e. when I write _book. do not get the members, but if I know them it is fine as I can write them and it works.

On the other hand if I look at the same code in C#

TotalPrice = groupedBooks.Sum(b => b.Price)

Presto b. contains all the members of book. I thought at first it was the way group was defined so I changed the VB one to:

Group By key = book.SubjectId Into myGroup = Group

Then tried

TotalPrice = Group.Sum(Function(_book) _book.

but there were still no members

Please Help
So my question is why does it work in C# example and not the VB, is there something missing in the VB one so that the behaviour is the same, as the strength of Linq is meant to be having such functionality and it seems unfair that the VB programmer sits there guessing members (or in my case typing above the grouped line to see the member is spelt correctly then pasting it below).

Any help would be fantastic.

Thanks,
Anthony
fabrice.marguerie (224) [Avatar] Offline
#2
Re: Using multiple aggregates (Listing 6-15)
Hello Anthony,

I've tried this on my machine, and I do have the completion box showing up both in C# and VB for the case you describe.
After I type _book. in any of the Group.XXX calls, I do see the list of members.

Maybe there's a strange side effect in your code. Did you change the source code or is the unchanged source code from the zip file?
What version of VS are you using? I have Visual Studio 2008 version 9.0.30729.1 SP

Fabrice
AldousA (4) [Avatar] Offline
#3
Re: Using multiple aggregates (Listing 6-15)
Hi Fabrice

Thank you for looking at this, I appreciate having someone elses view.

I am currently working on VS Express Edition with SP1, from the about it says version 9.0.30729.1 SP.

With it being Express I did open the project in C# then take the object dumper code to compile a DLL. I then incorporated this into the VB version... but I did not think this made any difference.

After reading your response, just in case, I re-extracted the source from the zip again, freshly overwriting anything I may have done.

I opened a new instance of VB 2008 selected the Chapter06to08.VB.sln file, after getting the messages about the object dumper (blah blah) I then went to the CommonCodeSamplesCh6Samples.VB in the solution Explorer.

Scrolling to the Aggregates_6_15 sub I went to the following line

Group By key = book.SubjectId Into Group

and pressed the dot at this point :

Group By key = book.

and I got the list of fields in book; this is the same as before.

I then went to the line:

TotalPrice = Group.Sum(Function(_book) _book.Price)

and pressed the dot at this point:

TotalPrice = Group.Sum(Function(_book) _book.

and no longer do I have the members of book.

If I go to the C# version and look at the equivalent points in the code I get the members always.

It sounds like you have the full edition?

If so I think maybe it may be something to do with the Express Edition for VB then? I am currently waiting to get the full edition so perhaps this will solve the problem
fabrice.marguerie (224) [Avatar] Offline
#4
Re: Using multiple aggregates (Listing 6-15)
Yes I have the full edition (Visual Studio Team System). Maybe it makes a difference. In any case, it's definitely a bug in VS.

Fabrice
jwooley (123) [Avatar] Offline
#5
Re: Using multiple aggregates (Listing 6-15)
Ocassionally, I have seen VB have issues resolving the type for type inferencing. 1) Make sure you have Option Strict ON. Otherwise, this may be infering the type as Object. 2) See if you get a different behavior if you change your Lambda to specify the type as follows:

TotalPrice = Group.Sum(Function(_book As Book) _book.Price)

Let us know if either of these help with the issue.

Jim
AldousA (4) [Avatar] Offline
#6
Re: Using multiple aggregates (Listing 6-15)
Hi Jim

I checked and option strict is on.

I then tried to recast as you suggested

TotalPrice = Group.Sum(Function(_book As Book) _book.Price)

when I do _book. I get the members but VS complains "Overload Resolution failed because no accessible 'Sum' can be called with these arguments"!

I think it must be something to with the fact that C# type casts and it can't be changed once set but VB is flexible and so forgets? Maddening, feels like a second class citizen being a vb programmer.

Anthony

PS Someone on a different forum said that he had team suite and there was no problem and maybe as I was using Express that this was the problem. I have sice come home and checked on my Pro Version here and I still have the same problem. Anyone else try this and it worked for them?