2013-04-03 3 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

ответ

1

Вы пропустили ту часть запроса выборки:

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

На ваш запрос это просто PetName = y.Name, поэтому, когда нет соответствующей строки в списке pets вы получаете NullReferrenceException, потому что y является null.

Должно быть:

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

+0

'DefaultIfEmpty' возвращает значение по умолчанию, когда коллекция пуста (например, в объединенной коллекции нет соответствующих значений). Для всех типов ссылок это «null». Вот как работает «LEFT JOIN». – MarcinJuraszek

+0

Так как я знаю, что 'DefaultIfEmpty' имеет перегрузку, где я могу указать объект для использования, должно быть возможно создать объект' Pet': 'Pet defaultPet = new Pet {Name =" "};' и использовать 'DefaultIfEmpty (defaultPet)?? В этом случае мне не нужно было бы проверять нулевые значения в моем 'SelectMany'. – Jeff

Смежные вопросы