1

I was working on an MVC project today at work, and I came by a problem, which I couldn't really figure out the best practice for.

Consider that I have a User, and each user have a UserType-ID or Code (not necessarily residing in another table). In this case the UserType is not in another table, but is hardcoded. But in the future, should be loaded from a persistence layer.
ID 1 is an Admin
ID 2 is a Moderator
ID 3 is a normal user.

Now I have a plain Index, Create, Edit view of this User, and the UserType Id is a Dropdownlist of UserTypes.

So far, the code built the SelectList in the Controller, and there it was all hardcoded.

On the index page, I would want to display the user type "name", rather than the id that represented that.

So I ended up, keeping the hard coded value in the Controller, and in the UserViewModel, I added a "UserTypeStr" property, that would give me a name for that user type.

Like this:

public class User
{
    public int UserType{get;set;}
    // other fields...

    public string UserTypeStr
    {
        get
        {
            switch(UserType)
            {
                case 1: return "Admin";
                case 2: return "Moderator";
                // ... and so on
            }
        }
    }
}

Now this code does NOT scale very well, and now I have duplicate code, that somewhat does the same damn thing.

I'm not entirely sure, what the best ways to solve this issue is. I have a few ideas, where I could put them in one class, either a dedicated ViewModel class, a Factory or something similar, but I don't feel that it's right.

I look forward to reading how you guys solve this.

BTW, I know this isn't very great design, but my time was limited, so I didn't refactor too much of the code.

I SHOULD NOTE That the code has to scale, so it later can be added to a database, and be translated.

André Snede
  • 9,899
  • 7
  • 43
  • 67
  • What's wrong with putting it in a database? – dav_i Nov 18 '13 at 17:44
  • Absolutely nothing? Did I make it seem so, because that wasn't intended! In the future it should be in the database, but for now it isn't, as my time limit on this project, didn't allow me to change too much. Read the last line btw. – André Snede Nov 18 '13 at 17:46
  • I don't understand your issue I'm afraid - just create a table in your database called `UserTypes` or similar and query that using your favourite ORM...? – dav_i Nov 18 '13 at 17:48
  • The issue is, I want to know what best practices is for doing it? Paired with MVC. Should be scalable, and support DI and IoC. Im looking for the best practice, to solve this problem. – André Snede Nov 18 '13 at 17:50
  • If you think it's going to be in the database in the futur. Just pretend in the .net that it's already is. But instead of loading the list from the database, load in a central place in your code. – the_lotus Nov 19 '13 at 13:14
  • @the_lotus you are right, and I had already come to that conclusion, I was just wondering if a better way existed. As far as I see, the `Repository pattern` is the best bet here, together with some helper classes, to generate the SelectList etc. – André Snede Nov 19 '13 at 14:03

3 Answers3

2

You can create a Dictionary<int, string> that would hold the list of UserTypeId and UserTypeValue and place this list in a common place.

You could then do a lookup on the list based on the UserType or an inner join between the user and the list (using LINQ)

Andy T
  • 10,223
  • 5
  • 53
  • 95
  • This is close to what I had in mind, making a class that holds that kind of information, and has the ability to get the Dictionary from somewhere else, if need be in the future. – André Snede Nov 18 '13 at 17:19
1

Create an enumration:

public enum UserType {
    NotSet = 0,
    Admin,
    Moderator
}

public class User
{
    public UserType Type {get; set; }

    public string TypeOfUser() {
        return Type.ToString();
    }
}

This approach scales and is common practice (having enumeration map to database enumerations). It does require re-compilation if alterations are made, but I wouldn't label it as "unscalable" ...

