Get to username from ID

Topics: Writing modules
Jun 8, 2011 at 11:49 PM

Hello,

In my module, I am storing the UserId in my tables to reference data for users...in this case, Points they are scoring in a game.

One one of my pages, I want to list a Leaderboard and show the top 5 users giving their username and total points. I have this coded out, but the query in my service obviously brings back UserId and Points. Is there a way I can do a lookup on the UserId to get the Username? Is there an Orchard service I can use to do that? Thanks for the help!

Coordinator
Jun 8, 2011 at 11:54 PM

Query from the content manager. It has methods to query by id.

Jun 9, 2011 at 4:21 PM
Edited Jun 10, 2011 at 9:31 PM

Thanks for the tip. Can you give me a quick hand formatting the command? So far I have

 

string userName = _services.ContentManager.Query<UserPart, UserPartRecord>().Where(u => u.Id == UserId).Select(u => u.UserName).FirstOrDefault();

 

Not sure how to get reference to UserPart and UserPartRecord...or if I'm even close on formatting this correctly. Am I on the right track here? Thanks

Jun 9, 2011 at 6:10 PM

I found another post that had the syntax for using ContentManager, so I believe the above is correct, however, I need to add a using directive to get to UserPart and UserPartRecord. I tried Orchard.Users.Models, but it wasn't found. Any ideas?

Jun 10, 2011 at 9:31 PM

Still struggling with figuring this out...any suggestions from the experts? Much appreciated!

Coordinator
Jun 11, 2011 at 12:30 AM

Do you have a reference to the module?

Jun 11, 2011 at 10:44 AM

Your thing wrong with your syntax is that ContentQuery can't have normal Linq operations (e.g. Select, FirstOrDefault) run on it. It has it's own version of Where, so that part is correct.

ContentQuery has two basic methods for getting the data out: List, and Slice. You can use Slice for bigger queries that need paging. Or use List to get an ordinary IEnumerable out that you can then perform further processing on - but note that List will cause all the data to get read from the database.

Ok; since you're getting a list of users, you might as well grab them all from a single query.

Here's the final version;

var userIds = new[] {1,2,3,4,5};
var userNames = _services.ContentManager.Query<UserPart,UserPartRecord>().Where(u=>userIds.Contains(u.Id)).List().Select(u=>u.UserName);

You also just need a reference to the Orchard.Users module; UserPart and UserPartRecord aren't in core.

Jun 13, 2011 at 3:52 PM
Edited Jun 13, 2011 at 4:13 PM

Thanks so much for the assistance...I added a reference to Orchard.Users in my project. I suppose it makes sense to reference that project when you want to use it =) LOL

I added "using Orchard.Users.Models;" to the top of my service file and UserPart and UserPartRecord are now resolving properly. I am still receiving a syntax error on the line you provided above. The error reads

 

The non-generic method 'Orchard.ContentManagement.IContentManager.Query()' cannot be used with type arguments

 

Also...one other question on this. The model for my project is setup to store an integer value for the UserId. Would I better off setting this up instead as a relationship to UserPartRecord?

So...currently, my model looks like this:

 

    public class LeagueMembersRecord
    {
        public virtual int Id { get; set; }
        public virtual ShowRecord Show { get; set; }
        public virtual SeasonRecord Season { get; set; }
        public virtual LeagueRecord League { get; set; }
        public virtual int UserId { get; set; }
        public virtual CastRecord Cast { get; set; }
        public virtual bool MemberPaid { get; set; }
    }

 

Would I better off doing something like this?:

 

    public class LeagueMembersRecord
    {
        public virtual int Id { get; set; }
        public virtual ShowRecord Show { get; set; }
        public virtual SeasonRecord Season { get; set; }
        public virtual LeagueRecord League { get; set; }
        public virtual UserPartRecord User { get; set; }
        public virtual CastRecord Cast { get; set; }
        public virtual bool MemberPaid { get; set; }
    }
Coordinator
Jun 13, 2011 at 7:33 PM

I would do a real relationship yes.

Jun 13, 2011 at 11:50 PM

It was a lot easier to do by creating that relationship...thanks for that.

I was able to do exactly what I needed to do.

Jul 7, 2011 at 8:00 AM

Hi psenechal

I have your same error:

The non-generic method 'Orchard.ContentManagement.IContentManager.Query()' cannot be used with type arguments

Have you found a solution ?

Jul 8, 2011 at 10:31 PM

No...never got it to work and changed my model to use a real relationship instead. I found another place I'd like to be able to use this though and have the same problem. I'm in a View in my module and am still getting the same error. It just doesn't like the way I'm trying to do it.

Jul 11, 2011 at 11:13 PM

In my Model I have a User object which ends up being a UserPartRecord or ContentItemRecord. I've been trying to figure out a way to refer to it as a ContentItem...then I should be able to get to the Profile Parts. So far I haven't been very successful. Just seems like there should be an easy way to take a UserPartRecord and get to the profile fields. It's so straight forward with WorkContext.CurrentUser, I just need to be able to do it for a UserPartRecord.

Anyone have any ideas on how to take a UserPartRecord and use it as a ContentItem? And yes...I already tried casting it =)

Coordinator
Jul 11, 2011 at 11:15 PM

uh? Where are you getting those from that you'd only get the records and not the parts?

Jul 11, 2011 at 11:18 PM

My model looks like this...

    public class LeagueMembersRecord
    {
        public virtual int Id { get; set; }
        public virtual ShowRecord Show { get; set; }
        public virtual SeasonRecord Season { get; set; }
        public virtual LeagueRecord League { get; set; }
        public virtual UserPartRecord User { get; set; }
        public virtual CastRecord Cast { get; set; }
        public virtual bool MemberPaid { get; set; }
    }
so it's the User in this model.

