填充 ViewModel 的正确方法?
Proper way to populate a ViewModel?
我正在为工作开发一个网络应用程序,并且我正在使用标准的 CRUD 样式交互。但是,有些字段我不希望用户更新,因此我将它们从视图中删除。但是,如果我没有显式设置这些字段,它们会在数据库中更新模型时被清除。
我关心为我的 ViewModels 填充字段的正确方法是什么。
我的粗略想法是这样的:
我的视图模型:
public class EditSoftwareTrackingViewModel
{
public EditSoftwareTrackingViewModel(SoftwareTracking model)
{
Id = model.Id;
SoftwareId = model.SoftwareId;
ComputerId = model.ComputerId;
SoftwareActionId = model.SoftwareActionId;
LastModified = model.LastModified;
Computer = model.Computer;
Software = model.Software;
SoftwareAction = model.SoftwareAction;
}
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
我的主要模型
[Table("asset.SoftwareTracking")]
public partial class SoftwareTracking
{
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Date Entered")]
public DateTime? EnteredDate { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
我的控制器使用视图模型
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
EditSoftwareTrackingViewModel softwaretracking = new EditSoftwareTrackingViewModel(db.SoftwareTrackings.Find(id));
if (softwaretracking == null)
{
return HttpNotFound();
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
softwaretracking.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
有更好的选择吗?或者我应该继续以这种方式创建我的视图模型吗?
编辑
我的业务逻辑和观点
private void GeneratePageData(int? id = null)
{
ViewBag.Computers = new SelectList(db.Computers, "Id", "ComputerName");
ViewBag.SoftwareActions = new SelectList(db.SoftwareActions, "Id", "ActionPerformed");
var usedSoft = (from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3)
select softTrack.Software);
var softwareList = (from soft in db.Softwares
where (
((from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3 && softTrack.SoftwareId == soft.Id)
select softTrack.Software).Count() < soft.KeyQuantity)
&& !(soft.AssetStatusId == 4 || soft.AssetStatusId == 5)
|| soft.Id == id)
select soft).ToList();
ViewBag.SoftwareList = softwareList.Select(t => new SelectListItem
{
Text = t.SoftwareIdNameFull,
Value = t.Id.ToString()
});
}
还有我的看法
@model Lighthouse_Asset_Manager.Models.EditSoftwareTrackingViewModel
@{
ViewBag.Title = "Edit Software Install";
Layout = "";
}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<h4 class="modal-title" id="myModalLabel">Edit Software Install</h4>
</div>
<div class="modal-body">
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "computerForm" }))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.Id)
<div class="form-horizontal">
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.SoftwareId, "Software", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("SoftwareId", (IEnumerable<SelectListItem>)ViewBag.SoftwareList, "-- Select --", new
{
@style = "width:100%",
@class = "select2"
})
@Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ComputerId, "Computer", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ComputerId", (IEnumerable<SelectListItem>)ViewBag.Computers, "-- Select --", new
{
@style = "width:100%",
@class = "select2"
})
@Html.ValidationMessageFor(model => model.ComputerId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SoftwareActionId, "Action", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("SoftwareActionId", (IEnumerable<SelectListItem>)ViewBag.SoftwareActions, "-- Select --", new
{
@style = "width:100%",
@class = "form-control"
})
@Html.ValidationMessageFor(model => model.SoftwareActionId)
</div>
</div>
<div class="form-actions no-color">
<button type="submit" class="btn btn-primary btn-sm"><i class="fa fa-floppy-o"></i> Edit Install Record</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
</div>
}
</div>
在不从 Db 加载对象的情况下修补更新您的模型。试试 Attach:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
var softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.SoftwareTrackings.Attach(softwareTrack);
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.ComputerId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.LastModified).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Software).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareAction).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareActionId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareId).IsModified = true;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
关于第二个问题是使用ViewModel还是直接使用Model。这真的是一个见仁见智的问题,每种方法都有其优点和缺点。我对此没有强烈的意见,我只是想指出这些利弊供您考虑:
- 直接使用模型使我们无需创建 viewModel,从而减少源代码并避免映射逻辑,但它会混淆问题。因为您对域逻辑和与客户端通信使用相同的模型,所以如果我们不考虑这一点,对模型的任何更改都可能传播到客户端。
- 使用 viewModel 是分离关注点的好方法,但它需要更多的努力和映射逻辑(可能会稍微降低性能)。为了有效地应用 ViewModel,我建议使用映射器:https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
您应该使用 AutoMapper 使 Model 和 ViewModel 之间的映射更清晰。首先使用此代码创建映射器。
Mapper.CreateMap<SoftwareTracking, EditSoftwareTrackingViewModel>();
Mapper.CreateMap<EditSoftwareTrackingViewModel, SoftwareTracking>();
如果您想从模型创建视图模型,请执行以下操作:
public ActionResult Edit(int? id)
{
SoftwareTracking tracking = db.SoftwareTrackings.Find(id);
EditSoftwareTrackingViewModel viewmodel =
Mapper.Map<SoftwareTracking, EditSoftwareTrackingViewModel>(tracking);
return View(viewmodel);
}
当您想将视图模型中的信息填充回模型时,请执行此操作
public ActionResult Edit(EditSoftwareTrackingViewModel vm)
{
if (ModelState.IsValid)
{
vm.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack =
Mapper.Map<EditSoftwareTrackingViewModel, SoftwareTracking>(vm, softwareTrack);
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
您使用视图模型的方法很好。 this question explains some of the benefits including preventing over-posting attacks, using view specific display and validation attributes and including view specific properties such as SelectLists
. Tools such as automapper 的答案可以让您轻松地在数据和视图模型之间进行映射,并减少控制器中的代码。我建议对您的视图模型进行一些更改。 LastModified
、Computer
、Software
和 SoftwareAction
属性不是必需的(您不绑定这些属性),我会在模型中包含 SelectList
属性而不是 ViewBag
查看模型
public class EditSoftwareTrackingViewModel
{
public int Id { get; set; }
[Display(Name="Software")]
public int SoftwareId { get; set; }
[Display(Name="Computer")]
public int ComputerId { get; set; }
[Display(Name="Software Action")]
public int SoftwareActionId { get; set; }
public SelectList Computers { get; set; }
public SelectList SoftwareActions{ get; set; }
public SelectList SoftwareList{ get; set; }
}
然后更改GeneratePageData()
方法接受视图模型
private void GeneratePageData(EditSoftwareTrackingViewModel model)
{
model.Computers = new SelectList(db.Computers, "Id", "ComputerName");
....
并在视图中(始终最好使用强类型助手)
@Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { @class = "select2" })
其他一些注意事项。
- 您应该使用
[Display(Name="..")]
属性(不是
[DisplayName(..)]
)
- 当你设置
LastModified
属性时,你应该考虑使用
UCT
次。
- 视图中不需要
Id
属性 的隐藏输入
(假设您使用默认的 {controller}/{action}/{id}
路由
mapping) - 它被添加到路由值中并且无论如何都会被绑定
- 除非您特别想要表单的
id
属性,否则您可以
只需使用 @using(Html.BeginForm()) {
- 您不需要
LabelFor()
中的第二个参数 - 它可以只是
Html.LabelFor(m => m.SoftwareId, new { @class = "control-label
col-md-2" })
因为您在 [Display]
中指定了它
属性
最后,如果您想进一步简化您的视图,您可以考虑自定义 EditorTemplates
或 html 助手,如 this answer 中所示,这将允许您替换
<div class="form-group">
@Html.LabelFor(model => model.SoftwareId, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { @class = "select2" })
@Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
与(自定义 EditorTemplate
)
@Html.EditorFor(m => m.SoftwareId, "BootstrapSelect", Model.SoftwareList)
或(自定义HtmlHelper
)
@Html.BootstrapDropDownFor(m => m.SoftwareId, Model.SoftwareList)
这是模型Class
[Table("CURRENCY")]
public class CurrencyClass : ICurrency
{
private Int32 mCURRENCY_ID = default(Int32);
[Key]
public virtual Int32 CURRENCY_ID
{
get { return mCURRENCY_ID; }
set { mCURRENCY_ID = value; }
}
private string mCURRENCY_NAME = default(string);
public virtual string CURRENCY_NAME
{
get { return mCURRENCY_NAME;}
set { mCURRENCY_NAME = value;}
}
private string mCURRENCY_DESC = default(string);
public virtual string CURRENCY_DESC
{
get { return mCURRENCY_DESC; }
set { mCURRENCY_DESC = value; }
}
private string mCURRENCY_SYMBOLE = default(string);
public virtual string CURRENCY_SYMBOLE
{
get { return mCURRENCY_SYMBOLE; }
set { mCURRENCY_SYMBOLE = value; }
}
private Int32 mcreated_by = default(Int32);
public virtual Int32 created_by
{
get { return mcreated_by; }
set { mcreated_by = value; }
}
private DateTime mcreated_date = default(DateTime);
public virtual DateTime created_date
{
get { return mcreated_date; }
set { mcreated_date = value; }
}
private Int32 mmodified_by = default(Int32);
public virtual Int32 modified_by
{
get { return mmodified_by; }
set { mmodified_by = value; }
}
private DateTime mmodified_date = default(DateTime);
public virtual DateTime modified_date
{
get { return mmodified_date; }
set { mmodified_date = value; }
}
}
这是视图模型
public class CurrencyViewModel
{
[Key]
public Int32 CURRENCY_Id { get; set; }
[Required(ErrorMessage="Currency Name is required")]
public string CURRENCY_NAME { get; set; }
[Required(ErrorMessage="Currency Description is required")]
public string CURRENCY_DESC { get; set; }
[Required(ErrorMessage = "Currency Symbole is Required")]
public string CURRENCY_SYMBOLE { get; set; }
}
这是行动
[HttpPost]
[ActionName("Create")]
public ActionResult Create(CurrencyViewModel vm)
{
if (!ModelState.IsValid)
{
return View("Create");
}
obj.CURRENCY_NAME = vm.CURRENCY_NAME;
obj.CURRENCY_DESC = vm.CURRENCY_DESC;
obj.CURRENCY_SYMBOLE = vm.CURRENCY_SYMBOLE;
obj.created_by = 1;
obj.created_date = DateTime.Now;
obj.modified_by = 1;
obj.modified_date = DateTime.Now;
db.Currencies.Add(obj);
db.SaveChanges();
return RedirectToAction("Index");
}
我正在为工作开发一个网络应用程序,并且我正在使用标准的 CRUD 样式交互。但是,有些字段我不希望用户更新,因此我将它们从视图中删除。但是,如果我没有显式设置这些字段,它们会在数据库中更新模型时被清除。
我关心为我的 ViewModels 填充字段的正确方法是什么。
我的粗略想法是这样的:
我的视图模型:
public class EditSoftwareTrackingViewModel
{
public EditSoftwareTrackingViewModel(SoftwareTracking model)
{
Id = model.Id;
SoftwareId = model.SoftwareId;
ComputerId = model.ComputerId;
SoftwareActionId = model.SoftwareActionId;
LastModified = model.LastModified;
Computer = model.Computer;
Software = model.Software;
SoftwareAction = model.SoftwareAction;
}
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
我的主要模型
[Table("asset.SoftwareTracking")]
public partial class SoftwareTracking
{
public int Id { get; set; }
[DisplayName("Software")]
public int SoftwareId { get; set; }
[DisplayName("Computer")]
public int ComputerId { get; set; }
[DisplayName("Date Entered")]
public DateTime? EnteredDate { get; set; }
[DisplayName("Software Action")]
public int SoftwareActionId { get; set; }
[DisplayName("Last Modified")]
public DateTime? LastModified { get; set; }
public virtual Computer Computer { get; set; }
public virtual Software Software { get; set; }
public virtual SoftwareAction SoftwareAction { get; set; }
}
我的控制器使用视图模型
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
EditSoftwareTrackingViewModel softwaretracking = new EditSoftwareTrackingViewModel(db.SoftwareTrackings.Find(id));
if (softwaretracking == null)
{
return HttpNotFound();
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
softwaretracking.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
有更好的选择吗?或者我应该继续以这种方式创建我的视图模型吗?
编辑
我的业务逻辑和观点
private void GeneratePageData(int? id = null)
{
ViewBag.Computers = new SelectList(db.Computers, "Id", "ComputerName");
ViewBag.SoftwareActions = new SelectList(db.SoftwareActions, "Id", "ActionPerformed");
var usedSoft = (from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3)
select softTrack.Software);
var softwareList = (from soft in db.Softwares
where (
((from softTrack in db.SoftwareTrackings
where (softTrack.SoftwareActionId != 3 && softTrack.SoftwareId == soft.Id)
select softTrack.Software).Count() < soft.KeyQuantity)
&& !(soft.AssetStatusId == 4 || soft.AssetStatusId == 5)
|| soft.Id == id)
select soft).ToList();
ViewBag.SoftwareList = softwareList.Select(t => new SelectListItem
{
Text = t.SoftwareIdNameFull,
Value = t.Id.ToString()
});
}
还有我的看法
@model Lighthouse_Asset_Manager.Models.EditSoftwareTrackingViewModel
@{
ViewBag.Title = "Edit Software Install";
Layout = "";
}
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">
×
</button>
<h4 class="modal-title" id="myModalLabel">Edit Software Install</h4>
</div>
<div class="modal-body">
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "computerForm" }))
{
@Html.AntiForgeryToken()
@Html.HiddenFor(model => model.Id)
<div class="form-horizontal">
@Html.ValidationSummary(true)
<div class="form-group">
@Html.LabelFor(model => model.SoftwareId, "Software", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("SoftwareId", (IEnumerable<SelectListItem>)ViewBag.SoftwareList, "-- Select --", new
{
@style = "width:100%",
@class = "select2"
})
@Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.ComputerId, "Computer", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("ComputerId", (IEnumerable<SelectListItem>)ViewBag.Computers, "-- Select --", new
{
@style = "width:100%",
@class = "select2"
})
@Html.ValidationMessageFor(model => model.ComputerId)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.SoftwareActionId, "Action", new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownList("SoftwareActionId", (IEnumerable<SelectListItem>)ViewBag.SoftwareActions, "-- Select --", new
{
@style = "width:100%",
@class = "form-control"
})
@Html.ValidationMessageFor(model => model.SoftwareActionId)
</div>
</div>
<div class="form-actions no-color">
<button type="submit" class="btn btn-primary btn-sm"><i class="fa fa-floppy-o"></i> Edit Install Record</button>
<button type="button" class="btn btn-default" data-dismiss="modal">
Cancel
</button>
</div>
</div>
}
</div>
在不从 Db 加载对象的情况下修补更新您的模型。试试 Attach:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Edit(EditSoftwareTrackingViewModel softwaretracking)
{
if (ModelState.IsValid)
{
var softwareTrack = new SoftwareTracking
{
Computer = softwaretracking.Computer,
ComputerId = softwaretracking.ComputerId,
LastModified = softwaretracking.LastModified,
Software = softwaretracking.Software,
SoftwareAction = softwaretracking.SoftwareAction,
SoftwareActionId = softwaretracking.SoftwareActionId,
SoftwareId = softwaretracking.SoftwareId,
EnteredDate = softwareTrack.EnteredDate
};
db.SoftwareTrackings.Attach(softwareTrack);
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.ComputerId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.LastModified).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Computer).IsModified = true;
db.Entry(softwareTrack).Property(a => a.Software).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareAction).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareActionId).IsModified = true;
db.Entry(softwareTrack).Property(a => a.SoftwareId).IsModified = true;
db.SaveChanges();
return RedirectToAction("Index");
}
GeneratePageData(softwaretracking.Software.Id);
return View(softwaretracking);
}
关于第二个问题是使用ViewModel还是直接使用Model。这真的是一个见仁见智的问题,每种方法都有其优点和缺点。我对此没有强烈的意见,我只是想指出这些利弊供您考虑:
- 直接使用模型使我们无需创建 viewModel,从而减少源代码并避免映射逻辑,但它会混淆问题。因为您对域逻辑和与客户端通信使用相同的模型,所以如果我们不考虑这一点,对模型的任何更改都可能传播到客户端。
- 使用 viewModel 是分离关注点的好方法,但它需要更多的努力和映射逻辑(可能会稍微降低性能)。为了有效地应用 ViewModel,我建议使用映射器:https://github.com/AutoMapper/AutoMapper/wiki/Getting-started
您应该使用 AutoMapper 使 Model 和 ViewModel 之间的映射更清晰。首先使用此代码创建映射器。
Mapper.CreateMap<SoftwareTracking, EditSoftwareTrackingViewModel>();
Mapper.CreateMap<EditSoftwareTrackingViewModel, SoftwareTracking>();
如果您想从模型创建视图模型,请执行以下操作:
public ActionResult Edit(int? id)
{
SoftwareTracking tracking = db.SoftwareTrackings.Find(id);
EditSoftwareTrackingViewModel viewmodel =
Mapper.Map<SoftwareTracking, EditSoftwareTrackingViewModel>(tracking);
return View(viewmodel);
}
当您想将视图模型中的信息填充回模型时,请执行此操作
public ActionResult Edit(EditSoftwareTrackingViewModel vm)
{
if (ModelState.IsValid)
{
vm.LastModified = DateTime.Now;
var softwareTrack = db.SoftwareTrackings.Find(softwaretracking.Id);
softwareTrack =
Mapper.Map<EditSoftwareTrackingViewModel, SoftwareTracking>(vm, softwareTrack);
db.Entry(softwareTrack).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
您使用视图模型的方法很好。 this question explains some of the benefits including preventing over-posting attacks, using view specific display and validation attributes and including view specific properties such as SelectLists
. Tools such as automapper 的答案可以让您轻松地在数据和视图模型之间进行映射,并减少控制器中的代码。我建议对您的视图模型进行一些更改。 LastModified
、Computer
、Software
和 SoftwareAction
属性不是必需的(您不绑定这些属性),我会在模型中包含 SelectList
属性而不是 ViewBag
查看模型
public class EditSoftwareTrackingViewModel
{
public int Id { get; set; }
[Display(Name="Software")]
public int SoftwareId { get; set; }
[Display(Name="Computer")]
public int ComputerId { get; set; }
[Display(Name="Software Action")]
public int SoftwareActionId { get; set; }
public SelectList Computers { get; set; }
public SelectList SoftwareActions{ get; set; }
public SelectList SoftwareList{ get; set; }
}
然后更改GeneratePageData()
方法接受视图模型
private void GeneratePageData(EditSoftwareTrackingViewModel model)
{
model.Computers = new SelectList(db.Computers, "Id", "ComputerName");
....
并在视图中(始终最好使用强类型助手)
@Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { @class = "select2" })
其他一些注意事项。
- 您应该使用
[Display(Name="..")]
属性(不是[DisplayName(..)]
) - 当你设置
LastModified
属性时,你应该考虑使用UCT
次。 - 视图中不需要
Id
属性 的隐藏输入 (假设您使用默认的{controller}/{action}/{id}
路由 mapping) - 它被添加到路由值中并且无论如何都会被绑定 - 除非您特别想要表单的
id
属性,否则您可以 只需使用@using(Html.BeginForm()) {
- 您不需要
LabelFor()
中的第二个参数 - 它可以只是Html.LabelFor(m => m.SoftwareId, new { @class = "control-label col-md-2" })
因为您在[Display]
中指定了它 属性
最后,如果您想进一步简化您的视图,您可以考虑自定义 EditorTemplates
或 html 助手,如 this answer 中所示,这将允许您替换
<div class="form-group">
@Html.LabelFor(model => model.SoftwareId, new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.DropDownListFor(m => m.SoftwareId, Model.SoftwareList, "-- Select --", new { @class = "select2" })
@Html.ValidationMessageFor(model => model.SoftwareId)
</div>
</div>
与(自定义 EditorTemplate
)
@Html.EditorFor(m => m.SoftwareId, "BootstrapSelect", Model.SoftwareList)
或(自定义HtmlHelper
)
@Html.BootstrapDropDownFor(m => m.SoftwareId, Model.SoftwareList)
这是模型Class
[Table("CURRENCY")]
public class CurrencyClass : ICurrency
{
private Int32 mCURRENCY_ID = default(Int32);
[Key]
public virtual Int32 CURRENCY_ID
{
get { return mCURRENCY_ID; }
set { mCURRENCY_ID = value; }
}
private string mCURRENCY_NAME = default(string);
public virtual string CURRENCY_NAME
{
get { return mCURRENCY_NAME;}
set { mCURRENCY_NAME = value;}
}
private string mCURRENCY_DESC = default(string);
public virtual string CURRENCY_DESC
{
get { return mCURRENCY_DESC; }
set { mCURRENCY_DESC = value; }
}
private string mCURRENCY_SYMBOLE = default(string);
public virtual string CURRENCY_SYMBOLE
{
get { return mCURRENCY_SYMBOLE; }
set { mCURRENCY_SYMBOLE = value; }
}
private Int32 mcreated_by = default(Int32);
public virtual Int32 created_by
{
get { return mcreated_by; }
set { mcreated_by = value; }
}
private DateTime mcreated_date = default(DateTime);
public virtual DateTime created_date
{
get { return mcreated_date; }
set { mcreated_date = value; }
}
private Int32 mmodified_by = default(Int32);
public virtual Int32 modified_by
{
get { return mmodified_by; }
set { mmodified_by = value; }
}
private DateTime mmodified_date = default(DateTime);
public virtual DateTime modified_date
{
get { return mmodified_date; }
set { mmodified_date = value; }
}
}
这是视图模型
public class CurrencyViewModel
{
[Key]
public Int32 CURRENCY_Id { get; set; }
[Required(ErrorMessage="Currency Name is required")]
public string CURRENCY_NAME { get; set; }
[Required(ErrorMessage="Currency Description is required")]
public string CURRENCY_DESC { get; set; }
[Required(ErrorMessage = "Currency Symbole is Required")]
public string CURRENCY_SYMBOLE { get; set; }
}
这是行动
[HttpPost]
[ActionName("Create")]
public ActionResult Create(CurrencyViewModel vm)
{
if (!ModelState.IsValid)
{
return View("Create");
}
obj.CURRENCY_NAME = vm.CURRENCY_NAME;
obj.CURRENCY_DESC = vm.CURRENCY_DESC;
obj.CURRENCY_SYMBOLE = vm.CURRENCY_SYMBOLE;
obj.created_by = 1;
obj.created_date = DateTime.Now;
obj.modified_by = 1;
obj.modified_date = DateTime.Now;
db.Currencies.Add(obj);
db.SaveChanges();
return RedirectToAction("Index");
}