Reputation: 642
Using MVC4, EF5 to develop on top of legacy database and code. We have a column (ex. productcolor) in the database that has a distinct set of values. The values can be 'red', 'green', or 'blue'. The DB column is a varchar(20). I can't change the database (yes, I've read about 'enums' - but can't touch the DB).
I would like to create some sort of common object that always returns a select list of these 3 values whenever a form is used to create/edit a new item.
Right now, I have a couple of [NotMapped] classes in my model
[NotMapped]
public string ProductColorSelected {
get { return productcolor; }
set { productcolor = value; }
}
[NotMapped]
public IEnumerable<SelectListItem> ProductColors { get; set; }
and then I manually create the SelectList in the Controller before passing to the view
product.ProductColors = new[]
{
new SelectListItem { Value = "Red", Text = "Red" },
new SelectListItem { Value = "Green", Text = "Green" },
new SelectListItem { Value = "Blue", Text = "Blue" },
};
and the view
@Html.DropDownListFor(model => model.ProductColorSelected , Model.ProductColors)
This works but I need to create this select list on every controller class that uses it (Edit, Create) both in POST and GET. Not really following DRY but I'm not sure of a better way.
Also, would the answer change if I had another table that stored the 3 values that could be used for that column. Instead of creating the select list from above, I would get the values from a lookup table (we have both scenarios in our application)?
Thanks!
Upvotes: 0
Views: 524
Reputation: 1038770
One possibility is to write a custom action filter which will execute after each action and populate the ProductColors property on your model:
public class PopulateProductColorsAttribute: ActionFilterAttribute
{
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
var viewResult = filterContext.Result as ViewResultBase;
if (viewResult == null)
{
// the controller action didn't return a view result => no need to go any further
return;
}
var model = viewResult.Model as SomeModel;
if (model == null)
{
// The controller action didn't pass a model containing the ProductColors property => no need to go any further
return;
}
// now populate the ProductColors property. Of course here you could do a db lookup or whatever
model.ProductColors = new[]
{
new SelectListItem { Value = "Red", Text = "Red" },
new SelectListItem { Value = "Green", Text = "Green" },
new SelectListItem { Value = "Blue", Text = "Blue" },
};
}
}
and now all that's left is decorate all controller actions that need this with the custom action filter:
[PopulateProductColors]
public ActionResult Index()
{
SomeModel model = ...
return View(model);
}
[PopulateProductColors]
[HttpPost]
public ActionResult Index(SomeModel model)
{
...
}
or register it as a global action filter in which case it will apply to all your controller actions.
Upvotes: 1