2013-08-14 7 views
7

Mam ViewModel, który jest połączony z trzema elementami, aby pobrać dane ze wszystkich obiektów do jednego formularza widoku. Chociaż udało mi się wprowadzić to samo. Ale nie mam pojęcia, jak edytować i zapisywać dane z powrotem do bazy danych. Moje klasy modeli są połączone relacją jeden do jednego.Jak edytować i zapisywać dane ViewModels z powrotem do bazy danych

Moje modele to:

public class Doctor 
{ 
    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 DoctorAvailablity DoctorAvailablity { get; set; } 

} 

public class DoctorAddress 
{ 
    public string Address { get; set; } 
    public string City { get; set; } 
    public int DoctorId { get; set; } 

    public virtual Doctor Doctor { get; set; } 
} 

public class DoctorCharge 
{ 
    public decimal OPDCharge { get; set; } 
    public decimal IPDCharge { get; set; } 
    public int DoctorId { get; set; } 

    public virtual Doctor Doctor { get; set; } 
} 

My ViewModel jest:

public class DoctorViewModel 
    { 
     public Doctor Doctor { get; set; } 
     public DoctorAddress DoctorAddress { get; set; } 
     public DoctorCharge DoctorCharge { get; set; } 

    } 

My Kontroler jest:

public ActionResult Index() 
    { 
     var model = from t1 in db.Doctors 
        join d in db.DoctorAddress on t1.DoctorId equals d.DoctorId into listi 
        join dc in db.DoctorCharges on t1.DoctorId equals dc.DoctorId into listj 

        from d in listi.DefaultIfEmpty() 
        from dc in listj.DefaultIfEmpty() 

        select new DoctorDetailsViewModel.DoctorViewModel { Doctor = t1, DoctorAddress = d, DoctorCharge = dc }; 

     return View(model.ToList()); 

    } 

moim zdaniem jest:

@model XXX.DoctorDetailsViewModel.DoctorViewModel 

@using (Html.BeginForm()) { 
@Html.ValidationSummary(true) 

<fieldset> 
    <legend>Doctor</legend> 

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

    <div class="editor-label"> 
     OPD Charge 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.DoctorCharge.OPDCharge) 
    </div> 

<div class="editor-label"> 
     Address 
    </div> 
    <div class="editor-field"> 
     @Html.EditorFor(model => model.DoctorAddress.Address) 
    </div> <p> 
     <input type="submit" value="Create" /> 
    </p> 
</fieldset>} 

moja klasa kontrolera jest:

public ActionResult Create() 
    { 
     return View(); 
    } 

    // 
    // POST: /Doctor/Create 

    [HttpPost] 
    public ActionResult Create(Doctor doctor) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Doctors.Add(doctor); 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 

     return View(doctor); 
    } 

Proszę mi pomóc jak mogę zrobić. Z góry dziękuję.

+1

Po prostu to dostałeś. Twoja metoda działania otrzymująca POST powinna otrzymać ten sam typ co model widoku, tj. 'DoctorViewModel'. Wiązanie modelu struktury MVC automatycznie zamapuje pola wejściowe na odpowiednie właściwości w modelu widoku na podstawie ich nazw. – asymptoticFault

+0

W jaki sposób podmioty Doctor i DoctorCharge mogą mieć relację jeden-do-jednego? – ataravati

+0

@ataravati Klasa Doctor ma właściwość DoctorCharge i vice versa. – asymptoticFault

Odpowiedz

3

Przede wszystkim, to naprawdę dobrze, że używasz ViewModels ale w tym konkretnym przypadku, to chyba nie jest to konieczne, Twój widok Create mógłby wyglądać następująco:

@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 

Następnie kontroler Doctor:

[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); 
} 

Jeśli chcesz zachować swoje ViewModel może to wyglądać tak:

[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

Rozsądne jest używanie modeli widoku bez względu na to, czy negują one ryzyko przypadkowego ujawnienia właściwości w celu modyfikacji później w linii –

4

Tutaj do tworzenia:

[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); 
} 
1

Dla tej odpowiedzi używam Tom Dykstry Tutorial Guide na Implementing Basic CRUD Functionality with the Entity Framework in ASP.NET MVC Application w ViewModel kontekście.

Samouczek wykorzystuje wywołanie metody TryUpdateModel(TModel, String, String[]) w celu aktualizacji pojedynczego modelu Student w metodzie Edit.

 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 metoda zwraca true czy aktualizacja przebiegła pomyślnie, w przeciwnym wypadku zwraca false. Powyżej pierwszego parametru dla wywołania metody TryUpdateModel jest model Student (studentToUpdate). Drugi parametr jest przedrostkiem do szukania wartości w dostawcy wartości (pusty ciąg ""). 3-ta parametr jest lista właściwości, które zostały zaktualizowane: ”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.

Aby powyższy pracy dla DoctorViewModel, drugi parametr (prefix) należy stosować zbyt.Na przykład dla Doctor modelu

Doctor doctorToUpdate = db.Doctors.Find(id); 

    bool doctorUpdateSuccess = TryUpdateModel(doctorToUpdate, "Doctor", 
           new string[] { "Name", "Speciality" }); 

Przedrostek "Doctor" jest potrzebne do TryUpdateModel wywołanie metody, bo gdy jest używany DoctorViewModel, że nie może znaleźć parametry Doctor modelki inaczej. Na przykład poniżej Watch okna pokazuje, w jaki sposób wartości formularza są pokazane w Visual Studio w trybie debugowania dla metody edycji:

enter image description here

w Edit zobaczyć poniższy kod:

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

tworzy następujące HTML :

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

Oto kod Edit sposobu 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); 
} 

Jest to także dobry pomysł, aby dodać ValidateAntiForgeryToken atrybut do kodu, aby zapobiec cross-site request forgery.

Aktualizacja

Ja również kilka drobnych zmian do oszacowania klas dodając atrybuty. Dzięki temu modele z relacji można znaleźć łatwiej:

DoctorAddress doctorAddressToUpdate = doctorToUpdate.DoctorAddress; 

DoctorCharge doctorChargeToUpdate = doctorToUpdate.DoctorCharge; 

Dlatego modele poniżej mają [Key] lub [Key, ForeignKey("Doctor")] atrybuty

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; } 
} 

Wszelkie zwrotnego w stosunku aktualizacjach ViewModel jest mile widziane. Ostatnio stanąłem przed podobnym problemem w moim własnym projekcie, i to było podejście, którego użyłem, aby rozwiązać ten problem. Sądzę, że istnieją alternatywne sposoby radzenia sobie z tym problemem.

Powiązane problemy