我有一个关于我的模型的问题,你可以在下面的图片中看到。

如你所见,我有3个实体和它们之间的1:n和m:n关系。
我希望我可以通过web界面编辑这些模型。因此,我搭建了这三个模型(使用实体框架添加控制器),并获得了edit/delete/create/视图,当然,每个实体也有一个控制器。
但是,VS不会自动为关系创建输入/字段。所以我想手动实现它们。在我想要这样做之前,有没有一种更简单的方法来实现/搭建这个模型,这样我甚至可以编辑关系(复选框或(多)选择将是最好的)?提前感谢!
发布于 2014-09-11 02:11:38
对于一对多,您可以在合作伙伴视图中使用小费的DropDownList (请参阅Scott Allen's solution。很多-很多都可以由ViewModels和JavaScript框架来处理。
发布于 2014-09-11 03:59:22
不,脚手架在这里是故意不加意见的,因为有许多不同的方法可以处理这个问题。也许您只是想从选择列表中进行选择?也许你想要复选框呢?或者,也许你想实际添加/编辑相关的项目内联?最后一个问题,你是想一次性发布还是使用AJAX?
因此,框架没有为您选择,而是将决定权留给了您,因为只有您知道应该如何构建应用程序。无论如何,依赖于脚手架往往会咬你一口。它们只在最基本和最理想的情况下工作,什么时候应用程序需求是基本的或理想的?在这一点上,我甚至不关心它们,我更喜欢手动创建我的控制器/视图。它最终比处理脚手架和撤销所有不适用的事情更快。
因此,由于您正在寻找选择框(单选或多选),首先,我建议为您的实体创建视图模型。例如,使用Tip
public class TipViewModel
{
[Required]
public string Name { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Required]
public int? SelectedPartnerId { get; set; }
public IEnumerable<SelectListItem> PartnerChoices { get; set;}
[Required]
public int? SelectedBookId { get; set; }
public IEnumerable<SelectListItem> BookChoices { get; set; }
}在这里,我添加了nullable int (使用nullable允许它们最初被取消选择,而不只是设置为第一个选项)属性来跟踪所选Book/Partner的id,因为看起来您的实体上没有外键的显式属性。这很好,但这并不会使保存关系变得更加复杂,稍后您将看到这一点。如果您确实有显式的外键属性,那么您应该在视图模型中镜像这些属性。
现在,在GET版本的操作中,您需要执行类似以下操作:
public ActionResult Create()
{
var model = new TipViewModel();
PopulateChoices(model);
return View(model);
}
...
protected void PopulateChoices(TipViewModel model)
{
model.PartnerChoices = db.Partners.Select(m => new SelectListItem
{
Value = m.Id.ToString(),
Text = m.Name
});
model.BookChoices = db.Books.Select(m => new SelectListItem
{
Value = m.Id.ToString(),
Text = string.Format("{0} by {1}", m.Name, m.Author)
});
}我抽象出了填充这些选择列表的代码,因为这些代码将在整个控制器中被多次使用。另外,我对图书的Text值使用了string.Format,只是为了说明您可以对选择列表项的文本执行任何操作。此外,很明显,上面的代码将用于创建操作。进行编辑与此类似,但略有不同:
public ActionResult Edit(int id)
{
var tip = db.Tips.Find(id);
if (tip == null)
{
return new HttpNotFoundResult();
}
var model = new TipViewModel
{
Name = tip.Name,
Description = tip.Description,
SelectedPartnerId = tip.Partner != null ? tip.Partner.Id : new int?(),
SelectedBookId = tip.Book != null ? tip.Book.Id : new int?()
}
PopulateChoices(model);
return View(model);
}主要区别在于,您显然是在处理一个现有的实例,因此您需要从数据库中提取它。然后,您只需要将数据从实体映射到视图模型。同样,由于您没有显式的外键属性,您必须做一些额外的工作来获得当前选择的Partner/Book值,否则您可以直接复制外键属性的值。另外,在这里,我只是做一个手动映射,但是有第三方库可以让这项任务变得更容易(参见:AutoMapper)。
这样,你就可以实现你的视图了。一切都会像你直接使用实体时一样工作,你只需要做一些修改。首先,您需要更改视图的模型声明:
@model Namespace.To.TipViewModel然后,添加两个相关属性的选择列表:
@Html.DropDownListFor(m => m.SelectedPartnerId, Model.PartnerChoices)
...
@Html.DropDownListFor(m => m.SelectedBookId, Model.BookChoices)乐趣发生在你的动作的POST版本中。GET版本的大部分代码将保持不变,但现在您将拥有一个if (ModelState.IsValid)块:
[HttpPost]
public ActionResult Create(TipViewModel model)
{
if (ModelState.IsValid)
{
// map the data from model to your entity
var tip = new Tip
{
Name = model.Name,
Description = model.Description,
Partner = db.Partners.Find(model.SelectedPartnerId),
Book = db.Books.Find(model.SelectedBookId)
}
db.Tips.Add(tip);
db.SaveChanges();
return RedirectToAction("Index");
}
// Form has errors, repopulate choices and redisplay form
PopulateChoices(model);
return View(model);
}同样,编辑版本与此类似,只是您将映射到现有实例上,例如:
tip.Name = model.Name;
tip.Description = model.Description;
tip.Partner = db.Partners.Find(model.SelectedPartnerId);
tip.Book = db.Books.Find(model.SelectedBookId);这就是引用属性的全部内容。在你的问题中,你的实体上实际上没有任何M2M的东西,甚至没有一对多的东西。一切都是一对一的,但是如果你有一个集合属性,你需要稍微改变一下处理方式。您仍然需要视图模型上的一个属性来保存所选值和可用选项:
public List<int> SelectedFooIds { get; set; }
public IEnumerable<SelectListItem> FooChoices { get; set; }填充选项也是相同的。选项就是选项;如果您只选择一个或多个选项,这并不重要。
不过,在创建操作中映射到实体将有所不同,因为您需要从数据库中选择所有选定的项,并将实体的集合属性设置为该属性:
var tip = new Tip
{
...
Foos = db.Foos.Where(m => model.SelectedFooIds.Contains(m.Id)),
}而且,您还需要对GET和POST版本的编辑操作进行更改。对于GET,您需要将集合属性压缩为ids列表:
var model = new TipViewModel
{
...
SelectedFooIds = tip.Foos.Select(m => m.Id).ToList(),
}在编辑版本中,您可以设置新的选定项目:
tip.Foos = db.Foos.Where(m => model.SelectedFooIds.Contains(m.Id);最后,在您的视图中,您将使用ListBoxFor而不是DropDownListFor来启用多重选择:
@Html.ListBoxFor(m => m.SelectedFooIds, Model.FooChoices)https://stackoverflow.com/questions/25772023
复制相似问题