Article Series
The Problem
For the third year in a row, Silicon Valley's Code Camp is happening. The way I've organized the data is that each year I make a fresh new sql server 2005 database catalog. this means that I have one for 2006, one for 2007 and a new one for 2008. I want to do a mailing to all people who have registered to previous code camps and who have not registered yet for this code camp. This way, I can do multiple mailings without worrying about sending to people that who have registered (which would make me look silly for not knowing they registered already). I do not like when people say things like "Ignore this message if you have registered...". In addition we will maintain an opt out list so that people who do not want additional emails sent can request that and not worry about us sending more emails.
The Givens
So, since this article is about how to solve the problem with LINQ, I will not go into details of how to create the generic lists of email addresses. Let's assume we have methods that give us these 4 lists. They are:
- 2006 Registered Attendees
- 2007 Registered Attendees
- 2008 Registered Attendees
- Opt Out Email List
The Code
Below is the C# version 3.0 (.Net 3.5 and asp.net 3.5) that performs this function described in the problem above. The next section "The Explanation" gives more details on what i s happening.
1: using System.Linq;
2:
3: /// <summary>
4: /// shows all non registered users by going
5: /// through past years and making a
6: /// unique query.
7: /// </summary>
8: /// <returns>List of all non-registered
9: /// code campers form previous years</returns>
10: public static List<ListItem> LoadAllUnRegisteredCodeCampUsers()
11: {
12:
13: List<string> codeCampersCurrentYear =
14: GetEmailsFromPreviousYear("CodeCampSV06");
15:
16: List<string> emailOptOut2008 =
17: GetDoNotRemoveList("CodeCampSV06");
18:
19: List<string> codeCampers2007 =
20: GetEmailsFromPreviousYear("PASTSV07");
21:
22: List<string> codeCampers2006 =
23: GetEmailsFromPreviousYear("PASTSV06");
24:
25: // Make Combined List of 06 and 07 and unique it
26: // (duplicates are removed in Union)
27: IEnumerable<string> uniqueNamesQuery =
28: codeCampers2006.Union(codeCampers2007).OrderBy(s => s);
29:
30: var emailListBeforeOptOut =
31: uniqueNamesQuery.Except(codeCampersCurrentYear);
32:
33: var emaiListAfterOptOut =
34: emailListBeforeOptOut.Except(emailOptOut2008);
35:
36: List<ListItem> finalList = new List<ListItem>();
37: foreach (string s in emaiListAfterOptOut)
38: {
39: finalList.Add(new ListItem(s,s));
40: }
41: return finalList;
42: }
43:
The Explanation
The first line (1) is required because all the LINQ methods we are using are static extension methods. This means, that without referencing the LINQ namespace, the methods OrderBy,Except and Union would not be available to us.
Lines 13 to 23 call methods that populate our generic lists of strings. The reason this is done is because each of these lists come from different SQL Server 2005 database catalogs. This can probably be done in LINQ but I thought it was easier to do it this way.
Line 27 creates a list of unique names. The Union method has the added benefit of eliminating duplicates. OrderBy(s=>s) simply creates an annonymous delegate that takes in a string and returns a string so that is what gets sorted. After giving this some thought, I'm not sure the OrderBy really helps us in anyway but this is a tutorial type article so I'm leaving it in.
Line 33 removes all the people who have asked to be opted out of the email. It uses the static extension method Except.
Finally, line 36 to 40 creates a generic list of ListItems which is what is returned by the method. ListItem's are returned primarily because the calling method shows a list of checkboxes and this makes it easy.
Conclusions
LINQ is a great tool for managing collections. In this case we demonstrated how to take 4 generic lists of strings (collections), do some simple set operations (union,except,orderby) and produce a list of emails we want to send. Not only is it simple to code, it's easy to maintain because the method names are so descriptive. Hopefully, this will help with your similar programming efforts. Best of luck.