简体   繁体   中英

Entity Framework - LINQ Expression Map many to many

I want to find a single User and populate the ICollection<Role> for that user

I've got users

public class User {
   public string Id { get; set; }
   public string UserName { get; set; }
   public ICollection<Role> Roles { get; set; }
}

And the roles

public class Role {
   public string Id {get; set; }
   public string Name { get; set; }
}

My Database looks like this

在此输入图像描述

I want to get a specific User by Id, all his Roles with a single SQL call.

_context is my DbContext where we can queue User, Roles and UserRoles

With the following sql command I get what data I'm looking for

from users in _context.Users
where users.Id == id
join userRoles in _context.UserRoles on users.Id equals userRoles.UserId
join roles in _context.Roles on userRoles.RoleId equals roles.Id
select new
{
    UserID = users.Id,
    UserName = users.UserName,
    RoleID = roles.Id,
    RoleName = roles.Name
};

My problem

I want to map this result to the User class, it should create a single user and a ICollection of Roles

在此输入图像描述

How can I achieve this?

Would it be possible using AutoMapper? How?

Thanks in advance! Alex

PS: I do not want to use the stores offered by Identity since there is a lot of extra information to be loaded from the database and control the number of calls to it

Try following :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;
using System.Xml.Serialization;


namespace ConsoleApplication63
{
    class Program
    {

        static void Main(string[] args)
        {


            Context _context = new Context() {
                UserRoles = new List<UserRole>() {
                    new UserRole() { RoleId = "1", UserId = "1"},
                    new UserRole() { RoleId = "2", UserId = "3"},
                    new UserRole() { RoleId = "3", UserId = "2"},
                    new UserRole() { RoleId = "4", UserId = "4"}
                    },
                Users = new List<User>() {
                    new User() { 
                        Id = "3", UserName = "ABC", Roles = new List<Role> {
                            new Role() { Id = "100", Name = "ABC"},
                            new Role() { Id = "101", Name = "DEF"},
                            new Role() { Id = "102", Name = "GHI"},
                            new Role() { Id = "103", Name = "JKL"},
                            new Role() { Id = "104", Name = "MNO"}
                        }
                    }
                },
                Roles = new List<Role>() {
                    new Role() { Name = "XYZ", Id = "2"}
                }
            };


            string id = "3";
            List<UserRole> results = (from users in _context.UserRoles
                where users.UserId == id
                join  user in  _context.Users  on users.UserId equals user.Id
                join role in _context.Roles on users.RoleId  equals role.Id
                select   new  { Roles = user.Roles, UserId = user.Id})
                .Select(x => x.Roles.Select(y => new UserRole() { RoleId = y.Id, UserId = x.UserId}).ToList()).FirstOrDefault();
        }


    }
    public class Context
    {
        public List<User> Users { get; set; }
        public List<Role> Roles{ get; set; }
        public List<UserRole> UserRoles{ get; set; }
    }
    public class UserRole
    {
        public string UserId { get; set; }
        public string RoleId { get; set; }
    }
    public class User {
       public string Id { get; set; }
       public string UserName { get; set; }
       public List<Role> Roles { get; set; }
    }


    public class Role {
       public string Id {get; set; }
       public string Name { get; set; }
    }



}

I think you need to use GroupBy to group your result and use an appropriate projection for the Roles collection. Considering your initial query, you could do the following (I am using the fluent syntax, you can convert it to query syntax):

var initialQuery = from users in _context.Users
            where users.Id == id
            join userRoles in _context.UserRoles on users.Id equals userRoles.UserId
            join roles in _context.Roles on userRoles.RoleId equals roles.Id
            select new
            {
                UserID = users.Id,
                UserName = users.UserName,
                RoleID = roles.Id,
                RoleName = roles.Name
            };

IEnumerable<User> result = initialQuery
                .GroupBy(x => new { x.UserID, x.UserName })
                .Select(x => new User
                {
                    Id = x.Key.UserID,
                    UserName = x.Key.UserName,
                    Roles = x.Select(a => new Role { Id = a.RoleID, Name = a.RoleName }).ToList() as ICollection<Role>
                });

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM