8

I'm still not yet sure on the best way to store selectlist options for front end display or db storage.

I've been using Enums at the moment, and also using description decorators (How do you create a dropdownlist from an enum in ASP.NET MVC?)

I'm now thinking that I might as well just create a full class for this stuff, so I can store the following information properly with full control:

  1. Item Name
  2. Full description
  3. int for storage in db
  4. order
  5. Any methods to get information in anyway from the list.

Is it right I should be thinking about implementing all this myself by hand? I want a really solid way of doing this, and an enum doesn't really feel like it's going to cut it.

Community
  • 1
  • 1
Chris Barry
  • 4,564
  • 7
  • 54
  • 89

5 Answers5

5

Is it right I should be thinking about implementing all this myself by hand?

Yes. Enums are often leaky and insufficient abstractions that aren't always suitable for the complex domain model you actually wish to represent.

Rather than roll your own, you may want to consider Headspring's Enumeration class (via github, nuget). We use it all the time instead of enums because it's nearly as simple and is much more flexible.

An example of a "State" enumeration and using it as a select list:

public class State : Enumeration<State>
{
    public static State Alabama = new State(1, "AL", "Alabama");
    public static State Alaska = new State(2, "AK", "Alaska");
    // .. many more
    public static State Wyoming = new State(3, "WY", "Wyoming");

    public State(int value, string displayName, string description) : base(value, displayName)
    {
        Description = description;
    }

    public string Description { get; private set; }
}

public IEnumerable<SelectListItem> Creating_a_select_list(State selected)
{
    return State.GetAll().Select(
        x => new SelectListItem
        {
            Selected = x == selected,
            Text = x.Description,
            Value = x.Value.ToString()
        });
}

I'm not trying to sell you on this particular implementation, you could certainly hand code your own (the Enumeration class is only about 100 lines of code). But I definitely think you'd benefit from moving beyond basic enums. It is the right approach given the scenario you described in your question.

Kurt Schindler
  • 21,037
  • 4
  • 43
  • 48
4

The first place where such information shoiuld be is the database...or any "virtual store" such as a web service that offers an interface to you db. In fact if there are other db entiies that use these values THEY MUST be represented in the database, otherwise you will run in big troubles. In fact, suppose one of such values is a string....if you don't define a table containing all possible values+a key and simply write the string as it is in other tables...it will be impossible for you to change the format of the string since it will be "spread" all over your db...On the contrary, if you just use an external key to refer to such strings...you can easily change them since the string is stored in just ONE place in your db. Also the enumeration solution suffers of the problem that you cannot add or deleted values...so if such operations "conceptually" might make sense you cannot use an enumeration. You can use enumeration when all options "conceptually span" all possibilities, so you are sure you will never add/delete other options, such as in the case of the enumeration (yes, no, unknown).

That said, once you have your options in the db the remainder is easy...you will have DTO entities or Business entities representing them in exactly the same way you do for all other DB entities.

For visualization purposes you may have a ViewModel version of this options that might just contain key and description, and a "Repository method" that your controllers can call to have the list of all options.

Once retrieved you controllers put them in the overall page ViewViewModel...together with all other information to be shown on the page. From the ViewModel...you can access them to put them in a dropdown.

Summing up: 1) You need a DB representation of your options 2) Then you will have DTO, business layer, and View versions of this entities...as needed, exactly as for all other DB entities.

