Going back to something I finally started messing around with over the weekend... LINQ.
I love it.
One of the first things I wrote a few years ago when starting to work with XML programmatically was an application that dealt with my iTunes library and loading it into a database (good way to learn, basically). When I first started with XML Serialization, I retooled that app to fit that purpose. Now I've retooled it yet again to work with LINQ (among other changes).
Code snippets below. To set this up, this code is after the XML portion of the program has ended and before any data changes are applied to the database; this is the part that determines what to change. There is a MusicTrack class that contains information about each track in the database or iTunes library. I've also defined a PlayHistory class that is a transactional history of when a given track is played. For the code featured, there are three generic lists of MusicTrack classes (one from the iTunes library file, one from the database, and one that will be built based on what tracks have been added/modified), and one generic list of PlayHistory classes that will be created based on the MusicTrack activity.
Old:
foreach (MusicTrack tempTrack in tempTracks)
{
bool bFound = false;
bool bChanged = false;
foreach (MusicTrack mainTrack in mainTracks)
{
if (tempTrack.PersistentID == mainTrack.PersistentID)
{
bFound = true;
if (tempTrack.PlayDateTime > mainTrack.PlayDateTime
|| tempTrack.PlayCount != mainTrack.PlayCount)
{
if (tempTrack.PlayCount > mainTrack.PlayCount)
{
PlayHistory playHistory = new PlayHistory();
playHistory.PersistentID = mainTrack.PersistentID;
playHistory.DatePlayed = tempTrack.PlayDateTime;
playHistory.TimesPlayed = tempTrack.PlayCount
- mainTrack.PlayCount;
playHistories.Add(playHistory);
}
UpdateTrack(tempTrack, mainTrack);
bChanged = true;
}
//mainTracks.Remove(mainTrack); // don't need this one anymore
}
}
if (!bFound) // new track
{
MusicTrack musicTrack = new MusicTrack();
UpdateTrack(tempTrack, musicTrack);
bChanged = true;
if (tempTrack.PlayCount > 0)
{
PlayHistory playHistory = new PlayHistory();
playHistory.PersistentID = tempTrack.PersistentID;
playHistory.DatePlayed = tempTrack.PlayDateTime;
playHistory.TimesPlayed = tempTrack.PlayCount;
playHistories.Add(playHistory);
}
}
if (bChanged)
alteredTracks.Add(tempTrack);
}
Above, there are two foreach loops iterating through the library and database track listings and comparing them to one other, trying to find updated or new tracks. If different or new, the DB record is synchronized with the library record (will be saved later in the code) and a PlayHistory instance is established.
In the new code below, I've switched it up to use LINQ. There is a new class, TrackUpdate, that simply contains the matched MusicTrack objects.
New:
var query = from tempTrack in tempTracks
join mainTrack in mainTracks
on tempTrack.PersistentID equals mainTrack.PersistentID
into gj // groupjoin
from submain in gj.DefaultIfEmpty()
select new TrackUpdate
{
Track = tempTrack,
DBTrack = submain // can be null
};
foreach (TrackUpdate trackUpdate in query)
{
if (trackUpdate.DBTrack == null)
{
trackUpdate.Track.AutoID = 0;
alteredTracks.Add(trackUpdate.Track);
PlayHistory ph = new PlayHistory();
ph.PersistentID = trackUpdate.Track.PersistentID;
ph.DatePlayed = trackUpdate.Track.PlayDateTime;
ph.TimesPlayed = trackUpdate.Track.PlayCount;
playHistories.Add(ph);
}
else if (trackUpdate.Track.PlayDateTime > trackUpdate.DBTrack.PlayDateTime
|| trackUpdate.Track.PlayCount != trackUpdate.DBTrack.PlayCount)
{
trackUpdate.Track.AutoID = trackUpdate.DBTrack.AutoID;
alteredTracks.Add(trackUpdate.Track);
if (trackUpdate.Track.PlayCount > trackUpdate.DBTrack.PlayCount)
{
PlayHistory ph = new PlayHistory();
ph.PersistentID = trackUpdate.Track.PersistentID;
ph.DatePlayed = trackUpdate.Track.PlayDateTime;
ph.TimesPlayed = trackUpdate.Track.PlayCount - trackUpdate.DBTrack.PlayCount;
playHistories.Add(ph);
}
}
}
With LINQ, I no longer need that nested foreach loop to match these tracks up, I can do it with a LINQ join and can even include an outer join so I can get unmatched (read: new) records from the iTunes library file.
I heart LINQ.

Since I didn't have much to do at work today, I went through a recent project I've been working on and added some LINQ hotness to it pro bono (the old code worked, after all).