I am learning asp.net mvc , using visual studio community 2017, and as a sort of teaching project I am making a web app that keeps track of exercise work outs. My model consists of WorkOut objects that have a list (or ICollection more specifically) of Exercise, and each Exercise has an ICollection. Heres the basics of my model classes.
public class WorkOut
{
public int Id { get; set; }
public int Length { get; set; }
public DateTime Date { get; set; }
public virtual ICollection<Exercise> ExerciseList { get; set; }
}
public class Exercise
{
public int Id { get; set; }
public string Name { get; set; }
public int WorkOutId { get; set; }
public virtual WorkOut WorkOut { get; set; }
public virtual ICollection<RepUnit> Sets { get; set; }
}
public class RepUnit
{
public int Id { get; set; }
public int Rep { get; set; }
public int? Weight { get; set; }
public int ExerciseId { get; set; }
public virtual Exercise Exercise { get; set; }
}
Generating a view automatically with WorkOut as a model leads to Create action and view that only generates a Length and Date property. In general, auto generated view and controllers only add the non virtual properties. So I figure maybe I have to do a multistep creation process; Create a workout, create an exercise and add reps to it, add that exercise to the work out, either stop or add another exercise. So I figured Id let VS to some of the work for me, and I make controllers and views for each of the model object typers (WorkOutsController, ExercisesController, RepUnitsController), and later I would trim out the uneeded views or even refactor the actions i actually use into a new controller. So WorkOutsController my POST action is this.
public ActionResult Create([Bind(Include = "Id,Length,Date")] WorkOut workOut)
{
if (ModelState.IsValid)
{
db.WorkOuts.Add(workOut);
db.SaveChanges();
return RedirectToAction("Create","Exercises",new { workoutId = workOut.Id });
}
return View(workOut);
}
So I carry the workoutId to the Exercise controller but this is where I am unsure how to proceed. I want to keep carrying around the workoutId and for the next step, where I give the exercise a name, also show the associated date that was just added. The only thing I could think to do was instantiate an Exercise in the GET action of ExerciseController like so.
public ActionResult Create(int workoutID)
{
Exercise ex= new Exercise();
ex.WorkOutId=workoutID;
ex.WorkOut=db.WorkOuts(workoutID);
return View(ex);
}
This seems terrible and I've not seen anything like this done in any examples, but it seems to work. The same exercise object is brought back to my POST create action here
public ActionResult Create([Bind(Include = "Id,Name,WorkOutId")] Exercise exercise)
{
if (ModelState.IsValid)
{
db.Exercises.Add(exercise);
db.SaveChanges();
return RedirectToAction("Create", "RepUnits", new { exerciseId = exercise.Id });
}
return View(exercise);
}
which as you see calls the RepUnits controller and associated Create action. There I do something very similar; create a rep object and pass it to the view, and essentially I add reps until I'm done. Eventually I will create navigation to either go back to add a new exercise or go back to an Index view.
So to sum up, it seems wasteful to be passing entire objects around, and maybe my whole implementation is wrong and I should be trying to somehow do this all on one form. Up to this point googling hasnt found me much because I wasnt sure what questions to be asking, however this post Creation of objects using form data within an ASP.NET MVC application just popped up in the similar question dialogue and the app in question is coincidentally very similar! However when the OP mentions passing the workoutId around, how is this accomplised? I thought to maybe use the ViewBag but how do I get the view to handle this Id? I had though to try, as an example
public ActionResult Create(int workoutId)
{
ViewBag.WoID = workoutId;
return View();
}
in the ExercisesController and then in the associated Create view:
@Html.Hidden("WorkOutId", new { ViewBag.WoID })
But later in the view when I try to reference the workout date it comes up blank
<div class="form-group">
@Html.LabelFor(model => model.WorkOut.Date, "Work Out On:", htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DisplayFor(model=>model.WorkOut.Date)
</div>
</div>
Should I be doing something like this in the view: @Model.WorkOutId=ViewBag.WoID;
which doesnt work for some reason (Compiler Error Message: CS1525: Invalid expression term '='), but is that along the lines of how I pass these ids around?