Reputation: 74
I have 3 tables: Users, Roles and an intermediate table UsersRoles. how can I Order the users according to their Role names?
public List<USERS> Find(UserFilter filter, string sortExpression, int maxRows, int startIndex)
{
var query = db.USERS.Include("ROLES").AsQueryable();
query = ApplyFilter(query, filter);
query = query.OrderBy(sortExpression);
query = ApplyPaging(query, maxRows, startIndex);
var result = query.ToList();
return result;
}
private IQueryable<USERS> ApplyOrder(IQueryable<USERS> query, UserFilter filter)
{
// what should I do here to sort/group according to role name ?
}
private IQueryable<USERS> ApplyFilter(IQueryable<USERS> query, UserFilter filter)
{
if (!string.IsNullOrEmpty(filter.UserName))
query = query.Where(u => u.USERNAME == filter.UserName);
}
private IQueryable<USERS> ApplyPaging(IQueryable<USERS> query, int maxRows, int startIndex)
{
var result = query;
if (maxRows != 0)
result = query.Skip(startIndex).Take(maxRows);
return result;
}
I'm calling Find method from the controller and I'm using AsQueryable so how can I group the users according to their Roles (the roles should be sorted according to role name)? what should I write in ApplyOrder method?
Upvotes: 0
Views: 44
Reputation: 30464
Consider the following example:
var users = new user[]
{
new user()
{
Name = "Jan",
Roles = new Role[]
{
new Role() {Name = "Supervisor},
new Role() {Name = "Teacher"},
}
},
new user()
{
Name = "Pierre",
Roles = new Role[]
{
new Role() {Name = "Student"},
new Role() {Name = "Scholar"},
}
}
}
how can I Order the users according to their Role names?
What do you mean? Do you want users with Roles, where Roles are ordered by name? Or do you want Roles ordered by name with their users?
Anyway, if you've followed the entity framework code first conventions your classes for the many-to-many will be similar to the following:
class User
{
public int Id {get; set;}
public string Name {get; set;}
// every User has zero or more Roles (many-to-many)
public virtual ICollection<Role> Roles {get; set;}
}
class Role
{
public int Id {get; set;}
public string Name {get; set;}
// every Role has zero or more Users (many-to-many)
public virtual ICollection<User> Users {get; set;}
}
class MyDbcontext : DbContext
{
public DbSet<User> Users {get; set;}
public DbSet<Role> Roles {get; set;}
}
In entity framework the columns of the tables are represented by non-virtual properties. The virtual properties represent the relations between tables.
This is enough for entity framework to detect that you intended a many-to-many relationship. Entity framework will create the junction table for you, and use this table when needed.
It might be that you want other names for tables and columns, in that case you'll need fluent API or attributes. The classes however will be similar.
Get Users with their Roles ordered by Name
var result = dbContext.Users
.Where(user => ...) // only if you don't want all Users
.Select(user => new
{
// select only the properties that you plan to use
Id = user.Id,
Name = user.Name,
Roles = user.Roles
.Where(role => ...) // only if you don't want all Roles
.OrderBy(role => role.Name)
.Select(role => new
{ // again: select only the properties you plan to use
Id = role.Id,
Name = role.Name,
})
.ToList(),
});
One of the slower parts of a query is the transport of the selected data to your local process. Hence it is wise not to select more data than you actually plan to use. If you use include
to fetch the data you select all properties of the class, inclusive the foreign keys.
For example, if you fetch Teacher with Id 4, with all his Students, you know that every one of his 1000 Students
will have a foreign key TeacherId
with a value 4. What a waste to transport all these foreign keys!
Advice: when querying data use
Select
to select the properties you actually plan to use. Only useInclude
if you plan to change the included object
Upvotes: 1