Linq Coding -- Part Seven (Join之左外部联接、DefaultIfEmpty、GroupJoin)

Join 子句有三种最常见的联接类型:内部联接分组联接,左外部联接
本次介绍:左外部联接,DefaultIfEmpty, GroupJoin

    左外部联接:就是返回第一个集合的每个元素,而无论该元素在第二个集合中是否具有相关元素。可以使用 LINQ,通过对分组联接的

    结果调用 DefaultIfEmpty 来执行左外部联接。

 

class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

 

class Pet
{
    public string Name { get; set; }
    public Person Owner { get; set; }
}

 

public void LeftOuterJoinExample()
{
    Person magnus = new Person { FirstName = "Magnus", LastName = "Hedlund" };
    Person terry = new Person { FirstName = "Terry", LastName = "Adams" };
    Person charlotte = new Person { FirstName = "Charlotte", LastName = "Weiss" };
    Person arlene = new Person { FirstName = "Arlene", LastName = "Huff" };

 

    Pet barley = new Pet { Name = "Barley", Owner = terry };
    Pet boots = new Pet { Name = "Boots", Owner = terry };
    Pet whiskers = new Pet { Name = "Whiskers", Owner = charlotte };
    Pet bluemoon = new Pet { Name = "Blue Moon", Owner = terry };
    Pet daisy = new Pet { Name = "Daisy", Owner = magnus };

 

    // Create two lists.
    List<Person> people = new List<Person> { magnus, terry, charlotte, arlene };
    List<Pet> pets = new List<Pet> { barley, boots, whiskers, bluemoon, daisy };

 

    var query = from person in people
                     join pet in pets on person equals pet.Owner into gj
                     from subpet in gj.DefaultIfEmpty()
                     select new
{

                     person.FirstName,

                     PetName = (subpet == null ? String.Empty : subpet.Name)

                     };
                      //此时subpet为引用类型,所以此时这里是需要进行null检查的。

    foreach (var v in query)
    {
        Console.WriteLine("{0,-15}{1}", v.FirstName + ":", v.PetName);
    }
}

 

DefaultIfEmpty:通过使用延迟执行实现。即时返回值为一个对象,该对象存储执行操作所需的所有信息。

它有两个重载方法:1.返回指定序列的元素;如果序列为空,则返回单一实例集合中的类型参数的默认值。

                               2.返回指定序列中的元素;如果序列为空,则返回单一实例集合中的指定值。

 

public class DefaultIfEmpty
    {
        public void DefaultifEmpty()
//第一种方法重载DEMO
        {
            List<Category> categorys = new List<Category> {
                new Category{ Name="AAAA", ID=11 },
                new Category{ Name="AAAA", ID=13 },
                new Category{ Name="AAAA", ID=14 }
            };

            foreach (Category category in categorys.DefaultIfEmpty())
            {
                Console.WriteLine(category.Name);
            }
        }

        public void EmptyList()
        {
            List<Int32> numbers = new List<Int32>();

            foreach (Int32 number in numbers.DefaultIfEmpty())
            {
                Console.WriteLine(number);
            }
        }

        public void DefaultifEmpty2()//第二种重载DEMO
        {
            Category defcategory = new Category { Name = "AAAA", ID = 13 };

            List<Category> categorys = new List<Category> {
                new Category{ Name="AAAA", ID=11 },
                new Category{ Name="AAAA", ID=13 },
                new Category{ Name="AAAA", ID=14 }
            };

            foreach (Category category in categorys.DefaultIfEmpty(defcategory))
            {
                Console.WriteLine("Name:{0}", category.ID);
            }

            List<Category> categoryEmpty = new List<Category>();

            foreach (Category category in categoryEmpty.DefaultIfEmpty(defcategory))
            {
                Console.WriteLine("Name:{0}", category.Name);
            }
        }

        /*
          11
          13
          14
         
          AAAA
         */

        //从以下的结果可以看出来,
       //如果 source 不为空,是返回List<Category>的数据;
       //如果 source 为空时,则为包含 defaultValue 的 IEnumerable<(Of <(T>)>)。

 }

 

*DefaultIfEmpty()方法与 GroupJoin 方法组合使用,可用于生成左外部联接。

 

GroupJoin:基于键相等对两个序列的元素进行关联并对结果进行分组
GroupJoin同样也有两个重载方法
             1.使用默认的相等比较器 Default 对键进行比较。
             2.使用指定的 IEqualityComparer<(Of <(T>)>) 对键进行比较。

 

 *以下代码执行结果均相同(只是三种不同的写法)

 

public class  GroupJoin    {
        public void groupJoin()
        {
            ///Lamda 写法
            var query =

            Database.people.GroupJoin(Database.pets,
                                    person => person,
                                    pet => pet.Owner,
                                    (person, petCollection) =>
                                    new
                                    {
                                      OwnerName = person.FirstName,
                                      Pets = petCollection.Select(pet => pet.Name)
                                    });

            foreach (var obj in query)
            {
                Console.WriteLine("{0}:", obj.OwnerName);
                foreach (String pet in obj.Pets)
                {
                    Console.WriteLine(" {0}", pet);
                }
            }

            ///结果等同于Lamda
            var queryForLinq2 =
from p in Database.people
                            join pp in Database.pets
                            on p.FirstName equals pp.Owner.FirstName
                            into peoplePets
                            select new
                            {
                              OwnerName = p.FirstName,
                              Pets = peoplePets.Select(pp => pp.Name)
                            };

            ///Linq 写法
           var queryForLinq =
from p in Database.people
                           select new
                           {
                             OwnerName = p.FirstName,
                             Pets = from pp in Database.pets
                                    where p.FirstName == pp.Owner.FirstName
                                    select pp
                           };
            
        }
    }

 

LINQ Coding 目录

  1. Linq Coding -- Part One
  2. Linq Coding -- Part Two[标准查询运算符]
  3. Linq Coding -- Part Three [Let子句]
  4. Linq Coding -- Part Four[Concat应用]
  5. Linq Coding -- Part Five (Join之内部联接查询)
  6. Linq Coding -- Part Six (Join之分组联接)
  7. Linq Coding -- Part Seven (Join之左外部联接、DefaultIfEmpty、GroupJoin)
  8. Linq Coding -- Part Eight (Equals Topic)
posted @ 2008-08-19 22:49  RicoRui  阅读(6230)  评论(2编辑  收藏  举报