Разница между Select и SelectMany - PullRequest
935 голосов
/ 06 июня 2009

Я искал разницу между Select и SelectMany, но не смог найти подходящий ответ. Мне нужно узнать разницу при использовании LINQ To SQL, но все, что я нашел, это стандартные примеры массивов.

Может ли кто-нибудь предоставить пример LINQ To SQL?

Ответы [ 13 ]

1456 голосов
/ 06 июня 2009

SelectMany сглаживает запросы, которые возвращают списки списков. Например

public class PhoneNumber
{
    public string Number { get; set; }
}

public class Person
{
    public IEnumerable<PhoneNumber> PhoneNumbers { get; set; }
    public string Name { get; set; }
}

IEnumerable<Person> people = new List<Person>();

// Select gets a list of lists of phone numbers
IEnumerable<IEnumerable<PhoneNumber>> phoneLists = people.Select(p => p.PhoneNumbers);

// SelectMany flattens it to just a list of phone numbers.
IEnumerable<PhoneNumber> phoneNumbers = people.SelectMany(p => p.PhoneNumbers);

// And to include data from the parent in the result: 
// pass an expression to the second parameter (resultSelector) in the overload:
var directory = people
   .SelectMany(p => p.PhoneNumbers,
               (parent, child) => new { parent.Name, child.Number });

Демонстрация в реальном времени на .NET Fiddle

166 голосов
/ 23 октября 2012

Выбор многих похож на операцию перекрестного соединения в SQL , где он принимает перекрестный продукт. Например, если у нас есть

Set A={a,b,c}
Set B={x,y}

Выберите многие можно использовать для получения следующего набора

{ (x,a) , (x,b) , (x,c) , (y,a) , (y,b) , (y,c) }

Обратите внимание, что здесь мы берем все возможные комбинации, которые можно составить из элементов множества A и множества B.

Вот пример LINQ, который вы можете попробовать

List<string> animals = new List<string>() { "cat", "dog", "donkey" };
List<int> number = new List<int>() { 10, 20 };

var mix = number.SelectMany(num => animals, (n, a) => new { n, a });

микс будет иметь следующие элементы в плоской структуре, такие как

{(10,cat), (10,dog), (10,donkey), (20,cat), (20,dog), (20,donkey)}
103 голосов
/ 30 октября 2013

enter image description here

var players = db.SoccerTeams.Where(c => c.Country == "Spain")
                            .SelectMany(c => c.players);

foreach(var player in players)
{
    Console.WriteLine(player.LastName);
}
  1. Де Хеа
  2. Alba
  3. Costa
  4. Villa
  5. Бускетс

...

73 голосов
/ 06 июня 2009

SelectMany() позволяет свернуть многомерную последовательность таким образом, чтобы в противном случае потребовался бы второй Select() или цикл.

Подробнее об этом сообщении в блоге .

33 голосов
/ 26 декабря 2010

Есть несколько перегрузок на SelectMany. Один из них позволяет вам отслеживать любые отношения между родителями и потомками при обходе иерархии.

Пример : предположим, у вас есть следующая структура: League -> Teams -> Player.

Вы можете легко вернуть фиксированную коллекцию игроков. Однако вы можете потерять любую ссылку на команду, в которую входит игрок.

К счастью, для этой цели существует перегрузка:

var teamsAndTheirLeagues = 
         from helper in leagues.SelectMany
               ( l => l.Teams
                 , ( league, team ) => new { league, team } )
                      where helper.team.Players.Count > 2 
                           && helper.league.Teams.Count < 10
                           select new 
                                  { LeagueID = helper.league.ID
                                    , Team = helper.team 
                                   };

Предыдущий пример взят из Dan's IK blog . Я настоятельно рекомендую вам взглянуть на это.

19 голосов
/ 06 июня 2009

Я понимаю, что SelectMany работает как ярлык соединения.

Так что вы можете:

var orders = customers
             .Where(c => c.CustomerName == "Acme")
             .SelectMany(c => c.Orders);
12 голосов
/ 25 сентября 2012

Выбор - это простая проекция один-к-одному из исходного элемента в элемент результата. Выбрать- Many используется, когда в выражении запроса есть несколько предложений from: каждый элемент в исходной последовательности используется для генерации новой последовательности.

7 голосов
/ 27 августа 2015

Некоторые SelectMany могут не понадобиться. Ниже 2 запроса дают одинаковый результат.

Customers.Where(c=>c.Name=="Tom").SelectMany(c=>c.Orders)

Orders.Where(o=>o.Customer.Name=="Tom")

Для отношений 1-ко-многим,

  1. если начать с «1», то SelectMany необходим, он сглаживает многие.
  2. если Начать с «Много», SelectMany не требуется. ( по-прежнему можно фильтровать с "1" , также это проще, чем ниже стандартного запроса на соединение)

from o in Orders
join c in Customers on o.CustomerID equals c.ID
where c.Name == "Tom"
select o
4 голосов
/ 11 марта 2016

Не слишком технически - база данных со многими организациями, в каждой из которых много пользователей: -

var orgId = "123456789";

var userList1 = db.Organizations
                   .Where(a => a.OrganizationId == orgId)
                   .SelectMany(a => a.Users)
                   .ToList();

var userList2 = db.Users
                   .Where(a => a.OrganizationId == orgId)
                   .ToList();

оба возвращают один и тот же Список пользователей приложения для выбранной организации.

Первый «проект» от организации до пользователей, второй напрямую запрашивает таблицу Users.

2 голосов
/ 12 октября 2017

Просто для альтернативного представления, которое может помочь некоторым функциональным программистам:

  • Select - это map
  • SelectMany - это bind (или flatMap для ваших людей из Scala / Kotlin)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...