Thoughts from Dan Miser RSS 2.0
# Friday, October 16, 2009
Given a collection of players that were constructed like this:

private static IList<Player> LoadPlayers()
{
	Player favre = new Player { Id = 1, Name = "Favre", Team = new Team { Id = 1, Name = "Vikings" } };
	Player peterson = new Player { Id = 2, Name = "Peterson", Team = new Team { Id = 1, Name = "Vikings" } };
	Player rodgers = new Player { Id = 3, Name = "Rodgers", Team = new Team { Id = 2, Name = "Packers" } };
	Player driver = new Player { Id = 4, Name = "Driver", Team = new Team { Id = 2, Name = "Packers" } };

	List<Player> players = new List<Player> {favre, peterson, rodgers, driver};
	return players;
}

And the following LINQ query:


var query = 
	from p in LoadPlayers()
	group p by p.Team into g
	select g;

We will see the following output:


Vikings
Vikings
Packers
Packers

The reason this is happening is that we created new Team objects for each and every Player, and when LINQ tries to group, it does so based on object equality. The solution to this is to override the Equals() and GetHashCode() methods in the Team class. After doing that, the LINQ query will be able to group the objects up properly and just display each team name once. Resharper has a nice code generation template to create solid implementations of these methods (press Alt+Ins to bring up the code generation menu).

The example here is obviously contrived. We could create each team object once, and then use the same instance during the property assignment, and if we did that, things would work just fine. However, I ran into a more generalized version of this problem when using WCF and a lot of custom code generation. The underlying lesson is still the same: LINQ and GroupBy need to have object equality defined properly in order to make things work as you would expect.

Friday, October 16, 2009 1:14:18 PM (Central Daylight Time, UTC-05:00)  #    Comments [2] -
.NET | LINQ
Friday, October 16, 2009 9:56:29 PM (Central Daylight Time, UTC-05:00)
Or use anonymous types, which already implement value equality.
Tuesday, October 20, 2009 10:55:45 AM (Central Daylight Time, UTC-05:00)
I wasn't aware of that, but it makes perfect sense. However, 2 things come to mind:
1. Obviously anonymous types can't be used across boundaries. You need to introduce named types at that point.
2. I couldn't get the sample to work when using
from p in LoadPlayers()
group p by p.Team into g
select new { g };

I assume you mean that you'd need to completely decompose the object and build it up property by propert in the anonymous case? (i.e. select new { Name = g.Key.Name }. But that doesn't work either. What am I missing?
Comments are closed.
Navigation
Archive
<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910
About the author/Disclaimer

Disclaimer
The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.

© Copyright 2012
Dan Miser
Sign In
Statistics
Total Posts: 375
This Year: 3
This Month: 0
This Week: 0
Comments: 654
Themes
Pick a theme:
All Content © 2012, Dan Miser
DasBlog theme 'Business' created by Christoph De Baene (delarou)