Alex
  • 34,899
  • 5
  • 77
  • 90
  • ...and use [Enum.GetName](http://msdn.microsoft.com/en-us/library/system.enum.getname%28v=vs.110%29.aspx) to convert to a string – sinelaw Nov 18 '13 at 17:13
  • ...and use the enum to build your `SelectList` for the dropdown in your view. – Cᴏʀʏ Nov 18 '13 at 17:14
  • Doesn't scale at all. So that won't solve it. – André Snede Nov 18 '13 at 17:14
  • 1
    @AndréSnedeHansen it doesn't scale in what sense? – sinelaw Nov 18 '13 at 17:15
  • i18n and it should be possible to change this to be flexible in the future. Meaning in the future it will be loaded from a database or some other repository. – André Snede Nov 18 '13 at 17:16
  • http://stackoverflow.com/questions/3914688/whats-the-best-way-to-provide-localization-for-enums – Alex Nov 18 '13 at 17:20
  • @Xander I don't want to compile again, to in the future add a new user type. For now it can be static, but should be flexible so that I in the future can scale it, without changing the architecture from the BLL and up. – André Snede Nov 18 '13 at 17:24
  • @Xander I will answer you here, instead of in Turchs post. Your solution doesn't scale, if it should be an object in the future, your Enum solution falls to the floor immediatly. Thinking the issue through for more than 1 minute, you will quickly realise that the enum isn't a fit here. Enums are better for setting a mode in an object, this is not a "mode", its data. – André Snede Nov 18 '13 at 17:55
  • well, then for f. sake just create the UserTypes table in your favorite database and put those user types in it with auto numbered integer primary key – mare Nov 18 '13 at 17:56
  • there's something to be said for keeping your code semantic, especially with regard to maintainability - the reason enumerations exist no? keep the code semantic (meaningful). – Alex Nov 18 '13 at 17:57
  • @mare if I wanted a simple, "just hack it, and don't think about it" answer, I could have asked anyone on the street. I came here for best practices :) – André Snede Nov 18 '13 at 17:57
  • @Xander you are correct on the semantic part, and you can use enums to illustrate common ones. Lets say admin and user, they will all be there, so you can use an enum for those, but the actual ID's come from the database, and the only ones reserved are admin and user. So for readability, you can use them yes. But that is not the issue here. – André Snede Nov 18 '13 at 17:59
  • the thing is, your issue is very basic, and you can do it either via the proposed enum way (which I agree is not the most flexible one) or store that list in some persistent and modifiable way for runtime – mare Nov 18 '13 at 18:01
  • @mare Exactly. And I wanted to know what the best practices is for accommodating this small, but common problem, is a scalable and low maintenance way. I could easily implement the repository pattern, but I wanted to ask my fellow professionals, for a proper, non-over-engineered solution. – André Snede Nov 18 '13 at 18:04
0

You can use an enum with the Description attribute

private enum UserTypeEnum
{
    [Description("Administrator")]
    Admin,
    [Description("Moderator")]
    Mod
};

public UserTypeEnum UserType;
public string UserTypeStr { get {return UserType.ToString();} }
Turch
  • 1,546
  • 2
  • 15
  • 31
  • Some other guy, just got downvoted for that same answer ( and for good reason). It doesn't scale. You have to recompile every time you want to add a new one, and the structure using the code will probably break if you use it. It doesn't scale for the future, where new ones might needed to be added, or made flexible through a database. – André Snede Nov 18 '13 at 17:42
  • @AndréSnedeHansen "You have to recompile every time you want to add a new one" you're going to be adding new user types at whim?! really?! and of course this scales, so did my answer. just not to the level that you're expecting. i deleted it cause i didn't want to join you down the rabbit hole. – Alex Nov 18 '13 at 17:46
  • @AndréSnedeHansen Oh I see, so you aren't asking for a way to convert ids to names directly, but more of a high-level approach to managing where the data comes from. You can use something like the "repository pattern" - then your display logic won't care where the data comes from - while hardcoded, you only need to recompile the enum implementation and nothing else, when ready to move to database you don't need to recompile anything, just switch repository providers. (misc. note, for some reason Xander's answer didn't show up for me, mine is pretty much a dupe) – Turch Nov 18 '13 at 17:47
  • @turch i just undid the delete after reflecting on its "scalability" – Alex Nov 18 '13 at 17:52
  • The dictionary way of doing it, is better then, for scaling purposes. But the repository pattern is a good way of solving it, but it seems over engineered for such a small problem. – André Snede Nov 18 '13 at 17:54