简体   繁体   中英

ASP.NET MVC multiple models single set of Create, View, Edit and Delete pages

I have a problem figuring out how to implement the Create, Edit and Delete pages for a case where there are multiple Models that I want to display in a single set of Views. I'm using Visual Studio 2013 and MVC 5. And I also use the latest Entity Framework 6.1.1.

So far I've got the Models:

public class CompositeModel
    {
        public int ID { get; set; }

        public MediaPlan MediaPlanModel { get; set; }
        public ContactInfo ContactInfoModel { get; set; }
        public MediaPlanDate MediaPlanDateModel { get; set; }

        [Timestamp]
        public byte[] RowVersion { get; set; }


    }

public class MediaPlan
{
    public int ID { get; set; }

    public string Client { get; set; }
    public string Product { get; set; }
    public string AE { get; set; }
    public string Supervisor { get; set; }
    public string Traffic { get; set; }
}

public class ContactInfo
{
    public int ID { get; set; }

    public string CompanyName { get; set; }
    public string CompanyContact { get; set; }
    public string CompanyAddress { get; set; }
    public string CompanyPhoneNumber { get; set; }
    public string CompanyEmail { get; set; }
}

public class MediaPlanDate
{
    public int ID { get; set; }

    public string Client { get; set; }
    public string Product { get; set; }
    public string AE { get; set; }
    public string Supervisor { get; set; }
    public string Traffic { get; set; }
}

Using Code First approach the database was created correctly.

I did auto-generate the CompositeModelsController.cs:

public class CompositeModelsController : Controller
{
    private MprContext db = new MprContext();

    // GET: CompositeModels
    public ActionResult Index()
    {
        //var compositeModel = new CompositeModel();
        //compositeModel.MediaPlanModel = new MediaPlan();
        //compositeModel.ContactInfoModel = new ContactInfo();
        //compositeModel.MediaPlanDateModel = new MediaPlanDate();

        //return View(compositeModel.ToList());
        return View(db.Composites.ToList());
    }

    // GET: CompositeModels/Details/5
    public ActionResult Details(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        CompositeModel compositeModel = db.Composites.Find(id);
        if (compositeModel == null)
        {
            return HttpNotFound();
        }
        return View(compositeModel);
    }

    // GET: CompositeModels/Create
    public ActionResult Create()
    {
        return View();
    }

    // POST: CompositeModels/Create
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind(Include = "ID,RowVersion")] CompositeModel compositeModel)
    {
        if (ModelState.IsValid)
        {
            db.Composites.Add(compositeModel);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        return View(compositeModel);
    }

    // GET: CompositeModels/Edit/5
    public ActionResult Edit(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        CompositeModel compositeModel = db.Composites.Find(id);
        if (compositeModel == null)
        {
            return HttpNotFound();
        }
        return View(compositeModel);
    }

    // POST: CompositeModels/Edit/5
    // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
    // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit([Bind(Include = "ID,RowVersion")] CompositeModel compositeModel)
    {
        if (ModelState.IsValid)
        {
            db.Entry(compositeModel).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(compositeModel);
    }

    // GET: CompositeModels/Delete/5
    public ActionResult Delete(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        CompositeModel compositeModel = db.Composites.Find(id);
        if (compositeModel == null)
        {
            return HttpNotFound();
        }
        return View(compositeModel);
    }

    // POST: CompositeModels/Delete/5
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id)
    {
        CompositeModel compositeModel = db.Composites.Find(id);
        db.Composites.Remove(compositeModel);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            db.Dispose();
        }
        base.Dispose(disposing);
    }
}

I did not expect it to work and it doesn't.

I was able to get the Index to work.

I also created Editor Templates:

@model Online_Mpr.Models.MediaPlan

<h2>MediaPlan</h2>


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

    <div class="form-horizontal">
        <h4>MediaPlan</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.ID)

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

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

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

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

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

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

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

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

And so forth for the other Models.

Then I have the Create View:

@model Online_Mpr.Models.CompositeModel

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


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

    <div class="form-horizontal">
        <h4>CompositeModel</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.EditorFor(model => model.MediaPlanModel)
        @Html.EditorFor(model => model.MediaPlanDateModel)
        @Html.EditorFor(model => model.ContactInfoModel)
        <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>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

I was planning to do similar thing for the Edit View.

When I go to the Create View it displays the edit boxes for all the elements but how do I get to code the controller that will create the records in the database. Preferably I would like to have just one "Create" button in the Create View that would create all four records.

Any help is appreciated as I scoured the internet for info about similar cases and could not find any.

Also if you could provide code samples. They don't have to be elaborate but the core thought will lead me on.

Thanks, -Arek

Your CompositeModel is essentially a view model. This class shouldn't have an Id property and should n't actually be tied to Entity Framework in any way (don't add a DbSet for it). All it needs to do is contain properties for the other model instances that you want to edit. You should also add a constructor to this class that news up all other models inside:

public class CompositeModel
{
    public CompositeModel()
    {
        MediaPlanModel = new MediaPlan();
        ContactInfoModel = new ContactInfo();
        MediaPlanDateModel = new MediaPlanDate();
    }

    ...
}

Then in post version of your Create action. You'll simply save each sub-model individually:

[HttpPost]
public ActionResult Create(CompositeModel model)
{
    if (ModelState.IsValid)
    {
        db.MediaPlans.Add(model.MediaPlanModel);
        db.ContactInfos.Add(model.ContactInfoModel);
        db.MediaPlanDates.Add(model.MediaPlanDateModel)
        db.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(model);
}

For your edit version:

[HttpPost]
public ActionResult Edit(CompositeModel model)
{
    if (ModelState.IsValid)
    {
        db.Entry(model.MediaPlanModel).State = EntityState.Modified;
        db.Entry(model.ContactInfoModel).State = EntityState.Modified;
        db.Entry(model.MediaPlanDateModel).State = EntityState.Modified;
        db.SaveChanges();

        return RedirectToAction("Index");
    }

    return View(model);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM