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.
Related
I am currently using a linq and accessing some meta data using a for loop:
public SignUpMeta GetSignUpMeta(User user)
{
var users = (from u in User
where user.Email == u.Email || user.UserName == u.UserName
select u);
var result = new SignUpMeta();
foreach (var u in users)
{
if (user.Email == u.Email) result.IsDuplicateEmail = true;
if (user.UserName == u.UserName) result.IsDuplicateUserName = true;
}
return result;
}
Is there any way for the Linq to generate the SignUpMeta directly?
This function is inside the DBContext class and I am looking for a way to get the exact data directly from the db (without raw sql).
Update:
The User is DbSet and the whole code runs inside the db context class. I am trying to write something that will make EF fetch the value directly in a single query.
Update 2:
The SQL equivalent of what I am looking for would be:
SELECT MAX(username), MAX(email)
(SELECT CAST((UserName = #user) AS bit) username,
CAST((Email = #email) AS bit) email
FROM User WHERE UserName = #user OR Email = #email)
Update 3:
SignUpMeta object that needs to be fetched contains the metadata that provides information required for server side validation.
The above C# code runs a query that fetches up to two columns in this instance. When there are more such conditions, there would be more lines. I am trying to find a way that EF would give only the two booleans alone in a single record.
This'll be my try, if you truly must use LINQ:
from u in stuff.Users
group u by 0 into grp
select new
{
IsDuplicateEmail = grp.Any(x => x.Email == user.Email),
IsDuplicateUserName = grp.Any(x => x.UserName == user.UserName)
}
Entity Framework will translate that into sub-selects. If you're using SQL Server and have both columns indexed, this should result in the same amount of I/O as your sample SQL.
I don't believe there is any query that will generate your desired sample SQL.
I think this will be the fastest query:
public SignUpMeta GetSignUpMeta(User user)
{
return new SignUpMeta()
{
IsDuplicateEmail = User.Where(u => u.Email == user.Email).Take(1).Any(),
IsDuplicateUserName = User.Where(u => u.UserName == user.UserName).Take(1).Any(),
};
}
Caching on the DB server should make the two queries quite fast.
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();
I've read nearly every post with a code example in the LinqToTwitter documentation.
I want to get the UserID or the User's ScreenName to make a call like this for the user who is logged in.
var friendList =
await
(from friend in twitterCtx.Friendship
where friend.Type == FriendshipType.FriendIDs &&
friend.ScreenName == "JoeMayo"
select friend)
.SingleOrDefaultAsync();
But all I can find are queries like above who have a hardcoded string for ScreenName.
Where can I get my own ScreenName/UserID out of the twitterCtx?
Cheers,
Chris
When you first authorize, the ScreenName and UserID of the IAuthorizer will be populated:
var credentials = auth.CredentialStore;
string oauthToken = credentials.OAuthToken;
string oauthTokenSecret = credentials.OAuthTokenSecret;
string screenName = credentials.ScreenName;
ulong userID = credentials.UserID;
If you're pre-loading all 4 credentials, LINQ to Twitter short-circuits to save time, bandwidth, and user annoyance by not going through the authorization process again. The side-effect is that you don't get the ScreenName and UserID, because those are a product of authorization. So, if you save someone's keys after initial authorization, so you can use them again on subsequent queries, then grab ScreenName and UserID at that time too.
Of course you have another way to obtain ScreenName and UserID. You can do a VerifyCredentials query, like this:
try
{
var verifyResponse =
await
(from acct in twitterCtx.Account
where acct.Type == AccountType.VerifyCredentials
select acct)
.SingleOrDefaultAsync();
if (verifyResponse != null && verifyResponse.User != null)
{
User user = verifyResponse.User;
Console.WriteLine(
"Credentials are good for {0}.",
user.ScreenNameResponse);
}
}
catch (TwitterQueryException tqe)
{
Console.WriteLine(tqe.Message);
}
The ScreenName and UserID are in the User entity of the User property on the Account entity returned from the VerifyCredentials query. They are named ScreenNameResponse and **UserIDResponse** properties, respectively.
Say I have a set of Sites that have a collection of Users. I find myself violating the DRY principal whenever I have to redefine a query to get, say, the last visited User for a given site.
For example, my query may look like this:
from site in Context.Sites
where site.ID == 99
select new {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.Users.OrderByDescending(u => u.LastVisited).Select(u => new {
ID = u.ID,
Username = u.Username,
Email = u.EmailAddress
})
.FirstOrDefault()
}
That query returns what I want, but I find myself repeating this same select for the LastVisitedUser in multiple places as I'm selecting the site in different ways to populate my various ViewModels.
So, I thought that I would simply extend my Site Entitiy class with a property like so:
public partial class Site {
public LastVisitedUser {
get {
var query = from user in Users
where user.SiteID == this.ID
orderby user.LastVisited descending
select user;
return query.FirstOrDefault()
}
}
}
In this manner, whenever I am selecting a site it would be fairly trivial to grab this property. This almost works, however I am stuck trying to assign an Entity user into my UserViewModel property into the LastVisited property of my return, without an obvious way on how to project the User into my ViewModel version.
Perhaps an example would help explain. What I'm trying to accomplish would be something like this:
from site in Context.Sites
where site.ID == 99
select new SiteViewModel {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.LastVisitedUser <--- NOTE
}
NOTE = This is my point of failure. LastVisitedUser is a ViewModel with a subset of User data.
Am I going about this in the correct manner? Can I achieve what I'm trying to do, or am I horribly misguided? Am I about to sove this issue and run into others?
Thanks!
Edit: The former answer was not correct. You cannot use extension method on the navigation property but you can still create extension method for the whole Site projection.
Just create simple reusable extension method:
public static IQueryalbe<SiteModel> GetSiteModels(this IQueryable<Site> query)
{
return query.Select(site => new SiteModel {
ID = site.ID,
Name = site.Name,
URL = site.URL,
LastVisitedUser = site.Users
.OrderByDescending(u => u.LastVisited)
.Select(u => new LastVisitedUser {
ID = u.ID,
Username = u.Username,
Email = u.EmailAddress
}});
}
Now you should be able to use that extension in your former query:
Context.Sites.Where(site => site.ID == 99).GetSiteModels();
Your example will not work because your property is not visible for Linq-to-entities.
If you mean that you what to reuse common queries with different extensions, you just nead to write some base query and get different results and some Where lambda expressions. If you profile it, you will see that you have just one query to DB just return IQuerable in a base query
I'm having a hard time getting the LINQ-syntax.. How can I do this command in a better way?
var user = (from u in context.users
where u.email.Equals(email)
select u).Single();
var pinToUser = (from ptu in context.pintousers
where ptu.user_id.Equals(user.id)
select ptu).Single();
var pin = (from p in context.pins
where p.idpin.Equals(pinToUser.pin_idpin)
select p).Single();
return pin;
As you can see, there's a table user, a table pintouser and a table pin. Pintouser references user and pin. Is it possible to write something short like "user.pintouser.pin"? I think I have the navigation properties all set up but I'm not sure how to use them properly or if I could make them better by modifying them.
Thanks for reading
Use joins to rewrite everything as a single clean query. If I read your queries properly, this should give you the correct result:
var pin = (from u in context.users
join ptu in context.pintousers on u.id equals ptu.user_id
join p in context.pins on ptu.pin_idpin equals p.idpin
where u.email == email
select p).Single();
Keep in mind, though, that if this query returns anything other than a single result your code will throw an Exception.
If you want to handle the possibility of getting one or no rows then you should use SingleOrDefault().
If you want to handle the possiblity of getting any number of rows then you should really use FirstOrDefault().
Note that if you have your foreign-key relationship set righ in your database, Linq-to-Sql should have the joins for you automatically:
var pin = (from u in context.users
where u.email == email
select u.pintouser.pin).Single();
which means you can reduce this to:
var pin = context.users.Where(u=>u.email == email)
.Select(u=>u.pintouser.pin)
.Single();
(UPDATE Note: I had originally suggested the following, which is much shorter, but I believe it will cause two round-trips to the database)
var pin = context.users.Single(u=>u.email == email).Single().pintouser.pin;
Now, the .pintouser.pin is safe, because the Single() will always return a user object (or throw an exception).
You should be using join, as #JustinNiessner points out, but this is another way to write your query.
var user = context.users.Single(u => u.email == email);
var pinToUser = context.pintousers.Single(ptu => ptu.user_id == user.id);
var pin = context.pins.Single(p => p.idpin == pinToUser.pin_idpid);
Since you have navigation properties, might as well use them:
Pin pin =
(
from u in context.Users
where u.email == email
from ptu in u.pintousers
let p = ptu.pin
select p
).Single();