我一直在搜索Select和SelectMany之间的区别,但我还没有找到合适的答案。我需要学习使用LINQ to SQL时的差异,但我所找到的都是标准数组示例。

有人能提供一个LINQ到SQL的例子吗?


当前回答

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

Live Demo。net Fiddle

其他回答

假设你有一组国家

var countries = new[] { "France", "Italy" };

如果你对国家执行Select,你将得到数组中的每个元素IEnumerable<T>

IEnumerable<string> selectQuery = countries.Select(country => country);

在上面的代码中,国家表示指向数组中每个国家的字符串。现在迭代selectQuery以获得国家:

foreach(var country in selectQuery)
    Console.WriteLine(country);

// output
//
// France
// Italy

如果你想打印每个国家的字符,你必须使用嵌套foreach

foreach (var country in selectQuery)
{
    foreach (var charOfCountry in country)
    {
        Console.Write(charOfCountry + ", ");
    }
}

// output

// F, r, a, n, c, e, I, t, a, l, y,

好的。现在尝试对国家执行SelectMany。这一次SelectMany获取每个国家作为字符串(和以前一样),因为字符串类型是一个字符的集合,SelectMany尝试将每个国家分为它的组成部分(字符),然后返回一个字符的集合IEnumerable<T>

IEnumerable<char> selectManyQuery = countries.SelectMany(country => country);

在上面的代码中,country表示一个字符串,该字符串引用数组中的每个国家,但返回值是每个国家的字符

实际上SelectMany喜欢在集合中获取两层,并将第二层平铺为IEnumerable<T>

现在遍历selectManyQuery以获得每个国家的字符:

foreach(var charOfCountry in selectManyQuery)
    Console.Write(charOfCountry + ", ");

// output

// F, r, a, n, c, e, I, t, a, l, y,

下面是一个用于测试的初始化小集合的代码示例:

class Program
{
    static void Main(string[] args)
    {
        List<Order> orders = new List<Order>
        {
            new Order
            {
                OrderID = "orderID1",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU1",
                        Quantity = 1
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU2",
                        Quantity = 2
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU3",
                        Quantity = 3
                    }
                }
            },
            new Order
            {
                OrderID = "orderID2",
                OrderLines = new List<OrderLine>
                {
                    new OrderLine
                    {
                        ProductSKU = "SKU4",
                        Quantity = 4
                    },
                    new OrderLine
                    {
                        ProductSKU = "SKU5",
                        Quantity = 5
                    }
                }
            }
        };

        //required result is the list of all SKUs in orders
        List<string> allSKUs = new List<string>();

        //With Select case 2 foreach loops are required
        var flattenedOrdersLinesSelectCase = orders.Select(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectCase)
        {
            foreach (OrderLine orderLine in flattenedOrderLine)
            {
                allSKUs.Add(orderLine.ProductSKU);
            }
        }

        //With SelectMany case only one foreach loop is required
        allSKUs = new List<string>();
        var flattenedOrdersLinesSelectManyCase = orders.SelectMany(o => o.OrderLines);
        foreach (var flattenedOrderLine in flattenedOrdersLinesSelectManyCase)
        {
            allSKUs.Add(flattenedOrderLine.ProductSKU);
        }

       //If the required result is flattened list which has OrderID, ProductSKU and Quantity,
       //SelectMany with selector is very helpful to get the required result
       //and allows avoiding own For loops what according to my experience do code faster when
       // hundreds of thousands of data rows must be operated
        List<OrderLineForReport> ordersLinesForReport = (List<OrderLineForReport>)orders.SelectMany(o => o.OrderLines,
            (o, ol) => new OrderLineForReport
            {
                OrderID = o.OrderID,
                ProductSKU = ol.ProductSKU,
                Quantity = ol.Quantity
            }).ToList();
    }
}
class Order
{
    public string OrderID { get; set; }
    public List<OrderLine> OrderLines { get; set; }
}
class OrderLine
{
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}
class OrderLineForReport
{
    public string OrderID { get; set; }
    public string ProductSKU { get; set; }
    public int Quantity { get; set; }
}

Select是一个简单的从源元素到结果元素的一对一投影。选择- - - 当查询表达式中有多个from子句时使用Many:原始序列中的每个元素都用于生成一个新序列。

SelectMany()方法用于抚平序列,其中序列的每个元素都是独立的。

我的类用户是这样的

class User
    {
        public string UserName { get; set; }
        public List<string> Roles { get; set; }
    }

主要:

var users = new List<User>
            {
                new User { UserName = "Reza" , Roles = new List<string>{"Superadmin" } },
                new User { UserName = "Amin" , Roles = new List<string>{"Guest","Reseption" } },
                new User { UserName = "Nima" , Roles = new List<string>{"Nurse","Guest" } },
            };

var query = users.SelectMany(user => user.Roles, (user, role) => new { user.UserName, role });

foreach (var obj in query)
{
    Console.WriteLine(obj);
}
//output

//{ UserName = Reza, role = Superadmin }
//{ UserName = Amin, role = Guest }
//{ UserName = Amin, role = Reseption }
//{ UserName = Nima, role = Nurse }
//{ UserName = Nima, role = Guest }

您可以对序列的任何项使用操作

int[][] numbers = {
                new[] {1, 2, 3},
                new[] {4},
                new[] {5, 6 , 6 , 2 , 7, 8},
                new[] {12, 14}
            };

IEnumerable<int> result = numbers
                .SelectMany(array => array.Distinct())
                .OrderBy(x => x);

//output

//{ 1, 2 , 2 , 3, 4, 5, 6, 7, 8, 12, 14 }
 List<List<int>> numbers = new List<List<int>> {
                new List<int> {1, 2, 3},
                new List<int> {12},
                new List<int> {5, 6, 5, 7},
                new List<int> {10, 10, 10, 12}
            };

 IEnumerable<int> result = numbers
                .SelectMany(list => list)
                .Distinct()
                .OrderBy(x=>x);

//output

// { 1, 2, 3, 5, 6, 7, 10, 12 }

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

Live Demo。net Fiddle