0

I'm just a beginner in MVC, so please help me out and bear with my question. I have a scenario, but I can't figure it out how to create a proper ViewModel for this. I have a ProjectViewModel which consists of 4 tables related to one another.

So far my this is my ProjectViewModel.

public class ProjectViewModel
{
        public int? ProjectId { get; set; }
        public string ProjectName { get; set; }
        public string ProjectLocation { get; set; }
        public string ProjectDescription { get; set; }
        public double? WorkArea { get; set; }
        public string ModeOfPayment { get; set; }
        public string Duration { get; set; }
        public DateTime? StartDate { get; set; }
        public DateTime? EndDate { get; set; }
        public double? TotalDirectCost { get; set; }
        public double? ProfitSupervision { get; set; }
        public double? TotalProjectCost { get; set; }
        public List<ScopeOfWork> ScopeOfWork { get; set; }
}
public class ScopeOfWork
{
        public int? ScopeOfWorkId { get; set; }
        public string ScopeOfWorkName { get; set; }
        public List<Materials> Materials { get; set; }
        public int? ProjectId { get; set; }
}
public class Materials
{
        public string MaterialName { get; set; }
        public int? Quantity { get; set; }
        public double? Cost { get; set; }
        public int? ScopeOfWorkId { get; set; }
        //This should be a select list
        public IEnumerable<SelectListItem> Category { get; set; 
}

Supposed to be a Project can have many ScopeOfWork object and the ScopeOfWork object can have many material object. And I will fill the category property of list of categories in the controller.

I just tried to create a view for List ScopeOfWork Object to see if the ScopeOfWork object will show but didn't show in the view.

Controller:

 [HttpGet]
 public ActionResult _CreateProject()
 {
    return View();
 }

 //POST: Create Project
 [HttpPost]
 public ActionResult _CreateProject(ProjectViewModel project)
 {
   return View(project);
 }

View:

@model MigratingDB.Models.ProjectViewModel

@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>ProjectViewModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        <div class="form-group">
            @Html.LabelFor(model => model.ProjectId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProjectId, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProjectId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProjectName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProjectName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProjectName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProjectLocation, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProjectLocation, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProjectLocation, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProjectDescription, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProjectDescription, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProjectDescription, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.WorkArea, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.WorkArea, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.WorkArea, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ModeOfPayment, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ModeOfPayment, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ModeOfPayment, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Duration, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Duration, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Duration, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.StartDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.StartDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.StartDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.EndDate, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.EndDate, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.EndDate, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.TotalDirectCost, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.TotalDirectCost, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.TotalDirectCost, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProfitSupervision, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProfitSupervision, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProfitSupervision, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.TotalProjectCost, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.TotalProjectCost, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.TotalProjectCost, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.ProjectStatus, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.ProjectStatus, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.ProjectStatus, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Kindly give suggestions to setup a correct ViewModel for this and that will allow me to create project with multiple ScopeOfWork and its corresponding materials for each ScopeOfWork created.

UPDATED: I separated the classes in each ViewModel

ProjectViewModel

public class ProjectViewModel
        {
            //tbl Project
            public int? ProjectId { get; set; }
            public string ProjectName { get; set; }
            public string ProjectLocation { get; set; }
            public string ProjectDescription { get; set; }
            public double? WorkArea { get; set; }
            public string ModeOfPayment { get; set; }
            public string Duration { get; set; }
            public DateTime? StartDate { get; set; }
            public DateTime? EndDate { get; set; }
            public double? TotalDirectCost { get; set; }
            public double? ProfitSupervision { get; set; }
            public double? TotalProjectCost { get; set; }
            //SelectList
            public int? ProjectStatus { get; set; }
            //SelectList
            public int? ForemanId { get; set; }
            //SelectList
            public int? ClientId { get; set; }

            //tbl ScopeOfWork
            public List<ScopeOfWorkViewModel> ScopeOfWork { get; set; }
        }

ScopeOfWorkViewModel

 public class ScopeOfWorkViewModel
    {
        public int? ScopeOfWorkId { get; set; }
        public string ScopeOfWorkName { get; set; }
        public List<MaterialsViewModel> Materials { get; set; }
        public int? ProjectId { get; set; }
    }

MaterialsViewModel

public class MaterialsViewModel
{
    public string MaterialName { get; set; }
    public int? Quantity { get; set; }
    public double? Cost { get; set; }
    public int? ScopeOfWorkId { get; set; }
    public IEnumerable<SelectListItem> Category { get; set; }
}
adiga
  • 34,372
  • 9
  • 61
  • 83
progammer101
  • 47
  • 1
  • 8
  • Just a suggestion, shouldn't there be a link in the `ScopeOfWork` class back to the `ProjectViewModel` class? E.g. `public int? ProjectId { get; set; }` or a different name if you want. Assuming each ScopeOfWork has to be linked back to exactly one ProjectViewModel. – Keyur PATEL Jun 06 '17 at 02:52
  • @KeyurPATEL oops, sorry I forgot, lemme update it. Thanks! – progammer101 Jun 06 '17 at 02:55
  • 1
    Apart from `ProjectViewModel` should contain a property which is a collection of `ScopeOfWorkViewModel` and `ScopeOfWorkViewModel` should contain a property which is a collection of `MaterialsViewModel` - do not use data models in your views (and the `ProjectId` and `ScopeOfWorkId` are not required despite @KeyurPATEL comment), what is your problem? You have not even shown how you generate the view. And you do not have a property to bind the selected `Category` to. –  Jun 06 '17 at 04:16
  • The problem is I need to post this data to the controller and save it to my database. @StephenMuecke. What do you mean by containing a property of a collection? Ex. public List ScopeOfWork { get; set; } in the ProjectViewModel. Is this right? Or It should be public virtual ICollection ScopeOfWork{ get; set; } – progammer101 Jun 06 '17 at 04:28
  • `public List ScopeOfWork { get; set; }`. And again, what problem are you having - you have not shown your view. If its correct, then it will bind fine when you submit. –  Jun 06 '17 at 04:37
  • It does not show the ScopeOfWork object or an input box for it, and what I want to happen is when everytime I add a ScopeOfWork object I might be able to add many Materials object – progammer101 Jun 06 '17 at 04:46
  • 1
    There is nothing in your form relating to `ScopeOfWork` properties (or `Materials`). You need a nested `for` loop or `EditorTemplate` to generate the controls. Refer [this answer](http://stackoverflow.com/questions/30094047/html-table-to-ado-net-datatable/30094943#30094943) for an example. –  Jun 06 '17 at 05:03
  • But once I added the ScopeOfWork object in the view, I might be able to access the materials properties right? – progammer101 Jun 06 '17 at 05:18

0 Answers0