So i can access the User table, but i need to do a further query within my linq statement to check to see if they have been added into a particular user role
var managers = (from a in db.Users
join b in db.**UserRoles** on a.Id equals b.Id
where a.IsManager == true select a).ToList();
I know you can access it via the html using User.IsInRole, but i really need to access it via my DB call
any help would be great
Given that you are using asp.net identity with code-first approach? you can access the users or Roles tables individually (db.Users/db.Roles). If you want to access roles for a user you could do db.Users.Roles. However, this would only return id's for your roles (there are no navigationproperty from here..)
To check for users in role by role-name, you could join user.Roles with db.Roles, and check the role name from db.Roles. Something like this:
using (var db = new ApplicationDbContext())
{
var user1 = new ApplicationUser { Email = "user1#test.com", UserName = "User #1"};
var user2 = new ApplicationUser { Email = "user2#test.com", UserName = "User #2 - No Roles" };
var role1 = new IdentityRole("SomeRole");
db.Users.Add(user1);
db.Users.Add(user2);
db.Roles.Add(role1);
db.SaveChanges();
user1.Roles.Add(new IdentityUserRole { RoleId = role1.Id });
db.SaveChanges();
var usersInRole = db.Users.Where(u =>
u.Roles.Join(db.Roles, usrRole => usrRole.RoleId,
role => role.Id, (usrRole, role) => role).Any(r => r.Name.Equals("SomeRole"))).ToList();}
Alternatively you could first fetch the Role and then check
var usersinRole = db.Users.Where(u => u.Roles.Any(r => r.RoleId.Equals(someRoleId)));
Depending on which version of you are using you should have some tables like this:
You will need to join to the users in roles table and the roles table.
Related
How can I get the identity users with their multiple assigned roles, I want the user's name and a list of roles to be seen, i am using blazor wasm and aspnet core.
so far I have this, but I don't know if I'm on the right track or there are other alternatives instead of using projection:
var listado = await (from user in context.Users
join userRoles in context.UserRoles on user.Id equals userRoles.UserId
join role in context.Roles on userRoles.RoleId equals role.Id
select new { UserId = user.Id, UserName = user.UserName, RoleId = role.Id, RoleName = role.Name })
.ToListAsync();
With this code I get that each user is assigned their roles, but a user has more than one role and generates it for me 3 times, when I want the user to be generated once with his list of roles
Widely answered here: Group by in LINQ.
Check Jon Skeet's answer. Your roles would be the cars in that example.
This works:
var query = (from user in _context.Users
join role in _context.UserRoles on user.UserID equals role.UserId
where user.Username == username
select role.Role).ToArray();
How do I do the same in the method syntax?
//here role.Role has multiple values
var query2 = _context.Users.Join(_context.UserRoles, u=>u.UserID,ur=>ur.UserId,
(u,ur)=> new { ur.Role }).ToArray();
The above code throws an error:
Cannot implicitly convert type<anonymous // type string Role>[] to 'string[]'
Better to stay with LINQ query syntax which is closer to the SQL and you can easily modify your query. Anyway here is your translation:
var query2 = _context.Users
.Where(u => u.Username == username)
.Join(_context.UserRoles, u => u.UserID, ur => ur.UserId, (u,ur) => ur.Role)
.ToArray();
So you have Users and UserRoles. There is a one-to-many relation between Users and UserRoles: every User has zero or more UserRoles; every UseRole belongs to exactly one User, namely the User that the foreign key UserId refers to.
You also have a UserName, and you want all Users that have this name, each User with its UserRoles.
Note: you didn't say that UserName is unique, so It can be, that after the Where you still have several Users with userName "Will Smith".
Short answer
string userName = "Will Smith";
var result = dbContext.Users
.Where(user => user.UserName == userName)
.Join(dbContext.UserRoles,
user => user.Id, // from each User take the Id
userRole => userRole.UserId, // from each UserRole take the foreign key
(user, userRole) => userRole);
Or the other way round: start at UserRoles and keep only those UserRoles that have aUser with userName:
dbContext.UserRoles.Where (userRole =>
dbContext.Users
.Where(user => user.Id == userRole.UserId // get the User of this Role
&& user.UserName == userName) // check the name of this User
.Any() );
There's room for improvement
If user [10] has 20 UserRoles, then every UserRole of User [10] will have a foreign key with a value 10. You will be transferring this value 20 times.
If there are several "Will Smith", you will have one big sequence with all the UserRoles of all "Will Smiths" randomly mixed.
Your solution will result in:
UserId UserRole
10 Administator,
10 User
25 Backup
10 Backup
18 User
25 User
Wouldn't it be more efficient to group the User, so you have something like:
UserId UserRoles
10 { Administator, User, Backup }
18 { User }
25 { User, Backup }
22 <no UserRoles yet>
Note: the result is slightly different: you also get the Users that have no role yet.
Whenever you have items with their zero or more subitems, like Schools with their Students, Customers with their Orders, or Users with their UserRoles, consider to use one of the overloads of Queryable.GroupJoin.
Most of the times I use the overload with a parameter resultSelector. This way you can specify exactly which properties you want, and in what format:
var usersWithTheirUserRoles = dbContext.Users
// keep only the users with a specific UserName
.Where(user => user.UserName == userName)
// fetch some properties of the remaining users and their UserRoles
.GroupJoin(dbContext.UserRoles,
user => user.Id, // from each User take the Id
userRole => userRole.UserId, // from each UserRole take the foreign key
// parameter resultSelector: take each user, with its zero or more userRoles
// to make one new:
(user, userRolesOfThisUser) => new
{
// Select only the user parameters that you plan to use:
Id = user.Id,
Address = user.Address,
...
// select the zero or more user roles of this user
UserRoles = userRolesOfThisUser.Select(userRole => new
{
// Select only the properties that you plan to use
Id = userRole.Id,
Description = userRole.Description,
...
// not needed, you've already got the value:
// UserId = userRole.UserId,
})
.ToList(),
});
Advantages:
You also get the Users that have no UserRoles yet (in your original requirement not a problem)
Efficiency: Every property of a User is sent only once. An inner join, or left outer join would send the same properties of the User over and over again
Efficiency: You transfer only the properties that you really need
You can deviate from your original tables. If you want to leave out UserRoles, or calculate some properties, like UserRoleCount you can just do it. This makes it easier to change your database tables in the future, without changing this query
Let Users be a database containing typical users data (name, email...) with an ID as primary key.
Let Applications be a database storing a list of applications (name, developer...) with an ID as primary key.
Let UsersApps be the mapping table between the two, using the primary key. UsersApps thus stores rows of ..., {102, user1_Id, appA_Id}, {103, userN_ID, appB_Id}, {104, user1_Id, appC_Id}, ...
And so on.
I want to retrieve a list of users data {name, email, List<Application> boughtApps}
I am struggling to find a LINQ request to do that and I am trying to do it in two steps, get a big table and then build each user's list of applications.
var q1 = from user in _dbContext.Users
join appUti in _dbContext.AppUsers on user.Id equals appUti.UsersId
join app in _dbContext.Applications on appUti.ApplicationId equals app.Id
orderby user.Id
select new UserDataWithApp { Id = user.Id, Name = user.Name, firstName= user.FirstName, Email = user.Email, App = app };
Then parse q1.toList() to build my required results list.
var qRes = q1.ToList();
int i = 0;
int j = 0;
while (i<qRes.Count())
{
listUsersWithApps[j] = qRes[i];
while (qRes[i].Id == listUsersWithApps[j].Id) // llist is ordered !!
{
listUsersWithApps[j].Apps.Add(qRes[i].Apps[0]);
i++;
}
j++;
}
Isn't there a better way ?
You can use navigation properties to allow the following:
var userApps = context.Users.Select(u => new UserWithApp(u.Name, u.Email, u.Applications))
Just add to following to User:
public virtual ICollection<Application> Applications { get; set; }
and to Application:
public virtual ICollection<Users> Users { get; set; }
So you can "navigate" between your entities and write to following query (just adapt your ordering and what user data to be seleted):
var userApps = from user in context.Users
select new UserDataWithApp { ..., BoughtApps = user.Applications }
See here for an example: http://www.entityframeworktutorial.net/code-first/configure-many-to-many-relationship-in-code-first.aspx
or another interesting blog: https://lostechies.com/jimmybogard/2014/03/12/avoid-many-to-many-mappings-in-orms/
I literally have no idea why this isn't querying the way I expect it to query, I am however new to programming but in my head it seems right.
I am using this.Context.User.Identity.Name to return the logged in user however it returns an email not the username. Here is the script in it's context.
#Html.ActionLink("My Account", "Users", new { id = this.Context.User.Identity.Name }, false) #: | #Html.ActionLink("Logout", "Logout", "Users")
from this I want the url to look like website/Users/Username hence wanting to get username instead of email.
The query:
Project1.Models.DBContext db = new Project1.Models.DBContext();
//save u.Username in var user where u.Email == user_logged_in_email
var user = from u in db.Users
where u.Email == this.Context.User.Identity.Name
select u.Username;
I was hoping that the linq query would find the row that contained the email address and then pull the Username out and store it in var user. what it really equals is System.Data.Entity.Infrastructure.DbQuery
You need to enumerate that query to get the user:
var user = (from u in db.Users
where u.Email == this.Context.User.Identity.Name
select u.Username).SingleOrDefault();
//SingleOrDefault will return null if no user is found, so you need to check for that before operating upon the user object.
I have an API written in .NET 4.5 using Entity Framework. Here is what one of the methods looks like:
private myEntities db = new myEntities();
// GET api/User
public IEnumerable<User> GetUsers()
{
return from u in db.Users
select u;
}
Pretty simple. This table can join with a Roles table, so a User can have many Roles. The foreign key UserId is in the Roles table. Here's what I'm trying to do:
private myEntities db = new myEntities();
// GET api/User
public IEnumerable<User> GetUsers()
{
return from u in db.Users
join r in db.Roles on u.UserId equals r.UserId
select new User
{
UserId = u.UserId,
Roles = u.Roles
};
}
This throws an error: The entity or complex type 'ppadModel.User' cannot be constructed in a LINQ to Entities query
How do I write a query that returns the User and all the Roles associated with that user?
You use the .Include extension method.
Like this:
return from u in db.Users.Include("Roles")
select u;
You can also use lamba expression to avoid strings:
return from u in db.Users.Include(x => x.Roles)
select u;
This tells the Entity Framework to load all users and additional all associated roles for the users.