asp.net-mvc 如何编辑 ViewModels 数据并将其保存回数据库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18237945/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to Edit and Save ViewModels data back to database
提问by Jaan
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 and Save data back to the database. My model classes are joined by one to one relationship.
我有一个 ViewModel,它由三个实体连接,以将所有实体的数据放入一个视图表单中。虽然我成功地实现了相同的。但我不知道如何编辑数据并将其保存回数据库。我的模型类通过一对一的关系连接起来。
My Models are:
我的模型是:
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 is:
我的视图模型是:
public class DoctorViewModel
{
public Doctor Doctor { get; set; }
public DoctorAddress DoctorAddress { get; set; }
public DoctorCharge DoctorCharge { get; set; }
}
My Controller is:
我的控制器是:
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());
}
My View is:
我的观点是:
@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>}
My Controller Class is:
我的控制器类是:
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);
}
Please help me how do i do. Thanks in advance.
请帮我我该怎么做。提前致谢。
回答by SOfanatic
First of all, it's really good that you are using ViewModelsbut for this particular case, it's probably not necessary, your Createview could look like this:
首先,您使用的确实很好,ViewModels但是对于这种特殊情况,可能没有必要,您的Create视图可能如下所示:
@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 Doctorcontroller:
然后你的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);
}
If you want to keep your ViewModel then it could look like this:
如果你想保留你的 ViewModel 那么它可能看起来像这样:
[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);
}
回答by Amin Saqi
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);
}
回答by jyrkim
For this answer I'm using Tom Dykstra'sTutorial Guide on Implementing Basic CRUD Functionality with the Entity Framework in ASP.NET MVC Applicationin ViewModelcontext.
对于这个答案,我使用Tom Dykstra 的教程指南,在ViewModel上下文中使用 ASP.NET MVC 应用程序中的实体框架实现基本 CRUD 功能。
The tutorial uses TryUpdateModel(TModel, String, String[])method call to update a single Studentmodel in Editmethod.
本教程使用TryUpdateModel(TModel, String, String[])方法调用来更新方法中的单个Student模型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");
}
TryUpdateModelmethod returns trueif update was successful, otherwise it returns false. Above the first parameter for TryUpdateModelmethod call is the Studentmodel (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"
TryUpdateModeltrue如果更新成功,则方法返回,否则返回false。TryUpdateModel方法调用的第一个参数上方是Student模型 ( studentToUpdate)。第二个参数是在值提供程序中查找值的前缀(空字符串"")。第三个参数是更新的属性列表:”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.
作为防止过度发布的最佳实践,您希望通过“编辑”页面更新的字段在 TryUpdateModel 参数中列入白名单。
To make the above work for DoctorViewModel, the second parameter (prefix) needs to be used too. For example for Doctormodel:
为了使上述工作适用于DoctorViewModel,还需要使用第二个参数(前缀)。例如Doctor模型:
Doctor doctorToUpdate = db.Doctors.Find(id);
bool doctorUpdateSuccess = TryUpdateModel(doctorToUpdate, "Doctor",
new string[] { "Name", "Speciality" });
The prefix "Doctor"is needed for TryUpdateModelmethod call, because when DoctorViewModelis used, it cannot find Doctormodel'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:
方法调用"Doctor"需要前缀TryUpdateModel,因为DoctorViewModel使用时,否则无法找到Doctor模型的参数。例如,下面的观察窗口显示了表单值如何在 Visual Studio 中以调试模式显示在编辑方法中:
in Editview the code below:
在Edit查看下面的代码:
<div class="editor-field">
@Html.EditorFor(model => model.Doctor.Name)
</div>
creates the following html:
创建以下 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 Editmethod for DoctorViewModel
这是Edit方法的代码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 ValidateAntiForgeryTokenattribute to the code to prevent cross-site request forgery.
在代码中添加ValidateAntiForgeryToken属性以防止跨站点请求伪造也是一个好主意。
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
因此下面的模型具有[Key]或[Key, ForeignKey("Doctor")]属性
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.
欢迎任何有关 ViewModel 更新的反馈。最近我在自己的项目中遇到了类似的问题,这就是我用来解决这个问题的方法。我想有其他方法可以处理这个问题。


