I'm creating the admin portion of a project. Specifically, I am wanting to allow the users to update the look-up tables for their areas of interest.
All of my look-up tables have the same structure:
TypeX Id int Description string Active DateTime Inactive Nullable<DateTime> CreatedBy string CreatedDate DateTime ModifiedBy string ModifiedDate DateTime
I created a model that holds IEnumerable
of each of the look-up tables and a TypeGeneric
, which is the same structure but it adds a string gType
(which will come into play in a moment). The types are all ITypeModel
.
Model
public class TypeModels
{
public IEnumerable<Type1> Type1 { get; set; }
public IEnumerable<Type2> Type2 { get; set; }
public IEnumerable<Type3> Type3 { get; set; }
public IEnumerable<Type4> Type4 { get; set; }
public TypeGeneric TypeG { get; set; }
}
Through several failed attempts and learning some odd behavior of Controllers and Actions I finally was able to create "Generic" Action set that would allow me to handle all of my Types. However, it feels more of a hack then an actual solution. Is there is a better way of handling this?
Controller
public ActionResult Index()
{
TypeModels model = new TypeModels();
model.Type1 = db.Type1.ToList();
model.Type2 = db.Type2.ToList();
model.Type3 = db.Type3.ToList();
model.Type4 = db.Type4.ToList();
return View(model);
}
public ActionResult Create(string type)
{
TypeModels m = new TypeModels();
m.TypeG = new TypeGeneric();
m.TypeG.sType = type;
createTypeView(m.TypeG);
return View(m);
}
[HttpPost]
public ActionResult Create(TypeModels m)
{
createType(m.TypeG);
return RedirectToAction("Index");
}
public void createTypeView<T>(T type) where T:ITypeModel
{
type.DateActive = DateTime.Now;
}
public void createType(TypeGeneric m)
{
ITypeModel model = null;
model = castAndLoadITypeModel(model, m);
if (ModelState.IsValid)
{
DateTime now = DateTime.Now;
string user = User.Identity.GetUserId();
model.CreatedDate = model.ModifiedDate = now;
model.CreatedBy = model.ModifiedBy = user;
if (model.DateActive < DateTime.Now)
{
model.DateActive = now;
}
db.Set(model.GetType()).Add(model);
db.SaveChanges();
}
}
public ITypeModel castAndLoadITypeModel(ITypeModel model, TypeGeneric type)
{
switch (type.sType)
{
case "1":
model = new Type1();
goto case "all";
case "2":
model = new Type2();
goto case "all";
case "3":
model = new Type3();
goto case "all";
case "4":
model = new Type4();
goto case "all";
case "all":
loadType(model, type);
break;
}
return model;
}
public void loadType(ITypeModel model, TypeGeneric m)
{
model.Description = m.Description;
model.DateActive = m.DateActive;
}
Index View
@model TMS.Models.TypeModels
@{
ViewBag.Title = "Index";
}
<h2>Index</h2>
@using (Html.BeginForm())
{
<div class="row">
<div class="col-md-4 col-sm-6">
<h3>Event Types</h3>
<div>
@{ WebGrid grid1 = new WebGrid(Model.Type1);}
@grid1.GetHtml(
tableStyle: "webgrid-table",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webrid-selected-row",
rowStyle: "webgrid-row-style",
mode: WebGridPagerModes.All,
columns: grid1.Columns(
grid1.Column("Description", "Types"),
grid1.Column("DateActive", "Active"),
grid1.Column("DateInactive", "Inactive")
))
</div>
@Html.ActionLink("Add", "Create", new { type = "1" })
</div>
<div class="col-md-4 col-sm-1"></div>
<div class="col-md-4 col-sm-5">
<h3>Dose Amounts</h3>
<div>
@{
WebGrid grid2 = new WebGrid(Model.Type2);
}
@grid2.GetHtml(
tableStyle: "webgrid-table",
headerStyle: "webgrid-header",
footerStyle: "webgrid-footer",
alternatingRowStyle: "webgrid-alternating-row",
selectedRowStyle: "webrid-selected-row",
rowStyle: "webgrid-row-style",
mode: WebGridPagerModes.All,
columns: grid2.Columns(
grid2.Column("Description")
))
</div>
@Html.ActionLink("Add", "Create", new { type = "2" })
</div>
</div>
}
Create View
@model TMS.Models.TypeModels
@{
ViewBag.Title = "Create " + Model;
}
<h2>Create @Model.TypeG.sType</h2>
@using (Html.BeginForm())
{
<div class="form-group">
@Html.LabelFor(m => m.TypeG.Description, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(m => m.TypeG.Description, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(m => m.TypeG.Description, "*", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(m => m.TypeG.DateActive, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(m => m.TypeG.DateActive, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(m => m.TypeG.DateActive, "*", new { @class = "text-danger" })
</div>
</div>
@Html.EditorFor(m => m.TypeG.sType, new { htmlAttributes = new { @class = "hide" } })
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
}
When the add button is clicked on the Index Page, it sends along a string value that tells me what Type was selected. I create and add a GenericType
to my model and pass it to the Create View. The data is filled into this GenericType
and when it is submitted I grab the string value and assign an ITypeModel
the proper TypeClass
and fill in the data using my GenericType
values.
This solution works, but I have a sneak suspicion that there are better ways of handling this.
Searching online I found a few different ways of handling this, but most of those came from my failures. One was creating my own Controllers for generic Actions, which is really more work than I think its worth.
My other problem was attempting to use an Interface in my model, which the controller doesn't like at all.