Select all users that have commented post in ASP.NET MVC - c#

I am having a trouble with LINQ query for sort of a complicated selection.
I am trying to create simply social network, where user can post posts and other users can comment on them.
For some statistic I want to find out who are the user who left comments on all posts of currently logged on user.
This are the tasks I am trying to preform:
Find currently logged on user.
Get all other registered user (except currently logged on).
Get all comments on all posts that currently logged on user has.
Since every comment has UserId which presents ID of a user who has left the comment, I want to compare this UserIds with all other registered users and get list of users who were commenting to currently logged on user.
It sound bit complicated, but it is not actually.
This is my code:
public ActionResult ListAllUsersThatCommentedPostsToCurrentUser()
{
ApplicationDbContext db = new ApplicationDbContext();
//Get ID from current user
var currentUserId = User.Identity.GetUserId();
var user = db.Users.SingleOrDefault(x => x.Id == currentUserId);
var comments = new List<Comment>();
if (user != null)
{
//Get all posts of current user
var postsOfCurrentUser = db.Posts.Where(x => x.UserId == user.Id).ToList();
foreach (var post in postsOfCurrentUser)
{
//Get all comments on posts which belong to current user
comments = db.Comments.Where(x => x.PostId == post.PostId).ToList();
}
}
var usersThatCommentedPosts = new List<ApplicationUser>();
if (comments != null)
{
//Get all user except current one
var otherUsers = db.Users.Where(u => u.Id != currentUserId).ToList();
foreach(var comment in comments)
{
//Filter all users except current one according to UserIds in Comment list
usersThatCommentedPosts = otherUsers.Where(u => u.Id == comment.UserId).ToList();
}
}
return View(usersThatCommentedPosts);
}
The problem is in this line:
usersThatCommentedPosts = otherUsers.Where(u => u.Id == comment.UserId).ToList();
I always get last user how left the comment to current user, instead of list of all users who have left comments.
I guess the problem is in foreach loop, but I have a mess in my head and no idea how can I implement this in a different and more efficient way.
As well, if somebody see something that can be refactored comments are more than welcome, because I have feeling that I have made unnecessary mess here.

you're replacing usersThatCommentedPosts every iteration of that loop. If you want to append to the loop, use AddRange
var users = otherUsers.Where(u => u.Id == comment.UserId).ToList();
usersThatCommentedPosts.AddRange(users );
or better yet, do a join in a proper query. (this way you don't have db queries in a loop)
var userQry =
from post in db.Posts
join comment in db.Comments on post.PostId equals comment.PostId
join otherUser in db.Users on comment.UserId equals otherUser.Id
where post.UserId == currentUserId
where otherUser.Id != currentUserId
select otherUser;
var users = userQry.ToList();

Related

Need help in getting data from multiple table using EF

I am getting details in list format using this query, in that I am also getting user id.
reportProblemsList = objEntities.ReportProblems.ToList();
Now I want to get user details based on that user id from users table. So I have tried with foreach loop as per below.
foreach(var item in reportProblemsList)
{
userdetails = objEntities.Users.Where(x => x.UserId == item.Userid).ToList();
}
Now I want to add this all userdetails in list and then access it. Below is my full code.
List<ReportProblem> reportProblemsList = new List<ReportProblem>();
List<User> userdetails = new List<User>();
reportProblemsList = objEntities.ReportProblems.ToList();
foreach(var item in reportProblemsList)
{
userdetails = objEntities.Users.Where(x => x.UserId == item.Userid).ToList();
}
reportProblemsList.Add(userdetails);
But not able to get it working..any idea.
Thanks
If you database is correctly designed from the given information, there is a high probability that your ReportProblem object has also the property User of type User. If this is the case you can instruct EF core to include such nested properties in your query by doing something like this:
var reportProblemsList = objEntities.ReportProblems
.Include(report => report.User)
.ToList();
If you don't have this property you have to create an anonymous type to hold the tuple:
var reportsWithUsers = objEntities.ReportProblems
.Join(objEntities.Users, r => r.UserId, u => u.UserId, (Report, User) => (Report, User)
.ToList();
I assume that you need a list users who reported the issue.
var userIds = objEntities.ReportProblems.Select(q=> q.Userid).ToList();
List<User> userdetails = objEntities.Users.Where(x => userIds.Contains( x.UserId)).ToList();

Problem with linq2sql Group-By then Where

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));

How to add condition to LINQ query based on Id

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.

How can I join application data with user information in ASP.NET

I am developing my first ever asp.net web application and have run into a problem, which is most certainly related to me being a newbee, but here goes:
I am using Entity Framework 6, mvc 5.1, c#. I have made changes to the user record (ASP.NET Identity) simply by adding a few fields. Now based on a value (OrganizationID) in the user record, I would like to limit data being shown to that of the user's organization. OrganizationID is stored in the Seasons table, but I can't find out why I cannot simply write something along the lines of:
.include(s => s.OrganizationID == currentUser.OrganizationID)
which is commented out below.
Am I doing this totally wrong? I will be needing this over and over in my application, I believe, so getting it right is crucial for me.
Thanks
(the code below runs fine but of course not constrained to the users organization!)
public ActionResult Index(int? id)
{
// my code to get current user record (ASP.NET Identity)
var currentUserId = User.Identity.GetUserId();
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var currentUser = manager.FindById(User.Identity.GetUserId());
//
var viewModel = new SeasonGoals();
viewModel.Seasons = db.Seasons
.Include(g => g.Goals);
// .include(s => s.OrganizationID == currentUser.OrganizationID)
if (id != null)
{
ViewBag.SeasonID = id.Value;
viewModel.Goals = viewModel.Seasons.Where(s => s.ID == id.Value).Single().Goals;
}
return View(viewModel);
}
you need to pass foreign key property in include by which these two classes are linked,try like this:
viewModel.Seasons = db.Seasons
.Include("ForeignKeyPropery")
.Where(s => s.OrganizationID == currentUser.OrganizationID)
or you can write like this:
(from c in db.Seasons.Include(c => c.Goals)
where c.OrganizationID == currentUser.OrganizationID
select c)

Get user email in mvc

I have written some dirty code that retrieves user email in MVC. As you can see I´m using linq queries to retrieve info from my user database.
List<string> emails = new List<string> {ConstantHelper.AdminEmail, ConstantHelper.OwnerEmail};
DataContext mDataContext = new DataContext();
User user =
(from allUsers in mDataContext.Users.Where(u => u.UserName == User.Identity.Name)
select allUsers).FirstOrDefault();
string userEmail =
(from allMemberships in mDataContext.Memberships.Where(u => user != null && u.UserId == user.UserId)
select allMemberships.Email).FirstOrDefault();
if(userEmail == null)
{
return false;
}
emails.Add(userEmail);
//TODO: senda email
What I want to know if there is any other "shorter" or cleaner way to retrieve user email (of the user who is currently logged in)?
I googled this and found some suggestions regarding this code but I never got that to work for me.
MembershipUser u = Membership.GetUser(username);
My code works, it´s just that I would rather have cleaner code with this, any suggestions would be well appreciated :)
MembershipUser u = Membership.GetUser(username); is definitely a much better and shorter way to achieve that. You just need to write a custom membership provider to replace the default one in order to be able to customize the behavior of the GetUser and other methods to suit your needs.

Categories

Resources