Francesco Abbruzzese
  • 4,139
  • 1
  • 17
  • 18
  • OK, so I guess the solidairty of having these options in the db outweights the lookups needed to find out what the options are? I certainly don't want to litter my database with loads of tidy tables, one for each dropdown? Could I put all select list options into a single table, and use a secondary grouping id to manage them like that? Then I get back into a problem of the options themselves not being tightly controlled and require default data in the db from day one? Is this never a bad thing (requiring some data in your db post scheme generation) – Chris Barry Mar 22 '12 at 12:27
  • if you could make an example of your options it would be great..I have not said to transform each list of optiont into a table, but that such information might be contained in the database. Then you can retrieve them with adequate queries. Putting or not several options in the same table..depends ...if they represents the same "stuff" that is "filtered" in different ways in different select you can do it...otherwise NOT. For instance you can put the list of all towns in US in the same table and then in some select you can use ..say just the ones of a state. – Francesco Abbruzzese Mar 22 '12 at 13:53
  • ON THE OTHER SIDE: if your options are just an User Interface staff with no "meaning" in the business domain you may consider putting them in a configuration file(or into an enumeration...if they don't change)..if you might do a couple examples...I can answer how I would dela with each of them...to make more clear what I said. – Francesco Abbruzzese Mar 22 '12 at 13:57
2

Are you looking for a one-size-fits-all solution for all your select list options? I personally advocate choosing the option that best fits the specific issue.

In a recent project I was introduced to a hybrid of a Smart Enum. Here's an example (I apologize for typos, I'm typing this cold):

public class Priority 
{
    public enum Types
    {
        High,
        Medium,
        Low
    }

    public Types Type { get; private set; }
    public string Name { get { return this.Type.ToString(); } } // ToString() with no arguments is not deprecated
    public string Description { get; private set; }

    public static High = new Priority{ Type = Types.High, Description = "..."};
    public static Medium = new Priority{ Type = Types.Medium, Description = "..."};
    public static Low = new Priority{ Type = Types.Low, Description = "..."};

    public static IEnumerable<Priority> All = new[]{High, Medium, Low};

    public static Priority For(Types priorityType)
    {
        return All.Single(x => x.Type == priorityType);
    }
}

So, in implementation, you could store the Enum value, but you would reference the object itself (Priority.For(entity.priority)) for the additional metadata when rendering your views.

Is that closer to what you're looking for?

Of course, one of the gotchas is if you need to write a query against the database that relies on the metadata on the lookup, this solution is going to create a few tears along the way.

brightgarden
  • 410
  • 4
  • 12
1

You can use "repository pattern" for data access and use viewmodels between your controllers and views. Example:

//Model
public class CustomerViewModel
{
    public Customer customer { get;set; }        
    public IEnumerable<Village> Villages { get; set; }
}

//Controller
public ActionResult Index()
{
    var customerViewModel = new CustomerViewModel
                           {
                               Customer = new Customer(),
                               Villages = _villageService.GetAll()
                           };
    return View(customerViewModel);
}

//View
@model ViewModel.RegisterViewModel
@Html.DropDownListFor(q => q.Customer.VillageId, new SelectList(Model.Villages, "Id", "Title"), "Please Select")

I have written a blog post about repository pattern, you may have a look.

Efe Kaptan
  • 465
  • 2
  • 11
  • Hi, I'm not sure if you've missed what I'm looking for? This is more a question about how to store the options for a dropdown box, not about how to use view models and controllers? I'm OK with that stuff? How do you store the options for the drop down, if they are not defined in the db to be extended at run time? For example, use role levels I don't want stored in the DB. – Chris Barry Mar 14 '12 at 16:18
  • Unless I was building an app that allowed custom roles of course ;) – Chris Barry Mar 14 '12 at 16:19
1

I store my options in the View Models themselves:

public class ViewModel {

    [Required]
    public int SelectListValue { get; set; }

    public IDictionary<String,String> SelectListOptions { 
        get { 
            return new Dictionary<String, String>{
                                                    { "0", Resources.Option1},
                                                    { "1", Resources.Option2},
                                                    { "2", Resources.Option3}
                                                 }; 
        } 
    }

}

Then I can just drop the following line into my view to render the select list:

<%= Html.DropDownListFor(m => m.SelectListValue, new SelectList(this.Model.SelectListOptions, "Key", "Value", "")) %>
Dr. Hilarius
  • 1,134
  • 1
  • 14
  • 20