Wednesday, December 12, 2012

ChordFactory on Windows 8

Coming soon - once I get the hang of async data loading and all the visual state support required


Not exactly the height of Metro design excellence either.

Monday, November 26, 2012

LINQ Outer Joins

I found out today how to do outer joins in LINQ and thought I’d save it as an Aide Memoire post.

Given a typical Foreign-Key relationship:

class Preference
{
    public int Id { get; set; }
    public string Description { get; set; }
}

class Person
{
    public int Id { get; set; }
    public string Forename { get; set; }
    public string Surname { get; set; }
    public int? PreferenceId { get; set; }
}

 

And this sample data:

    var peopleList = new List<Person>();
    peopleList.Add(new Person {Id = 77, Forename = "Fred", Surname = "Flintstone", PreferenceId = 2 });
    peopleList.Add(new Person {Id = 154, Forename = "Barney", Surname = "Rubble", PreferenceId = 1 });
    peopleList.Add(new Person {Id = 308, Forename = "Wilma", Surname = "Flintstone" });
    peopleList.Add(new Person {Id = 462, Forename = "Betty", Surname = "Rubble", PreferenceId = 1 });
    peopleList.Add(new Person {Id = 616, Forename = "Bam Bam", Surname = "Rubble", PreferenceId = 4 });
    peopleList.Add(new Person {Id = 770, Forename = "Pebbles", Surname = "Flintstone" });

    var preferenceList = new List<Preference>();
    preferenceList.Add(new Preference {Id = 1, Description = "Coffee"});
    preferenceList.Add(new Preference {Id = 2, Description = "Tea"});
    preferenceList.Add(new Preference {Id = 3, Description = "Hot Chocolate"});
    preferenceList.Add(new Preference {Id = 4, Description = "Fruit Juice"});

 

The obvious LINQ query:

    var peopleWithPreferences = from p in peopleList
                            join pr in preferenceList
                            on p.PreferenceId equals pr.Id
                            select new  {p.Forename, p.Surname, pr.Description};

 

Produces results that contain only the inner joined pairs of people and their beverage preference:

Forename  Surname     Description
Fred      Flintstone  Tea
Barney    Rubble      Coffee
Betty     Rubble      Coffee
Bam Bam   Rubble      Fruit Juice
 

In order to retrieve the full list of people with their beverage preference if they have one, the LINQ query becomes:

    var peopleAnyPreferences = from p in peopleList
                            join pr in preferenceList
                            on p.PreferenceId equals pr.Id into joinedPreferences
                            from j in joinedPreferences.DefaultIfEmpty()
                            select new  {p.Forename, p.Surname, pref = j != null ? j.Description : string.Empty};

 

Forename  Surname     Description
Fred      Flintstone  Tea
Barney    Rubble      Coffee
Wilma     Flintstone
Betty     Rubble      Coffee
Bam Bam   Rubble      Fruit Juice
Pebbles   Flintstone

 

The differences being the intermediate results joinedPreferences and its use with the DefaultIfEmpty extension, with a null check for the nullable column.


UPDATE: From a technique shown in this post by Jim Wooley:

A way of avoiding the need for intermediate results, using old-fashioned T-SQL style joins via a LINQ Where extension:

var betterPeopleAnyPreferences = from p in peopleList 
                    from pr in preferenceList
                    .Where(x => p.PreferenceId == x.Id)
                    .DefaultIfEmpty()
                    select new  {p.Forename, p.Surname, pref = pr != null ? pr.Description : string.Empty};

Friday, March 23, 2012

System.Collections.Generic.List<T> ForEach method is missing in Windows 8 Runtime

It seems that the handy ForEach method has been removed from the List of T class in the WinRT. According to Wes Haggard of the .NET Framework Bas Class Library (BCL) Team:

“List<T>.ForEach has been removed in Metro style apps. While the method seems simple it has a number of potential problems when the list gets mutated by the method passed to ForEach. Instead it is recommended that you simply use a foreach loop.”

Which is a shame, as I use this method quite a bit to invoke method group calls to do one-time iterations over Lists, like this:

keywordResults.ForEach(this.searchActivity.Keywords.Add);


For situations like this, the mutation issue doesn’t arise and it would be safe to use the ForEach method if it existed. So I did an extension method implementation of the functionality by taking a look at the decompiled code of the method in earlier versions of the .NET Framework:

public void ForEach(Action<T> action)
{
if (action == null)
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
for (int index = 0; index < this._size; ++index)
action(this._items[index]);
}



Using this as a starting point it was fairly easy to come up with an extension method version:

public static void ForEach<T>(this IEnumerable<T> list, Action<T> action)
{
if (action == null)
{
throw new ArgumentNullException("action");
}

foreach (var t in list)
{
action(t);
}
}



Now I can use the extension to give me the same ForEach functionality on IEnumerable objects such as List<T> as I had before.