Coordinator
Jul 11, 2011 at 11:20 PM

That wasn't my question. How are you doing your querying that you would get only the records without the parts?

Jul 11, 2011 at 11:24 PM
Edited Jul 11, 2011 at 11:26 PM

Sorry...misunderstood the question. I'm selecting the entire LeagueMembersRecord using IRepository as such

 

IEnumerable<LeagueMembersRecord> leagueMember = from leagueMembers in _leaguemembersRepository.Table
                                                where leagueMembers.League.Id == leagueId
                                                select leagueMembers;

 

This was the reason I was trying to use ContentManager.Query

Coordinator
Jul 11, 2011 at 11:25 PM

Right, you should be using the content manager to query. That will give you the full content items.

Jul 11, 2011 at 11:29 PM

That's where both myself and rcorra68 were getting the error message

The non-generic method 'Orchard.ContentManagement.IContentManager.Query()' cannot be used with type arguments

When we specified <UserPart, UserPartRecord>

Coordinator
Jul 11, 2011 at 11:49 PM

I have no idea: I just reproduced exactly that code and it worked flawlessly.

Jul 11, 2011 at 11:51 PM
Edited Jul 11, 2011 at 11:51 PM

Would you mind pasting your code here just so I can double-check that I'm not making some really dumb typo? Much appreciated.

Jul 11, 2011 at 11:53 PM

and also how the Query would look if it was done in a View instead of a Service class possibly?

Coordinator
Jul 11, 2011 at 11:57 PM

I actually did my test in a view because that was the fastest way to test this (but of course you should *NEVER* write that sort of code in a view):

@{
    var cm = WorkContext.Resolve<IContentManager>();
    var userIds = new[] { 1, 2, 3, 4, 5 };
    var users = cm.Query<UserPart, UserPartRecord>().Where(ur => userIds.Contains(ur.Id)).List();
}
User: @users.FirstOrDefault().UserName

Jul 12, 2011 at 12:01 AM

Do you have any @using declarations that are specific to making this work? Maybe I'm missing one. I have @using Orchard.Users.Models;

Jul 12, 2011 at 12:07 AM

Or perhaps I'm missing a reference in my Module? I did reference Orchard.Users.

I copied your code and pasted and I get the error mentioned above. [scratching head]

Coordinator
Jul 12, 2011 at 12:08 AM

I have

@using Orchard.ContentManagement

@using Orchard.Users.Models

Jul 12, 2011 at 4:59 PM
Edited Jul 12, 2011 at 5:01 PM

SUCCESS!

I think the combination that was causing the problem was that I wasn't using WorkContext.Resolve<IContentManager>(). I was trying to use IContentManager directly instead of an instance of it. I also then made the mistake of trying to initialize it by using WorkContext.Resolve<Orchard.ContentManagement.IContentManager>(), which also didn't work. Adding the @using Orchard.ContentManager resolved that issue.

So...I got it to work in my view and then moved it over my service file, initializing the IContentManager using an instance of Orchard.Services as such

 

var cm = _services.WorkContext.Resolve<IContentManager>;

 

I was then able to get to the ProfileParts as such

 

var user = cm.Query<UserPart, UserPartRecord>().Where(ur => ur.Id == myUser.Id).List().FirstOrDefault();

string userFirstName = ((TextField)user.ContentItem.Parts.First(p => p.PartDefinition.Name == "ProfilePart").Fields.First(f => f.Name == "FirstName")).Value;

 

FirstName is the name of the textfield I added to the Profile Part to hold the user's first name. myUser.Id is just a representation of the value I'm pulling out of my module's table that represents the Id of a user.

Since I moved this to the service file, I had to create a new model to hold the regular UserPartRecord and the new Profile fields that I want to retrieve. Then I just swapped out this model for the old one in my ViewModel and of course had to change some items in the View.

Thanks again for your patience helping me get that figured out. That was a hard one, but will definitely come in handy throughout my module. Now if I can just get users to go in and actually fill out those fields after they register on the site.

Coordinator
Jul 12, 2011 at 7:12 PM

ContentItem user = cm.Query<UserPart, UserPartRecord>().Where(ur => ur.Id == myUser.Id).List().FirstOrDefault().ContentItem;

string userFirstName = user.ProfilePart.FirstName.Value;

Jul 12, 2011 at 9:00 PM

Lost my reply somehow...

Your version is quite a bit shorter, however, I'm getting an error message:

'Orchard.ContentManagement.ContentItem' does not contain a definition for 'ProfilePart' and no extension method 'ProfilePart' accepting a first argument of type 'Orchard.ContentManagement.ContentItem' could be found (are you missing a using directive or an assembly reference?)
I have a reference to Contrib.Profile and a using statement in this class file. Anything else I might be missing to use your more concise version? Thanks!

Coordinator
Jul 12, 2011 at 10:03 PM

Maybe just .Profile. Don't forget that the caller MUST be casted to ContentItem, it's a dynamic extension to ContentItems which was introduced in 1.1

Jul 12, 2011 at 10:23 PM

I tried Profile as well. I did make sure to cast user to a ContentItem, but when I type user.  - there isn't anything coming up related to Profile. Since this is within my custom module, is there anything needed to allow dynamic extensions that I may need to add?

Coordinator
Jul 12, 2011 at 10:45 PM

If it's a contentitem it should work as is.

Feb 8, 2013 at 2:36 AM
This is an old post, but I had a need to get a user by id today - I did this:
int id = Convert.ToInt32(rxUserEditProfile.Match(this._orchardService.WorkContext.HttpContext.Request.Url.PathAndQuery).Groups["UserID"].Value);
var user = this._orchardService.ContentManager.Get<IUser>(id);
just requires a dependency to IOrchardServices from Orchard.Framework