How to extend a User record

Topics: Customizing Orchard, Writing modules
Jul 5, 2011 at 2:03 PM

Hi all,

which options does Orchard have in case when I need to add more data for the standard User record to be used in my module? In other words I would like to extend the standard user record with own data, without affecting existing table.
I know there is a 'connectors' concept, may it be used for my case? (I guess connectors is a UI-related feature, so it doesn't affect my low-level data structures, right?)

Another my concern is how can I make Orchard read data from Orchard_Users_UserPartRecord table and my 'Orhcard_Module_ExtendedUserRecord' table in one query, using SQL Join? As far as I understand, splitting application functionality to modules/parts/records leads to the issue when data will be read from the DB part by part though could be read by complex query, does anybody know details on this scenario?

Thanks in advance

Jul 5, 2011 at 2:15 PM

Connectors are part of a separate module called "Mechanics" (which I am the author of). They're useful in scenarios where you want to create n-n relationships.

For what you want, all you need to do is build a content part. "User" is just a content type that happens to have UserPart. So you are free to add any other parts to it for your own custom data. A content part is implemented as a separate table with a 1-1 join to the content item record. The Orchard documentation has tutorials and examples for building parts.

Jul 5, 2011 at 3:38 PM

But is the following possible:

Create an new content type named "Member". And include the user part to the new Member type. Is it now possible to login using the default login mechanism in Orchard using the created member?

Jul 5, 2011 at 4:47 PM

@Znowman, this is not a scenario needed for me - to implement a supertype for existing User type.

I've implemented a part named MyUserPart and appropriate record, which extends a standard user profile with 'Skype' field, marked it as attachable and included into the user type. Yes, for now I can store Skype account info, but still not aware how to see a 'Skype' column within a standard grid with users. Possibly, this cannot be implemented and I should create own controller/views for rendering full user's profile info?

Jul 5, 2011 at 7:58 PM

it is possible to extend the user with extra field. Take a look at the UserPersonalInformation module for that. What i don't know if it is possible to create an supertype user which extends a normal user with extra fields and is still managable like a normal user?

so that the default user is not extended with the new fields.

Jul 6, 2011 at 10:47 AM

@Znowman, thanks a lot for the reference to UserPersonalInformation - I've already done the same work for my module :)

I don't fully understand your desire to have 'a normal user with extra fields and is still managable like a normal user'. As far as I understand a module like UserPersonalInformation will inevitably add new fields to standard user implementation - for all users without exception. If you mind having several sets of users with different sets of fields, this should be carried as a fully separate module with all own tables, imho..

As for me, I see here another big problem:
say, I have 4 users within my DB, and my User content type includes my own part (RmsUserPart), that extends standard implementation with Skype field. I'm querying all users in order to show them at the UI:

            var userQuery = OrchardServices.ContentManager.Query().ForType("User");
            var users = userQuery.List();

            var viewModel = new RmsUserIndexViewModel();
            viewModel.Users = users.Select(x => new RmsUserItem
                                                    {
                                                        UserPart = x.Parts.OfType<UserPart>().First(),
                                                        RmsUserPart = x.Parts.OfType<RmsUserPart>().First()
                                                    }).ToList();

            return View("Users", viewModel);

And when I look through the SQL Profiler's output, there are about N * M requests, where N = number of users, M = number of content parts the user consists of and I use to show info at the UI.

So consider the case when I'm going to handle 1000 or more Users, Products or some another complex content type - I'll get a huge bunch of SQL queries.
I'm not aware if there any mechanisms in Orchard that will let me tell the ContentManager to load users 'eagerly'..

I know there is an option to access underlying tables directly via LINQ queries, but that would be wonderful if ContentManager took all this job.

Jul 6, 2011 at 2:39 PM

Couple of comments on this;

- You shouldn't ever read 1000 records at once from the database. You should use .Slice(..) to page the query and read a sensible number to display on the screen at once. Orchard already provides a nice Pager system that you can use (this can be seen in some other places).

- If think that on your query if you use .Join<RmsUserPartRecord>() then NHibernate will correctly read that records at the same time and save the extra database calls. I haven't throughly tested it, but it's my understand that it works that way. Unfortunately it's impossible for the system to know which extra part tables will be required unless you explicitly declare it during your query, since any content item can theoretically be joined to any other part table.

Jul 6, 2011 at 3:25 PM

Thank you very much, Join call seems to be a solution - this allows querying my own types/parts without extra DB calls.