2013-04-03 143 views
1

我試圖讓這個左外連接工作,但我似乎遇到了一些問題。我已經拿到了MSDN left join article的示例代碼。這個例子是在LINQ語法中的,但是我希望我的擴展方法語法,所以我也引用了這個SO問題。左外連接錯誤

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 = people 
      .GroupJoin(pets, 
      p1 => p1.FirstName, 
      p2 => p2.Owner.FirstName, 
      (p1, p2) => new {p1,p2}) 
      .SelectMany(x => x.p2.DefaultIfEmpty(), 
      (x, y) => new { FirstName = x.p1.FirstName, PetName = y.Name }); 

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

我的查詢基本上等同於我所引用的代碼,但我得到這個錯誤:

NullReferenceException 
Object reference not set to an instance of an object. 

這應該是非常簡單的。我究竟做錯了什麼?

+0

查詢語法更易於閱讀。但是要回答你的問題,在你訪問對象中的一個屬性(從左連接)之前,你必須檢查它是否爲null。 (當使用Linq2Sql時,這是不需要的) – Magnus 2013-04-03 20:40:24

回答

1

你錯過了樣本查詢部分:

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

您的查詢它只是PetName = y.Name,所以每當有pets列表中沒有相應的行你得到NullReferrenceException因爲ynull

應該是:

var query = people 
      .GroupJoin(pets, 
      p1 => p1.FirstName, 
      p2 => p2.Owner.FirstName, 
      (p1, p2) => new { p1, p2 }) 
      .SelectMany(x => x.p2.DefaultIfEmpty(), 
       (x, y) => new { FirstName = x.p1.FirstName, PetName = (y == null ? String.Empty : y.Name) }); 

或者你可以使用DefaultIdEmpty(TSource)方法重載:

var def = new Pet { Name = string.Empty }; 

var query = people 
      .GroupJoin(pets, 
      p1 => p1.FirstName, 
      p2 => p2.Owner.FirstName, 
      (p1, p2) => new { p1, p2 }) 
      .SelectMany(x => x.p2.DefaultIfEmpty(def), 
       (x, y) => new { FirstName = x.p1.FirstName, PetName = y.Name }); 
+0

這很有效,但我認爲這是'DefaultIfEmpty'的用途。這不涉及右手收集包含空值的情況嗎? – Jeff 2013-04-03 20:41:38

+0

'DefaultIfEmpty'返回集合爲空時的默認值(例如,連接的集合中沒有對應的值)。對於所有的引用類型,它是'null'。這就是'LEFT JOIN'的工作原理。 – MarcinJuraszek 2013-04-03 20:42:38

+0

因此,因爲我知道'DefaultIfEmpty'有一個重載的地方,我可以指定一個對象來使用,應該可以創建一個'Pet'對象:'Pet defaultPet = new Pet {Name =「」};'並使用'DefaultIfEmpty (defaultPet)對嗎?'在這種情況下,我不需要在我的'SelectMany'中檢查空值。 – Jeff 2013-04-03 20:46:24