2013-08-16 54 views
2

我讀左外連接在http://msdn.microsoft.com/en-us/library/vstudio/bb397895.aspx爲什麼linq join是單向的?

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 static 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) }; 

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

    // This code produces the following output: 
    // 
    // Magnus:   Daisy 
    // Terry:   Barley 
    // Terry:   Boots 
    // Terry:   Blue Moon 
    // Charlotte:  Whiskers 
    // Arlene: 

我想了解外連接,所以我調整了一點點

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" }; 
    **Person Momo = new Person { FirstName = "Momo", LastName = "Shawn" };** 

    **Pet kaw = new Pet { Name = "Kaw", Owner = Momo };** 
    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, **kaw** }; 

    var query = from pet in pets 
       join person in people on pet.Owner equals person into gj 
       from subpet in gj.DefaultIfEmpty() 
       select new { name = (pet.Owner == null ? "unknown": person.FirstName) , PetName = (subpet == null ? String.Empty : subpet.Name) }; 

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

智能感知不顯示。爲什麼?我一直認爲你可以在一個連接中交換左側和右側。但顯然,你不能。

有沒有任何文件解釋這個?

回答

1

智能感知不顯示人。爲什麼?

因爲它只在join ... into條款的範圍內。但你無論如何選擇每個person值,這一點:

from subpet in gj.DefaultIfEmpty() 

...所以只需使用subpet代替person。哎呀,你甚至可以調用的範圍變量person如果你想:

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

目前尚不清楚爲什麼分別致電範圍變量subpet不過,考慮到這將是一個人。也許是對join ... into做什麼的誤解?有關更多詳細信息,請參閱MSDN article on join,或者我的Edulinq blog post on query expressions

說實話,這不是完全清楚爲什麼這個連接是擺在首位有用 - 它看起來像一隻寵物只能有一個主人,在這種情況下,你真的只是檢查pet.Owner是否people。通常情況下,你可以執行一個分組,當有多個元素。例如,反過來更有意義:

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

現在,你發現每個人,並列出他們的寵物 - 或者,如果他們沒有一個寵物注意到。

你想用你的查詢來達到什麼目的?

+0

我不明白從gj中的subpet是什麼意思。 gj應該是對象對。看起來subpet指的是加入右側的對象 –

+0

@ user1978421:否,'gj'不是對象對 - 它是一組'Person'引用。目前還不清楚爲什麼你期望它是成對的。不要忘記,「寵物」仍然在範圍內...... –

+0

我明白了。這就像gj是一個指針列表。但是,爲什麼人們自動刪除空指針(如果不使用DefaultIfEmpty()?) –

1

由於您將其加入gj,因此無法訪問該人員。而不是person.FirstName,請使用gj.FirstOrDefault().FirstName

可能值得改變成這樣的東西?

var query = 
    from pet in pets 
    from person in people.Where(o => o == pet.Owner).DefaultIfEmpty() 
    select new 
    { 
     name = (person == null ? "unknown" : person.FirstName), 
     PetName = pet.Name 
    };