Cómo aplanar objetos nesteds con expresión linq

Estoy tratando de aplanar objetos nesteds como este:

public class Book { public string Name { get; set; } public IList Chapters { get; set; } } public class Chapter { public string Name { get; set; } public IList Pages { get; set; } } public class Page { public string Name { get; set; } } 

Déjame hacer un ejemplo. Esta es la información que tengo

 Book: Pro Linq { Chapter 1: Hello Linq { Page 1, Page 2, Page 3 }, Chapter 2: C# Language enhancements { Page 4 }, } 

El resultado que estoy buscando es la siguiente lista plana:

 "Pro Linq", "Hello Linq", "Page 1" "Pro Linq", "Hello Linq", "Page 2" "Pro Linq", "Hello Linq", "Page 3" "Pro Linq", "C# Language enhancements", "Page 4" 

¿Cómo podría lograr esto? Podría hacerlo con una nueva selección, pero me han dicho que un SelectMany sería suficiente.

 myBooks.SelectMany(b => b.Chapters .SelectMany(c => c.Pages .Select(p => b.Name + ", " + c.Name + ", " + p.Name))); 

Asumiendo books es una lista de libros:

 var r = from b in books from c in b.Chapters from p in c.Pages select new {BookName = b.Name, ChapterName = c.Name, PageName = p.Name}; 
 myBooks.SelectMany(b => b.Chapters .SelectMany(c => c.Pages .Select(p => new { BookName = b.Name , ChapterName = c.Name , PageName = p.Name }); 

Estaba tratando de hacer esto también, y de los comentarios de Yuriy y de meterme con linqPad tengo esto …

Tenga en cuenta que no tengo libros, capítulos, páginas, tengo persona (libros), compañíaPersona (capítulos) y empresas (páginas)

 from person in Person join companyPerson in CompanyPerson on person.Id equals companyPerson.PersonId into companyPersonGroups from companyPerson in companyPersonGroups.DefaultIfEmpty() select new { ContactPerson = person, ContactCompany = companyPerson.Company }; 

o

 Person .GroupJoin ( CompanyPerson, person => person.Id, companyPerson => companyPerson.PersonId, (person, companyPersonGroups) => new { person = person, companyPersonGroups = companyPersonGroups } ) .SelectMany ( temp0 => temp0.companyPersonGroups.DefaultIfEmpty (), (temp0, companyPerson) => new { ContactPerson = temp0.person, ContactCompany = companyPerson.Company } ) 

Ref sitio que utilicé: http://odetocode.com/blogs/scott/archive/2008/03/25/inner-outer-lets-all-join-together-with-linq.aspx