【发布时间】:2015-03-15 17:58:50
【问题描述】:
我正在开发一个用于工作的 webapp,并且我正在使用标准的 CRUD 样式交互。但是,我不希望用户更新某些字段,因此我将它们从视图中删除。但是,如果我没有明确设置这些字段,那么当模型在数据库中更新时它们会被清除。
我关心为我的 ViewModel 填充字段的正确方法是什么。
我想出的粗略想法是这样的:
我的视图模型:
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>
【问题讨论】:
-
使用视图模型是正确的方法,但是在您的POST方法中,您需要从数据库中获取原始
SoftwareTracking对象并将您的视图模型属性映射到它,然后保存原始对象。旁注:您不需要(也不应该)需要在 POST 方法中调用GeneratePageData(softwaretracking.Software.Id);(尝试基于原始模型重置视图模型属性无论如何都会被忽略) -
我更新了我上面的代码,所以它确实可以工作,但是,我不知道还能做些什么来让它更干净、更高效。我有 GeneratePageData 的原因是因为我用视图中显示的某些列表填充 ViewBag。这些是从 get 方法中携带的吗?
-
不,您需要在返回视图之前重新填充任何选择列表 - 如果这就是它所做的一切,那么它就可以了。由于您有一个视图模型,您应该在视图模型中包含
SelectList属性,而不是在ViewBag中,并且您的视图模型包含一个似乎不必要的LastModified属性(只需在数据模型中设置值发回并保存时的控制器 - 我假设它不是用户应该能够编辑的东西)。您还可以查看automapper 之类的工具,使其更轻松、更简洁 -
我实际上正在执行一些非常复杂的 linq 语句来创建选择列表。我认为将业务逻辑排除在模型之外是最佳做法吗?
-
我同意。我只是建议您的视图模型包含
SelectLists的属性,并且您仍然有一个通用的私有方法来分配您在 GET 和(假设您返回视图)POST 方法中调用的那些属性。我使用类似private void ConfigureEditModel(MyViewModel model) { model.MyFirstSelectList = someLinqQuery; }的东西。
标签: c# asp.net-mvc entity-framework asp.net-mvc-5 viewmodel