![](/img/trans.png)
[英]How can I manually bind data from a ModelStateDictionary to a presentation model with ASP.NET MVC?
[英]How can i attach existing model(device) data to another model(user) data in mvc asp.net
我正在创建一个系统,在该系统中,创建用户时可以将设备分配给该用户。 我正在使用一个下拉列表来执行此操作,并且在下拉列表中填充了设备列表时,它不会使用该设备更新用户。 多个用户可以使用同一设备,并且我想避免进行硬编码,因为该信息已经在数据库中。
我首先通过ef代码执行此操作,其他任何建议都将被考虑在内。 我真的只是专注于使它起作用,所以我愿意提出建议。 我也想让它与Edit一起工作,但是如果我使用类似的代码,我想解决方案将同时解决创建和编辑问题。
我一直在使用viewmodel在索引页面上显示设备。 db上的当前用户显示了他们分配的设备,因此我知道这是可行的,但是我不得不在表数据中手动分配设备。
PatientController.cs(用户也称为患者)
namespace FaceToFaceWebsite.Controllers
{
public class PatientController : Controller
{
private F2FData db = new F2FData();
public ActionResult Index()
{
var viewModel = db.Users
.Select(u => new UserDeviceViewModel()
{
User = u,
Device = u.Device
}).ToList();
return View(viewModel);
}
public ActionResult Create()
{
ViewBag.DeviceID = new SelectList(db.Devices, "DeviceID", "Name");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "UserID,CodeName,UseBriefInstructions,DeviceID,Name")] User user, Device device)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.Devices.Attach(device);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(user);
}
User.cs(在另一个项目中,但在相同的解决方案中)
namespace FaceToFace.Model
{
public class User
{
public int UserID { get; set; }
public string CodeName { get; set; }
public bool UseBriefInstructions { get; set; }
public ICollection<RegimeItem> RegimeItems { get; set; }
public Device Device { get; set; }
public virtual ICollection<Grading> UserGradings { get; set; }
public User()
{
this.RegimeItems = new List<RegimeItem>();
Device = new Device();
}
}
public class RegimeItem
{
public int RegimeItemID { get; set; }
public Exercise RegimeExercise { get; set; }
}
}
Device.cs(在另一个项目中,但在相同的解决方案中)
namespace FaceToFace.Model
{
public class Device
{
public int DeviceID { get; set; }
public string Name { get; set; }
}
}
UserDeviceViewModel.cs
namespace FaceToFaceWebsite.Models
{
public class UserDeviceViewModel
{
public Device Device { get; set; }
public User User { get; set; }
public IList<SelectListItem> Name { get; set; }
}
}
查看/患者/Create.cshtml
@model FaceToFace.Model.User
@{
ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) {
@Html.AntiForgeryToken()
@Html.ValidationSummary(true)
<fieldset>
<legend>User</legend>
<div class="editor-label">
@Html.LabelFor(model => model.CodeName)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.CodeName)
@Html.ValidationMessageFor(model => model.CodeName)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.Device.Name, "Device")
</div>
<div class="editor-field">
@Html.DropDownListFor(model => model.Device.DeviceID, (IEnumerable<SelectListItem>)ViewBag.DeviceID)
</div>
<div class="editor-label">
@Html.LabelFor(model => model.UseBriefInstructions)
</div>
<div class="editor-field">
@Html.EditorFor(model => model.UseBriefInstructions)
@Html.ValidationMessageFor(model => model.UseBriefInstructions)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
我相信问题出在控制器中,我一直在做,经过多次尝试,我无法从数据库中获得创建功能来将用户分配给设备的功能,因此,我们将不胜感激。
更新
PatientController.cs
private void PopulateDeviceChoices(UserDeviceViewModel model)
{
model.DeviceChoices = db.Devices.Select(m => new SelectListItem
{
Text = m.Name,
Value = m.DeviceID
});
}
//
// GET: /Patient/
public ActionResult Index()
{
//var viewModel = new List<FaceToFaceWebsite.Models.UserDeviceViewModel>();
var viewModel = db.Users
.Select(u => new UserDeviceViewModel()
{
User = u,
Device = u.Device
}).ToList();
return View(viewModel);
}
public ActionResult Create(UserDeviceViewModel model, User user)
{
ViewBag.DeviceID = new SelectList(db.Devices, "DeviceID", "Name");
var device = db.Devices.Find(model.DeviceId);
user.Device = device;
PopulateDeviceChoices(model);
return View(model);
}
//
// POST: /Patient/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(User user, Device device, UserDeviceViewModel model)
{
if (ModelState.IsValid)
{
db.Users.Add(user);
db.Devices.Attach(device);
db.SaveChanges();
return RedirectToAction("Index");
}
PopulateDeviceChoices(model);
return View(model);
}
我已经按照克里斯的建议进行了更改,但是我认为我没有正确翻译它们,因为在Value = m.DeviceID
时出现错误,告诉我Cannot implicitly convert type 'int' to 'string'
我已经开始工作了,但是我在视图上得到了两组用户输入行,这也不允许我仍然将设备分配给用户。
更新2(Stephens建议)
PatientController.cs
public ActionResult Create()
{
UserDeviceCreateViewModel model = new UserDeviceCreateViewModel();
ConfigureViewModel(model);
return View(model);
}
public ActionResult Create(UserDeviceCreateViewModel model, User user, Device device)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
从视图模型中删除Device
属性。 您不是在此处添加/编辑设备,而只是将其与用户关联。
然后,您需要将IEnumerable<SelectListItem>
添加到包含可能的设备选项的视图模型:
public IEnumerable<SelectListItem> DeviceChoices { get; set; }
您将在GET和POST操作中初始化此列表,因此您可能应该将初始化逻辑分解为控制器中自己的私有方法:
private void PopulateDeviceChoices(UserDeviceViewModel model)
{
model.DeviceChoices = db.Devices.Select(m => new SelectListItem
{
Text = m.Name,
Value = m.Id
};
}
然后,在操作中,请在返回视图之前调用此方法:
PopulateDeviceChoices(model);
return View(model);
您没有为Device
on User
定义显式外键属性,这有一点点困扰。 你不必 ,但它使事情变得更加简单。 如果要添加显式属性,则可以执行以下操作:
@Html.DropDownListFor(m => m.User.DeviceId, Model.DeviceChoices)
但是,由于您没有此显式属性,因此您必须采取一些额外的步骤。 首先,您需要在视图模型中添加属性以保存发布的ID:
public int DeviceId { get; set; }
然后,在您的视图中,将通过以下方式呈现下拉列表:
@Html.DropDownListFor(m => m.DeviceId, Model.DeviceChoices)
最后,在操作中,您必须使用此ID从数据库中查找设备,然后在用户上进行设置:
var device = db.Devices.Find(model.DeviceId);
user.Device = device;
您收到的错误是因为DeviceID
属性为typeof int
但Value
属性为typeof string
因此需要
model.DeviceChoices = db.Devices.Select(m => new SelectListItem
{
Text = m.Name,
Value = m.DeviceID.ToString()
});
但是,您的代码还有很多其他问题,例如您的Create()
GET方法不仅具有不必要的参数,而且其属性将为null,视图基于User
但是POST方法也具有Device
和UserDeviceViewModel
参数,两者都将为null,并且如果您向任何模型添加验证属性,则ModelState
可能无效。 与往常一样,您应该使用视图模型来表示要显示/编辑的内容
public class UserCreateVM
{
[Display(Name = "Code Name")]
[Required(ErrorMessage = "Please enter a code name")]
public string CodeName { get; set; }
[Display(Name = Use Brief Instructions?")]
public bool UseBriefInstructions { get; set; }
[Display(Name = Device")]
[Required(ErrorMessage = "Please select a device")]
public int? SelectedDevice { get; set; }
public SelectList DeviceList { get; set; }
}
控制者
public ActionResult Create()
{
UserCreateVM model = new UserCreateVM();
ConfigureViewModel(model);
return View(model);
}
[HttpPost]
public ActionResult Create(UserCreateVM model)
{
if (!ModelState.IsValid)
{
ConfigureViewModel(model);
return View(model);
}
// Initialize new instance of the data model
User user = new User();
// Map properties from view model to data model
user.CodeName = model.CodeName;
user.UseBriefInstructions = model.UseBriefInstructions;
user.Device = db.Devices.Find(model.SelectedDevice);
// Save and redirect
db.Users.Add(user);
db.SaveChanges();
return RedirectToAction("Index");
}
private void ConfigureViewModel(UserCreateVM model)
{
model.DeviceList = new SelectList(db.Devices, "DeviceID", "Name");
}
视图
@model UserCreateVM
@using (Html.BeginForm())
{
....
@Html.LabelFor(m => m.CodeName)
@Html.TextBoxFor(m => m.CodeName)
@Html.ValidationMessageFor(m => m.CodeName)
@Html.LabelFor(m => m.SelectedDevice)
@Html.DropDownListFor(m => m.SelectedDevice, Model.DeviceList, "-Please select-")
@Html.ValidationMessageFor(m => m.SelectedDevice)
@Html.LabelFor(m => m.UseBriefInstructions)
@Html.CheckboxFor(m => m.UseBriefInstructions)
@Html.ValidationMessageFor(m => m.UseBriefInstructions)
....
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.