Wednesday, December 12, 2012
ChordFactory on Windows 8
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.