Tuesday, March 15, 2011

Adventures in LINQ - Part 1

The one thing that I am really enjoying about my current stint in c# is learning about and using LINQ.  This really seems like a powerful way to query objects.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LinqExamples.examples
{

    class LinqExample2 : IExample
    {
        private Role Role1 = new Role(){Id = 1,Name = "Role 1"};
        private Role Role2 = new Role(){Id = 2, Name = "Role 2"};
        private Role Role3 = new Role(){Id = 3, Name = "Role 3"};
        private User User1 = new User() { Id = 1, Name = "User 1" };
        private Account Account1 = new Account() { Id = 1, Name = "Account 1" };

        List&ltuserroleaccount> UserRoleAccountsList;
        List&ltrole> NewRoles;

        public LinqExample2() 
        {
            UserRoleAccountsList = new List&ltuserroleaccount>()
                                                                    {
                                                                        new UserRoleAccount() {
                                                                            Account = Account1,
                                                                            Roles = new List&ltrole>(){ Role1, Role2}
                                                                        }

                                                                    };
            NewRoles = new List&ltrole>() { Role1, Role3 };
        }

        public void ExecuteExample()
        {
            Console.WriteLine("Linq Example #2: Only adding new roles");
            Console.WriteLine("========================================================");

            var rolesToAdd = NewRoles.Except(UserRoleAccountsList.Where(x => x.Account.Id == Account1.Id).Select(x => x.Roles).FirstOrDefault());
            foreach (var item in rolesToAdd)
            {
                Console.WriteLine("Role to add: {0}", item.Name);
            }

            var rolesIntersect = NewRoles.Intersect(UserRoleAccountsList.Where(x => x.Account.Id == Account1.Id).Select(x => x.Roles).FirstOrDefault());
            foreach (var item in rolesIntersect)
            {
                Console.WriteLine("Role intersect {0}", item.Name);
            }

            var rolesUnion = NewRoles.Union(UserRoleAccountsList.Where(x => x.Account.Id == Account1.Id).Select(x => x.Roles).FirstOrDefault());
            foreach (var item in rolesUnion)
            {
                Console.WriteLine("Role union {0}", item.Name);
            }
        }
    }

    class UserRoleAccount
    {
        public List&ltrole> Roles { get; set; }
        public Account Account { get; set; }
    }

    class User
    {
        public string Name { get; set; }
        public long Id { get; set; }
    }

    class Role
    {
        public string Name { get; set;}
        public long Id { get; set; }
    }

    class Account
    {
        public string Name { get; set; }
        public long Id { get; set; }
    }
}


[Sorry about the encoding, hopefully I'll figure out a better way to display generics soon]


As you can see from the above example, it is very easy to compare the NewRoles object to the list of roles already set in the UserRoleAccount object.

1) Except:  displays all roles that are in NewRoles but not in the current role list
2) Intersect: displays all the roles that exist in both lists
3)  Union:  Does a join on the two lists.  Does not display duplicates.

This is a far cry from the days of iterating over the lists or implementing custom comparator functions.