Apparently you are trying to make groups of Customers with the same value for LastName. Some database management systems don't support GroupBy, although this is very rare, as Grouping is a very common database action.
To see if your database management system supports grouping, try the GroupBy using method syntax. End with ToList, to execute the GroupBy:
var customerGroupsWithSameLastName = dbContext.Customers.GroupBy(
// Parameter KeySelector: make groups of Customers with same value for LastName:
customer => customer.LastName)
.ToList();
If this works, the DBMS that your DbContext communicates with accepts GroupBy.
The result is a List of groups. Every Group object implements IGrouping<string, Customer>, which means that every Group has a Key: the common LastName of all Customers in this group. The group IS (not HAS) a sequence of all Customers that have this LastName.
By the way: a more useful overload of GroupBy has an extra parameter: resultSelector. With the resultSelector you can influence the output: it is not a sequence of IGrouping objects, but a sequence of objects that you specify with a function.
This function has two input parameters: the common LastName, and all Customers with this LastName value. The return value of this function is one of the elements of your output sequence:
var result = dbContext.Customers.GroupBy(
customer => customer.LastName,
// parameter resultSelector: take the lastName and all Customers with this LastName
// to make one new:
(lastName, customersWithThisLastName) => new
{
LastName = lastName,
Count = customersWithThisLastName.Count(),
FirstNames = customersWithThisLastName.Select(customer => customer.FirstName)
.ToList(),
... // etc
})
.ToList();
Back to your question
If the above code showed you that the function is not supported by your DBMS, you can let your local process do the grouping:
var result = dbContext.Customer
// if possible: limit the number of customers that you fetch
.Where(customer => ...)
// if possible: limit the customer properties that you fetch
.Select(customer => new {...})
// Transfer the remaining data to your local process:
.AsEnumerable()
// Now your local process can do the GroupBy:
.GroupBy(customer => customer.LastName)
.ToList();
Since you selected the complete Customer, all Customer data would have been transferred anyway, so it is not a big loss if you let your local process do the GroupBy, apart maybe that the DBMS is probably more optimized to do grouping faster than your local process.
Warning: Database management systems are extremely optimized in selecting data. One of the slower parts of a database query is the transfer of the selected data from the DBMS to your local process. So if you have to use AsEnumerable(), you should realize that you will transfer all data that is selected until now. Make sure that you don't transfer anything that you won't use anyhow after the AsEnumerable(); so if you are only interested in the FirstName and LastName, don't transfer primary keys, foreign keys, addresses, etc. Let your DBMS do the Where and Select`