LINQ query for joining multiple tables and get comma separated values in single row

Viewed 530

I have below tables with the values.

Account:

Id Name Email
101 Nasir Uddin nasir@email.com

Role:

Id Title
101 Admin
102 Operator

AccountRole:

AccountId RoleId
101 101
101 102

Now I want to write a linq to have the result like below:

UserAccount

AccountId Name Email Roles
101 Nasir Uddin nasir@email.com Admin, Operator

To get the above result I have written the below query in LINQ. But it does not get the expected result.

var userAccount1 = (from account in _db.Accounts
                               join accountRole in _db.AccountRoles on account.Id equals accountRole.AccountId
                               join role in _db.Roles on accountRole.RoleId equals role.Id             
                               select new UserAccountInfo
                               {
                                   AccountId = account.Id,
                                   Name = account.UserFullName,
                                   Email = account.Email,                                 
                                   Roles = string.Join(",", role.Title)
                               });
2 Answers

At last I found my answer. The results can be achieved in different ways. Examples are given below:

var answer1 = (from account in userAccounts
    join accountRole in accountRoles on account.Id equals accountRole.AccountId
    join role in roles on accountRole.RoleId equals role.Id
    select new UserAccount
    {
        AccountId = account.Id,
        Name = account.Name,
        Email = account.Email,
        Roles = role.Title
    }).ToList().GroupBy(x => new { x.AccountId, x.Name, x.Email }).Select(y => new UserAccount
    {
        AccountId = y.Key.AccountId,
        Name = y.Key.Name,
        Email = y.Key.Email,
        Roles = string.Join(", ", y.Select(a => a.Roles))
    }).ToList();
----------------------------------------------------------------------------
var answer2 = (from account in userAccounts
     join accountRole in accountRoles on account.Id equals accountRole.AccountId
     join role in roles on accountRole.RoleId equals role.Id
     group new { account, role } by new { account.Id, account.Name, account.Email } into ag
     select new UserAccount
     {
         AccountId = ag.Key.Id,
         Name = ag.Key.Name,
         Email = ag.Key.Email,
         Roles = string.Join(", ", ag.Select(x=> x.role.Title))
     }).ToList();
    ----------------------------------------------------------------------------

var answer3 = (from account in userAccounts
     let roles1 = from accountRole in accountRoles
                  join role in roles on accountRole.RoleId equals role.Id
                  where accountRole.AccountId == account.Id
                  select role
     select new UserAccount
     {
         AccountId = account.Id,
         Name = account.Name,
         Email = account.Email,
         Roles = string.Join(", ", roles1.Select(x => x.Title))
     }).ToList();

The below gives you the expected result using Lambda Expression (not Query Expression) based on the information provided in your post (and some assumptions since I could not find e.g. UserFullName in any of your tables)

Note: I'm also convinced there is a more efficient way to do this, but it is a starting point if nothing else.

(Here is working .NET Fiddle of the below: https://dotnetfiddle.net/aGra15):

    // Join the AccountRoles and Roles together and group all Titles for
    // a given AccountId together
    var groupedAccountRoles = AccountRoles.GroupJoin(Roles, i => i.RoleId, o => o.Id, (o, i) => new {o, i})
        .Select(x => new {AccountId = x.o.AccountId, Titles = string.Join(",", x.i.Select(y => y.Title))});

    // Perform another GroupJoin to group by AccountId and Join to groupedAccountRoles table. Then `string.Join()`
    var userAccount1 = Accounts.GroupJoin(AccountRoles, acc => acc.Id, accrol => accrol.AccountId,
            (o, i) => new {o, UserAccountRoles = i})
        .GroupJoin(groupedAccountRoles, ii => ii.o.Id, oo => oo.AccountId,
            (ii, oo) => new UserAccountInfo
            {
                AccountId = ii.o.Id, 
                Email = ii.o.Email, 
                Name = ii.o.Name,
                Roles = string.Join(",", oo.Select(x => x.Titles))
            });

This will give the following output:

enter image description here

Related