开发者

Why is my result of type List<IEnumerable<T>>

Two queries that should result in a list of account numbers (strings). However the second query actually returns a List<IEnumerable<string>>, where I would like it to return a List<string>. What am I doing wrong?

//the type here resolves to List<string>
var acts = (from a in base.context.Accounts
            select a.Acco开发者_开发百科untNumber).ToList();

//the type here resolves to List<IEnumerable<string>>
var uAccounts = (from u in base.context.Users
                 select u.Accounts.Select(s => s.AccountNumber)).ToList();


Change

var uAccounts = (from u in base.context.Users
             select u.Accounts.Select(s => s.AccountNumber)).ToList();

to

var uAccounts = base.context.Users.SelectMany(u => 
                u.Accounts.Select(s => s.AccountNumber)).ToList();

And to actually answer your question, the difference between the two lines of your code is that the first one goes through every single account and selects just the account number. The second statement selects an embedded Linq query of IEnumerable<string>. So you are converting to a List<T> of these IEnumerable<string>

That actually shows the benefit of the SelectMany extention method (I'm not actually sure about how to use that in a query statement). The SelectMany method instead flattens the IEnumerable<T> you would normally receive to a single enumeration of the T element. So when ToList() is called, it will return you a List<string> instead of the enumerable.


Your select clause is returning / nests another select operation and hence you end up with nested enumerations. To flatten the list you need to use SelectMany instead.

var acts = base.context.Accousts
  .SelectMany(a => x.AccountNumber)
  .ToList();


u.Accounts.Select(s => s.AccountNumber) by itself gives you an IEnumerable<string>.

Then wrapping that in from u in base.context.Users select u.Accounts.Select(s => s.AccountNumber) gives you an IEnumerable<IEnumerable<string>>.

Then calling .ToList() on that gives List<IEnumerable<string>>.


While you could use SelectMany, it is more straightforward to nest your from clauses:

var uAccounts = (from u in base.context.Users
                  from a in u.Accounts
                    select a.AccountNumber).ToList();

When and if you use products like NHibernate, you will want to know this idiom, as it is a very straightforward way to do table joins in the resulting SQL code.


In the second query, you are doing a second select that's creating your inner list

This returns an IEnumerable<string>

 u.Accounts.Select(s => s.AccountNumber)

and then your are wrapping it in another select that creates the outer list


u.Accounts.Select(s => s.AccountNumber)

is a list of Account number

so

(from u in base.context.Users
     select u.Accounts.Select(s => s.AccountNumber))

is an IEnumerable of lists of account numbers

adding .ToList()

Makes it a List of lists of account numbers


I think I need to use u.Accounts.SelectMany(...) to get the desired result.


In the second case, the ToList() only applies to the outer list, which itself consists of lists.


u.Accounts.Select(s => s.AccountNumber) returns IEnumerable<string>

select u.Accounts.Select(s => s.AccountNumber) returns IEnumerable<IEnumerable<string>>

select u.Accounts.Select(s => s.AccountNumber)).ToList(); just turns the outer IEnumerable into IList

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