Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linq does not group in VB.Net

For educational purposes I tried to convert the following Linq expression from the book "Linq in action" into VB.net

Original C#

var list = 
  from book in SampleData.Books
  group book by new { book.Publisher.Name, book.Subject }
    into grouping
  select new {
    Publisher = grouping.Key.Publisher,
    Subject = grouping.Key.Subject,
    Book = grouping
  };

My attempt:

Dim list = _books.GroupBy(Function(book) New With {.Publisher = book.Publisher.Name,
                                                    book.Subject}).
                  Select(Function(grouping) New With {.Publisher = grouping.Key.Publisher,
                                                      .Subject = grouping.Key.Subject,
                                                      .Books = grouping})

For Each item In list
  Console.WriteLine("Publisher:" & item.Publisher & ", Subject:" & item.Subject)
  For Each Book In item.Books
    Console.WriteLine("  " & Book.Title)
  Next
Next

This leads to the following output:

Publisher:FunBooks, Subject:Fun  
  Funny Stories  
Publisher:Joe Publishing, Subject:Work  
  LINQ rules  
Publisher:Joe Publishing, Subject:Work  
  C# on rails  
Publisher:Joe Publishing, Subject:Fun  
  All your base are belong to us  
Publisher:FunBooks, Subject:Fun  
  Bonjour mon Amour  

I expected, that the books "LINQ rules" and "C# on rails" are grouped as well as the books "Funny Stories" and "Bonjour mon Amour" because they have the same Publisher and Subject. My anonymous key consists a new object of two simple strings.

I already tried to search in SO, but other (or) answers do not solve my problem. Even some code translators like telerik or carlosag are no help in this case.

like image 455
Markus Avatar asked Oct 26 '11 06:10

Markus


2 Answers

This is the problem:

GroupBy(Function(book) New With {.Publisher = book.Publisher.Name,
                                  book.Subject})

That's not equivalent to the C# version, because unfortunately VB uses mutable properties in anonymous types by default, and mutable properties aren't considered as part of the hash code or equality operations. You need to make both properties "Key" properties:

GroupBy(Function(book) New With {Key .Publisher = book.Publisher.Name,
                                 Key book.Subject})

Then it should work fine. You can read more about anonymous types in VB on MSDN.

like image 110
Jon Skeet Avatar answered Nov 04 '22 02:11

Jon Skeet


While I applaud your efforts to translate the samples, we actually have all of the samples for LINQ in Action in C# and VB available for download from the Manning Site: http://www.manning.com/marguerie/. Also, we have added samples to the LinqPad samples to make it easy to try the samples and save your changes. See http://www.thinqlinq.com/Default/LINQ-In-Action-Samples-available-in-LINQPad.aspx for instructions on how to access that.

It appears that you are working on example 5.06b. Updating it slightly, our VB translation is:

Dim query = _
  From book In SampleData.Books _
  Group book.Title By book.Publisher, book.Subject Into grouping = Group _
  Select _
    Publisher = Publisher.Name, _
    Subject = Subject.Name, _
    Titles = grouping 

If you want to use the Lambda syntax, you do need to specify the Key as @johnskeet indicated:

Dim list = SampleData.Books.GroupBy(Function(book) New With { 
                          Key .Publisher = book.Publisher.Name, 
                          Key .Subject = book.Subject}). 
               Select(Function(grouping) New With {
                  .Publisher = grouping.Key.Publisher, 
                  .Subject = grouping.Key.Subject, 
                  .Books = grouping}) 
like image 40
Jim Wooley Avatar answered Nov 04 '22 01:11

Jim Wooley