I have a table Users. Users has a column rating. How i can get information about user place using linq2sql? I want method like:
var userPlace =
GetUserPlaceById(userId);
Table Users may contains a few thousands users.
Sorry guys. Users DOESNT contain place column. Real example: Rating is chess elo rating. if you have high rating then you on 1st place. If you have lower rating then you on the last place.
Did you mean something like this?
int userRating = users.Single(user => user.Id = userId).Rating;
int userPlace = users.Where(user => user.Rating < userRating).Count() + 1;
I have a table Users. Users has a column rating. How i can get information about user place using linq2sql?
I'm not sure what "userPlace" is, but assuming it is a column in that table...
var userPlace = (from user in db.Users
where user.Id == userId
select user)
.First()
.UserPlace;
Be aware that calling .First() will throw an exception if no match is found, so if you expect that sometimes this user will not exist use FirstOrDefault, check for null, and then grab the UserPlace property.
You would use something like:
string GetUserPlaceById(int userId)
{
IQueryable<User> users = GetUsers(); // Get users queryable reference
return users.Single(user => user.Id == userId).Place;
}
You could do something like this:
var userPlace = _db.Users.Where(x => x.UserId == userId).Select(x => x.Place).SingleOrDefault();
Related
I'm trying to get the user records that do NOT have the current role. A user can have multiple roles.
I'm working with 2 tables - Users and UserRoleMap
var superAdminRoleId = *GUID*
var query = from user in _userRepository.Table
join userRoleMap in _userRoleMapRepository.Table
on user.Id equals userRoleMap.UserId
// Now, group the roles by the user
group userRoleMap by user into userRoleMaps
// get the records that are NOT super admin
where !userRoleMaps.Any(map=>map.UserId == superAdminRoleId)
select userRoleMaps.Key;
I'm getting the error
LinqToDB.LinqToDBException: ''map.UserId' cannot be converted to SQL.'
So I revised it to
var query = from user in _userRepository.Table
join userRoleMap in _userRoleMapRepository.Table
on user.Id equals userRoleMap.UserId
// Now, group the roles by the user
group userRoleMap.UserId by user into userRoleMaps // changed userRoleMap to userRoleMap.UserId
// get the records that are NOT super admin
where !userRoleMaps.Any(map=>map == superAdminRoleId) // update
select userRoleMaps.Key;
Now, I'm getting
System.ArgumentException: 'Property 'System.Guid Id' is not defined for type 'System.Guid' (Parameter 'property')'
There's probably a way to fix your group by, but looking at what it seems you're trying to accomplish I think you'll get a better-performing and simpler query like this:
var userRoleMaps = _userRoleMapRepository.Table;
var nonAdminUsers = _userRepository.Table
.Where(user => !userRoleMaps
.Any(map => map.UserId == user.Id && map.RoleId == superAdminRoleId));
This is an add-on question to one asked here: Entity Framework Core 5.0 How to convert LINQ for many-to-many join to use Intersection table for ASP.NET Membership
How can I return the results of an the following LINQ IQueryable result, which is from two join tables, for the RoleName column to a List<string>?
var queryResult = (this.DbContext.aspnet_UsersInRoles
.Where(x => x.UserId == dpass.UserId)
.Join(
this.DbContext.aspnet_Roles,
ur => ur.RoleId,
r => r.RoleId,
(ur, role) => new
{
ur,
role
}
)
.Select(x => new { x.ur.UserId, x.role.RoleName })
);
UPDATE 1
I need the List in the form of an array of values so that I can use the Contains() method. I need to search for specific RoleNames assigned to a UserId. If I use ToList() on the IQueryable, then the array result is in the form of:
{ RoleName = "admin"}
{ Rolename = "user"}
I am unable to use the .Contains() method because I get the following error:
cannot convert from 'string' to <anonymous type: string RoleName>.
It seems be to expecting a class that the query result can be assigned to. But, one doesn't exist because I am doing this on-the-fly.
UPDATE 2
I need the queryResult in a List that is in the form of:
{ "admin"}
{ "user"}
With this output, I can use the .Contains() method to perform multiple checks. This is used for determining Windows Forms field properties. So, if the UserId belongs to the admin role then the form enables certain check boxes and radio buttons whereas if the UserId belongs to the user role then the form enables different check boxes. This is not an exhaustive list of roles available along with the checks that are performed by the form. But, what is important is that there are multiple checks on the List that need to be performed in separate IF statements.
Currently, I am able to use the queryResult to do the following:
Get a list of the RoleNames
Perform separate LINQ queries on the queryResult by checking for the specific RoleName
Perform a .Count() > 0 check to see if the UserId is in a specific role.
This seems like an ugly hack because I have the intermediate step of creating 1 + N variables to retrieve, by LINQ, and store each RoleName and then check to see if the .Count() is greater than zero. I think that the List method would be cleaner and more efficient. If that is possible.
var varUser = from d in queryResult
where d.RoleName == "user"
select new { d.RoleName };
var varAdmin = from u in queryResult
where u.RoleName == "admin"
select new { u.RoleName };
//... more declarations and LINQs ...
Short answer:
Select only the RoleName, and use SelectMany instead of Select
Better answer
So you have a table of Roles, and a table of Users (I'm simplifying your long identifiers, not part of the problem and way too much typing).
There seems to be a many to many relation between Roles and Users: Every Role is a role for zero or more Users, every User has zero or more Roles.
This many-to-many relation is implemented using a standard junction table: UsersInRoles. This junction table has two foreign keys: one to the User and one to the Roles.
You have a UserId, and it seems that you want all names of all Roles of the user that has this Id.
How about this:
int userId = ...
// Get the names of all Roles of the User with this Id
var namesOfRolesOfThisUser = dbContext.UsersInRoles
// only the user with this Id:
.Where(userInRole => userInRole.UserId == userId)
// get the names of all Roles for this userInRole
.SelectMany(userInRole => dbContext.Roles.Where(role => role.RoleId == userInRole.RoleId)
.Select(role => role.RoleName));
In words: from the table of UsersInRoles, keep only those UsersInRoles that have a value for property UserId that equals userId.
From every one of the remaining UsersInRoles, select all Roles that have a RoleId that equeals the UserInRole.RoleId. From these Roles take the RoleName.
I use SelectMany to make sure that I get one sequence of strings, instead of a sequence of sequences of strings.
If you suspect double RoleNames, consider to append Distinct() at the end.
But I want to Join!
Some people really like to do the joins themselves.
int userId = ...
var namesOfRolesOfThisUser = dbContext.UsersInRoles
.Where(userInRole => userInRole.UserId == userId)
.Join(dbContext.Roles,
userInRole => userInRole.RoleId, // from every UserInRole take the foreign key
role => role.RoleId, // from every Role take the primary key
// when they match, take only the name of the Role
(userInRole, role) => role.RoleName);
Try to use GroupBy(). Be careful, this method is not supported by direct IQueryable to SQL conversion. If you will try to call GroupBy() before .ToList(), it will throw an error.
In your example you could this: select a list in memory and then work with it:
var queryResult = (this.DbContext.aspnet_UsersInRoles
.Where(x => x.UserId == dpass.UserId)
.Join(this.DbContext.aspnet_Roles,
ur => ur.RoleId,
r => r.RoleId,
(ur, role) => new { ur, role }
)
.Select(x => new { x.ur.UserId, x.role.RoleName })
.ToList() // MATERIALIZE FIRST
.GroupBy(x => x.UserId) //ADD THIS
);
queryResult.Contains(roleName=> roleName == "ROLE_TO_SEARCH")
var userId = queryResult.Key;
I have a Mysqlcontext from which im doing queries. However, i dont know how these queries work, since i normally do the standard calls e.g. "select from where".
These are slightly different, and in this case i try to fetch an id from my db.Users. Unfortunately, it cant write my UserId to a variable?
var id = db.Users.Where(u => u.Email == email).Select(u => u.UserId);
it just returns null. How is this done correctly, and where can i find more documentation on how these queries work?
This is my updated code:
var id = db.Users.Where(u => u.Email == email).Select(u => u.UserId);
var materializeId = id.ToList();
int UserId = materializeId[0];
This actually seems to be working. Im however still confused that i have to fetch my item from a list, when there is only 1 matching ID? (There will be in all cases)
Cant i somehow query just a single id and write it to an int variable?
I would do something like this:
var userId = (from u in db.Users
where u.Email == email
select u.Id).FirstOrDefault();
This is my action method which fetches all the users with their Id.
public JsonResult GetUsers()
{
var ret = (from user in db.Users.ToList()
select new
{
UserName = user.UserName,
// i am stuck here, i want to get all those ids whom current logged user is following
Idfollowing = user.FollowTables.Contains()
Idnotfollowing =
});
return Json(ret, JsonRequestBehavior.AllowGet);
}
the structure of FollowTable is like this:
ID UserId FollowId
1 4 11
2 4 12
2 4 13
here, current loggedin user's id is 4 and he is following 11, 12, 13 so i want to return only 11, 12 and 13 to Idfollowing and rest remaining id in the Idnotfollowing. how to get it done.
Well, i think with list or array, i will not get desired result. so, i want to add something here.
Well, with every UserName an id is also passed to view page. So, i have break them into two.Now, how to assign values to these ids.
Comapre User.Id with Current loggedin user's follow table's followId column.If match is found .i.e if id matches or found then assign that user.Id to Idfollowing and null to Idnotfollowing and vice versa in opposite case.
I have to generate follow unfollow button based on these ids returned.
public JsonResult GetUsers()
{
int currentUserId = this.User.Identity.GetUserId<int>();
var ret = (from user in db.Users.ToList()
let Id = user.FollowTables.Where(x => x.UserId == currentUserId).Select(f => f.FollowId).ToList()
let Idnot = (from user2 in db.Users
where !Id.Contains(user2.Id)
select user2.Id).ToList()
select new
{
UserName = user.UserName,
Id = Id,
//Id = user.FollowTables.Where(x => x.UserId == currentUserId)
// .Select(x => x.FollowId).Single(),
Idnot = Idnot,
It looks like you have a standard one-to-many relationship from User to FollowTable. This data model enforces that user.FollowTables only contains followers. You won't be able to fill in Idnotfollowing from the FollowTables property directly.
Something like this may work:
var query = (
from user in db.Users // note: removed ToList() here
// to avoid premature query materialization
where //TODO ADD WHERE CLAUSE HERE ?
let followIds = user.FollowTables.Select(f => f.FollowId)
let notFollowIds = (from user2 in db.Users
where !followIds.Contains(user2.Id)
select user2.Id)
select new
{
UserName = user.UserName,
Idfollowing = followIds.ToArray(),
Idnotfollowing = notFollowIds.ToArray()
})
// TODO add paging? .Skip(offset).Take(pageSize)
.ToList();
Do verify the SQL generated by this query and make sure it performs ok though...
Also, note that I removed the .ToList() from db.Users.ToList() to avoid premature query materialization. It is generally a bad idea anyway to extract all data from a table unconstrained, you will typically want to a
var ret = (from user in db.Users.ToList()
select new
{
UserName = user.UserName,
Idfollowing = user.FollowTables.Select(x=> x.Id)
Idnotfollowing = db.FollowTables.Where(x=> !user.FollowTables.Select(x=> x.Id).Contains(x.Id)).Select(x=> x.Id)
});
it's ugly but will work, there must be another better way to do.
You can simply use a Where method to filter the table and use Select to project FollowiId:-
var ret = (from user in db.Users.ToList()
select new
{
UserName = user.UserName,
Idfollowing = user.FollowTables.Where(x => x.UserId == user.Id)
.Select(x => x.FollowId).ToArray(),
Idnotfollowing = user.FollowTables.Where(x => x.UserId != user.Id)
.Select(x => x.FollowId).ToArray()
});
Assuming, Idfollowing & Idnotfollowing are array if integers (if FollowId is integer) otherwise you can replace it with ToList if its a list instead.
I have a collection lets call it 'Users', aka a set of USER
A USER has a set of CONTACTs.
I simply want to get all CONTACTs for a given user in common with another user.
I'm learning about Lambda/Linq expressions but not sure if thats what I should be doing to solve this sort of collection filtering problem.
So really I'm just looking for a intersection of 2 sets.
You can't simply do "==" on two collections. However, if the contacts have some kind of id and a user can't have the same contact twice, this is pretty easy to do:
User user = ...
var contactIds = user.Contacts.Select(c => c.Id).ToArray();
var usersWithMatchingContacts = this.unitOfWork.UserRepository.Get()
// basically, we're checking that the number of matching contacts is the same as the
// total number of contacts for the user, which means that the user has the same
// set of contacts. If you just want to require some overlap, change
// the "== u.Contacts.Count" to "> 0"
.Where(u => u.Contacts.Count(c => contactIds.Contains(c.Id)) == u.Contacts.Count);
//input data
var firstId = 12;
var secondId = 23;
var firstUser = users.First(user => user.Id == firstId);
var secondUser = users.First(user => user.Id == secondId);
var commonContacts = firstUser.Contacts
.Where(contact =>
secondUser.Contacts.Contains(contact))
Use LINQs Intersect method
var commonContacts = firstUser.Contacts.Intersect(secondUser.Contacts)