cableload cableload - 1 month ago 6
C# Question

linq selectmany flatten multiple levels

I have the following relation (for example)

A contains one or more B's

Each B contains one or more C's and D's

I want to flatten everything using SelectMany along with some search conditions and get A,B,C and D's . This is what i have.

context.A.Where(a => (string.IsNullOrEmpty(name) || a.Name.Contains(name)))
.SelectMany(ab =>ab.b.Where(n=>n.bname.Contains(name) || string.IsNullOrEmpty(name)),
(aa, bb) => new { aa, bb }) //gets all a's and b's
.SelectMany(bc => bb.c.Where(w => w.KEYWORD.Contains(Keyword) || string.IsNullOrEmpty(Keyword)),
(bc,words) => new {bc,kwords}) //gets all b's and c's


Is what i am doing right? If so , then how to get B along with all D's adding to the above expression?

Answer

Agreeing with what Ivan suggested you can flatten this 3 levels deep structure like this:

var query = (from a in A
             from b in (List<dynamic>)a.b
             from c in (List<dynamic>)b.c
             from d in (List<dynamic>)b.d
             select new { a, b, c, d });

if (!string.IsNullOrEmpty(name))
{
    query = query.Where(record => record.b.bname.Contains(name));
}

if (!string.IsNullOrEmpty(keyword))
{
    query = query.Where(record => record.c.keyword.Contains(keyword));
}

var result = query.ToList();

You can also add the where clauses in the query at the top but seeing that you are checking if you got any valid input at all I'd put it after

Tested it with this sample data:

List<dynamic> A = new List<dynamic>
{
    new { b = new List<dynamic> { new { bname = "a", c = new List<dynamic> { new { keyword = "b" } }, d = new List<dynamic> { 1, 2, 3 } } } },
    new { b = new List<dynamic> { new { bname = "a", c = new List<dynamic> { new { keyword = "d" } }, d = new List<dynamic> { 1, 2, 3 } } } }
};

string name = "a";
string keyword = "b";