Dot Net Thoughts

December 9, 2007

The Linq Jukebox

Filed under: csharp — dotnetthoughts @ 8:18 am
Tags: , , ,

Earlier this week, the Portland Area Dot Net Users’ Group had an installation party for Visual Studio 2008. During the event, they had a contest to see who could come up with the best LINQ sample. The winner would receive a customized Zune. While I had not yet used LINQ, I decided to throw my hat in the ring with the following query:

     var query = from ZuneWinner in db.PeopleInRoom 
     where ZuneWinner.FirstName == "Michael" and   
     ZuneWinner.LastName=="Weier" 
     select new {ZuneWinner.FirstName, ZuneWinner.LastName};

As you’ve probably already guessed, I didn’t leave with the fancy new piece of hardware. I did receive a chuckle from the judge, though.

After everything had ended, I came up with an idea that may have been a serious contender. A cool entry would have been to try and model an mp3 player’s functionality using LINQ. I decided to create a program that would rip through the music structure on my PC and display the results by artist, album and track.

On my laptop, I have an ITunes folder. (Can you say ITunes on an essentially Microsoft blog?) This folder arranges music into three different levels. The topmost folder contains one folder for each artist I have music for on my PC. Each artist folders contains one folder for each album I have by this artist. The artist folder, in turn, contains a list of tracks that I have available to play on my pc.

LinqFolders

My ultimate goal is to take this hierarchical structure and flatten it into a listbox view similar to the following:

LinqListbox

Traditional (pre-LINQ) programming would have achieved this through a simple nested-loop construct. Starting at the top level folder, loop through the subfolders populating the ListBox’s ListItems as you go.

 
        private void LoadMusicData2() 
        { 
            string musicFolder = @"C:\Users\Mike\Music\iTunes\iTunes Music"; 
            DirectoryInfo topDirectory = new DirectoryInfo(musicFolder); 
            foreach (DirectoryInfo artistDirectory in topDirectory.GetDirectories()) 
            { 
                foreach (DirectoryInfo albumDirectory in artistDirectory.GetDirectories()) 
                { 
                    foreach (FileInfo trackFile in albumDirectory.GetFiles("*.mp3", 
                        SearchOption.TopDirectoryOnly)) 
                    { 
                        AddListViewItem(artistDirectory.Name, albumDirectory.Name, 
                            Path.GetFileNameWithoutExtension(trackFile.ToString()), trackFile.FullName); 
                    } 
                } 
            } 
        } 

This method works well enough, but LINQ gives us a much more elegant solution. In the above code, we have three different objects. The first object maintains artist directories, the second maintains album directories, and the third maintains track information. By using LINQ, we can create an anonymous type which will hold only the pieces of data we are interested in dealing with. The following method is the LINQ equivalent to the above code.

 
        private void LoadMusicData() 
        { 
            string musicFolder = @"C:\Users\Mike\Music\iTunes\iTunes Music"; 
            DirectoryInfo topDirectory = new DirectoryInfo(musicFolder); 
            var query = 
                from artistDirectory in topDirectory.GetDirectories() 
                from albumDirectory in artistDirectory.GetDirectories() 
                from file in albumDirectory.GetFiles("*.mp3", SearchOption.TopDirectoryOnly) 
                select new { Track = Path.GetFileNameWithoutExtension(file.Name), 
                                  Album = albumDirectory.Name, 
                                  Artist = artistDirectory.Name, 
                                  TrackFile = file.FullName};        

            foreach (var trackData in query) 
            { 
                AddListViewItem(trackData.Artist, trackData.Album, trackData.Track, trackData.TrackFile); 
            }         
        } 

The from statements in this query retrieves data from each of the individual folders and merges them into a flattened hierarchy. The select statement then creates a new anonymous type which contains four properties: Track, Album, Artist, and TrackFile. Not only has the data been reduced to only the data we care about, it has been renamed to make more sense for our application. Finally, we loop through the data returned in the query, adding the values into the ListView.

So, really, what is so amazing? Is the second method really that much better than the first?

What I really think will set LINQ apart is the fact that it is platform agnostic when it comes to querying data. The same syntax can be used to query databases, objects, and Xml. Furthermore, one is able to extract and merge exactly what one needs from these different types and combine them into specialized types on the fly. Sorting and filtering data in LINQ is very simple. Want to see only music by the Big Horn Brass with the tracks in descending order? No problem.

 
            var query = 
                from artistDirectory in topDirectory.GetDirectories() 
                from albumDirectory in artistDirectory.GetDirectories() 
                from file in albumDirectory.GetFiles("*.mp3", SearchOption.TopDirectoryOnly) 
                where artistDirectory.Name == "The Big Horn Brass" 
                orderby file.Name descending 
                select new { Track = Path.GetFileNameWithoutExtension(file.Name), 
                                  Album = albumDirectory.Name, 
                                  Artist = artistDirectory.Name, 
                                  TrackFile = file.FullName}; 

The biggest drawback I see at the moment is the syntax for non-trivial queries. I’d originally wanted to merge in some Xml comments to a couple of tracks using the equivalent of a LEFT OUTER JOIN, but never quite got it to work right. The syntax for Xml seems to be entirely new and is not immediately intuitive to someone who has used the old model. (Granted, I’ve probably played with LINQ a total of three hours, now, so I can’t complain too much.) I’ve picked up a LINQ book, and will work to figure that one out. I suspect that the syntax will become easier with time and practice.

Is the demo worth a free Zune? Well, if anybody at Microsoft feel so, let me know <grin>.

That’s pretty much it for today.

Code Safe!

MW

Advertisements

5 Comments »

  1. You really have a ‘Mannheim Steamroller’ album?

    (seriously, this is cool)…

    Comment by Lewis — December 21, 2007 @ 6:38 pm | Reply

  2. Lewis–

    Yup. I sure do. I lived in Omaha, Nebraska (home of Mannheim Steamroller) through the 80s and 90s when they were at their peak. We’ve seen their Christmas concerts a couple of times, and they’re a lot of fun. I used to have a copy of Fresh Aire VI signed by Chip Davis, but I have no idea what happened to it over the years.

    Hope you enjoy the postings. Thanks for the comment!

    MW

    Comment by dotnetthoughts — December 21, 2007 @ 9:37 pm | Reply

  3. sir please i want juke box vb.net code in that
    searching option will be produce.that search
    will give the all information .

    Comment by nagayya — February 13, 2008 @ 3:24 am | Reply

  4. Wow, thanks! I was looking at LINQ and found this to be a really great example!

    Comment by Chad — March 29, 2008 @ 6:09 pm | Reply

  5. Excellent beat ! I would like to apprentice even as you amend your website,
    how could i subscribe for a blog site? The
    account aided me a applicable deal. I were a little bit acquainted of this your broadcast provided shiny transparent concept

    Comment by centerblog.net — June 14, 2013 @ 11:58 am | Reply


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: