简体   繁体   中英

Cant use Linq WHERE/IN/JOIN with Entity Framework on many to many

I can do this very simply in SQL, but trying to learn how to do this in Linq using Entity Framework.

I have a User, a User can have multiple Groups, and a group can have multiple Permissions.

I would like to get all the permissions for a user.

I have the following DbSets in my DbContext

public virtual DbSet<User> Users { get; set; }
public virtual DbSet<Group> Groups { get; set; }
public virtual DbSet<Permission> Permissions { get; set; }

And there classes are like so

public class User : Entity, IUser<long>
{
    public string UserName { get; set; }

    public string PasswordHash { get; set; }

    public User()
        : base()
    {
        this.Groups = new HashSet<UserGroup>();
    }

    public virtual ICollection<UserGroup> Groups { get; set; }
}

public class Group : AuditableEntity
{
    public Group() {
        this.Permissions = new HashSet<GroupPermission>();            
    }

    public string Name { get; set; }

    public virtual ICollection<GroupPermission> Permissions { get; set; }
}

public class Permission 
{
    public string Name { get; set; }

    public Permission()
    {

    }
}

To cope with the many to many relationships, i also have these classes

public class UserGroup
{

    public long UserId { get; set; }
    public long GroupId { get; set; }

    public virtual User User { get; set; }
    public virtual Group Group { get; set; }

}

public class GroupPermission
{
    public long PermissionId { get; set; }
    public long GroupId { get; set; }

    public virtual Permission Permission { get; set; }
    public virtual Group Group { get; set; }
}

Now in SQL i would simply do

SELECT Permission.* 
FROM Permission
    INNER JOIN PermissionGroup ON Permission.Id = PermissionGroup.PermissionId
    INNER JOIN Group ON PermissionGroup.GroupId = Group.Id
    INNER JOIN UserGroup ON Group.Id = UserGroup.GroupId
WHERE UserGroup.UserId = @UserId

Can someone please tell me why i cant do this in LINQ? Well i know i can, but i cannot figure out how.

EDIT

context.PermissionGroup and context.UserGroup are not DbSets in my context.

List<Permission> result;
using(DataContext context = new DataContext())
{
   result = (from permission in context.Permissions
             join permissionGroup in context.PermissionGroup on permission.Id equals permissionGroup.Id
             join g in context.Groups on permissionGroup.GroupId equals g.Id
             join userGroup in context.UserGroup on g.Id equals userGroup.GroupId
             where userGroup.UserId == user.Id 
             select permission).ToList();
}

use this

var linqQuery=(from p in Permission
                    join pg in PermissionGroup on p.Id equals pg.Id
                    join g in Group on pg.GroupId equals g.Id
                    join ug in UserGroup on g.Id equals ug.GroupId
                    where ug.UserId == USERID 
                    select p);

If you have your own DbContext class where all your database tables are represented as DbSets

public partial class OwnContext: DbContext
{
   public DbSet<User> Users { get; set; }
   public DbSet<Group> Groups { get; set; }
   public DbSet<Permission> Permissions { get; set; }
   public DbSet<UserGroup> UserGroups { get; set; }
   public DbSet<PermissionGroup> PermissionGroups { get; set; }
}

you have to create an instance of that class with a using statement and execute your query in the using statement .

List<Permission> result;
using(OwnContext context = new OwnContext())
{
   result = (from permission in context.Permissions
             join permissionGroup in context.PermissionGroups on permission.Id equals permissionGroup.Id
             join group in context.Groups on permissionGroup.GroupId equals group.Id
             join userGroup in context.UserGroups on group.Id equals userGroup.GroupId
             where userGroup.UserId == user.Id 
             select permission).ToList();
}

Joining in SQL doesn't automatically mean that you should join in LINQ. Use navigation properties whenever possible. Your case becomes much simpler if you do that, and use SelectMany for this:

from u in db.Users
select new { 
             u.UserName,
             Permissions = u.Groups
                            .Select(ug => ug.Group)
                            .SelectMany(g => g.Permissions)
                            .Select(gp => gp.Permission
           }
using (var context = new NombreDeEntityDataModel)
{
    var query = from a in context.Permission
                join b in context.PermissionGroup on a.id equals b.PermissionId
                join c in context.Group on b.GroupId equals c.id
                join d in context.UserGroup on c.id equals d.GroupId
                where d.UserId = @UserId
                select a;
}

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