How to Edit and Save ViewModels data back to database

后端 未结 3 1223
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-02-05 23:40

I have a ViewModel which is joined by three Entities to get data from all entities into one view form. Although i succeeded to implement the same. But i have no idea how to Edit

相关标签:
3条回答
  • 2021-02-05 23:53

    First of all, it's really good that you are using ViewModels but for this particular case, it's probably not necessary, your Create view could look like this:

    @model MvcApplication1.Models.Doctor
    
    //other fields here
    
    <div class="editor-label">
            @Html.LabelFor(model => model.DoctorAddress.Address)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.DoctorAddress.Address)
            @Html.ValidationMessageFor(model => model.DoctorAddress.Address)
        </div>
    
        <div class="editor-label">
            @Html.LabelFor(model => model.DoctorCharge.IPDCharge)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.DoctorCharge.IPDCharge)
            @Html.ValidationMessageFor(model => model.DoctorCharge.IPDCharge)
    </div>
    
    //other fields here
    

    Then your Doctor controller:

    [HttpPost]
    public ActionResult Create(Doctor doctor)
    {
        if (ModelState.IsValid)
        {
            db.Doctors.Add(doctor);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
    
        return View(doctor);
    }
    
    Your `Edit` action could then look like this:
    
    [HttpGet]
    public ActionResult Edit(int id = 0)
    {
        Doctor doctor = db.Doctors.Find(id);
        if (doctor == null)
        {
            return HttpNotFound();
        }
        return View(doctor);
    }
    
    [HttpPost]
    public ActionResult Edit(Doctor doctor)
    {
        if (ModelState.IsValid)
        {
            db.Entry(doctor).State = EntityState.Modified;
            db.Entry(doctor.DoctorAddress).State = EntityState.Modified;
            db.Entry(doctor.DoctorCharge).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(doctor);
    }
    

    If you want to keep your ViewModel then it could look like this:

    [HttpPost]
    public ActionResult Edit(DoctorViewModel doctorViewModel)
    {
        if (ModelState.IsValid)
        {
            var doctorAddress = doctorViewModel.DoctorAddress;
            var doctorCharge = doctorViewModel.DoctorCharge;
            var doctor = doctorViewModel.Doctor;
            db.Entry(doctorAddress).State = EntityState.Modified;
            db.Entry(doctorCharge).State = EntityState.Modified;
            db.Entry(doctor).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(doctor);
    }
    
    0 讨论(0)
  • 2021-02-06 00:17

    Here, for creating:

    [HttpPost]
    public ActionResult Create(DoctorViewModel model)
    {
        if (ModelState.IsValid)
        {
            model.Doctor.DoctorAddress = model.DoctorAddress;
            model.Doctor.DoctorCharge = model.DoctorCharge;
            db.Doctors.Add(doctor);
            db.SaveChanges();
            return RedirectToAction("Index");
        }
    
        return View(doctor);
    }
    
    0 讨论(0)
  • 2021-02-06 00:18

    For this answer I'm using Tom Dykstra’s Tutorial Guide on Implementing Basic CRUD Functionality with the Entity Framework in ASP.NET MVC Application in ViewModel context.

    The tutorial uses TryUpdateModel(TModel, String, String[]) method call to update a single Student model in Edit method.

         var studentToUpdate = db.Students.Find(id);
    
         if (TryUpdateModel(studentToUpdate, "",
               new string[] { "LastName", "FirstMidName", "EnrollmentDate" })) {
               //Save all changes made in this context to the underlying database 
               db.SaveChanges();
               return RedirectToAction("Index");
         }
    

    TryUpdateModel method returns true if update was successful, otherwise it returns false. Above the first parameter for TryUpdateModel method call is the Student model (studentToUpdate). The 2nd parameter is a prefix for looking values in the value provider (empty string ""). 3rd parameter is list of properties that are updated: ”LastName", "FirstMidName", "EnrollmentDate"

    As a best practice to prevent overposting, the fields that you want to be updateable by the Edit page are whitelisted in the TryUpdateModel parameters.

    To make the above work for DoctorViewModel, the second parameter (prefix) needs to be used too. For example for Doctor model:

      Doctor doctorToUpdate = db.Doctors.Find(id);
    
      bool doctorUpdateSuccess = TryUpdateModel(doctorToUpdate, "Doctor", 
                                    new string[] { "Name", "Speciality" });
    

    The prefix "Doctor" is needed for TryUpdateModel method call, because when DoctorViewModel is used, it cannot find Doctor model’s parameters otherwise. For example the below Watch window shows how the form values are shown in Visual Studio in debug mode for edit method:

    in Edit view the code below:

    <div class="editor-field">
         @Html.EditorFor(model => model.Doctor.Name)
    </div>
    

    creates the following html:

    <div class="editor-field">
        <input class="text-box single-line" id="Doctor_Name" 
         name="Doctor.Name" type="text" value="Foo"/>
    </div> 
    

    Here’s code for Edit method for DoctorViewModel

    [HttpPost, ActionName("Edit")]
    public ActionResult EditPost(int? id)
    {
        if (id == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
    
        Doctor doctorToUpdate = db.Doctors.Find(id);
        if (doctorToUpdate == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        bool doctorUpdateSuccess = TryUpdateModel(doctorToUpdate, "Doctor", new string[] { "Name", "Speciality" });
    
        DoctorAddress doctorAddressToUpdate = doctorToUpdate.DoctorAddress;
        if (doctorAddressToUpdate == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        bool doctorAddressUpdateSuccess = TryUpdateModel(doctorAddressToUpdate, "DoctorAddress", new string[] { "Address" });
    
        DoctorCharge doctorChargeToUpdate = doctorToUpdate.DoctorCharge;
        if (doctorChargeToUpdate == null)
        {
            return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        bool doctorChargeUpdateSuccess = TryUpdateModel(doctorChargeToUpdate, "DoctorCharge", new string[] { "OPDCharge" });
    
        // if all models have been successfully updated
        // then save changes to database
        if (doctorUpdateSuccess &&
            doctorAddressUpdateSuccess &&
            doctorChargeUpdateSuccess)
        {
            db.SaveChanges();
            return RedirectToAction("Index");
        }
    
        DoctorDetailsViewModel.DoctorViewModel viewModel = new DoctorDetailsViewModel.DoctorViewModel();
        viewModel.Doctor = doctorToUpdate;
        viewModel.DoctorAddress = doctorAddressToUpdate;
        viewModel.DoctorCharge = doctorChargeToUpdate;
        return View(viewModel);
    }
    

    It’s also a good idea to add ValidateAntiForgeryToken attribute to the code to prevent cross-site request forgery.

    Update

    I also made some small changes to model classes by adding attributes. This enables models with relationship to be found more easily:

    DoctorAddress doctorAddressToUpdate = doctorToUpdate.DoctorAddress;
    
    DoctorCharge doctorChargeToUpdate = doctorToUpdate.DoctorCharge;
    

    Therefore models below have [Key] or [Key, ForeignKey("Doctor")] attributes

    public class Doctor
    {
        [Key]
        public int DoctorId { get; set; }
        public string Name { get; set; }
        public string Speciality { get; set; }
    
        public virtual DoctorAddress DoctorAddress { get; set; }
        public virtual DoctorCharge DoctorCharge { get; set; }
        public virtual DoctorAvailability DoctorAvailablity { get; set; }
    
    }
    
    public class DoctorAddress
    {
        public string Address { get; set; }
        public string City { get; set; }
    
        [Key, ForeignKey("Doctor")]
        public int DoctorId { get; set; }
        public virtual Doctor Doctor { get; set; }
    }
    
    public class DoctorCharge
    {
        public decimal OPDCharge { get; set; }
        public decimal IPDCharge { get; set; }
    
        [Key, ForeignKey("Doctor")]
        public int DoctorId { get; set; }
        public virtual Doctor Doctor { get; set; }
    }
    

    Any feedback in relation ViewModel updates is welcomed. Recently I faced similar problem in my own project, and this was the approach I used to solve this issue. I guess there are alternative ways to handle this issue.

    0 讨论(0)
提交回复
热议问题