2014-09-10 70 views
1

我得到了一个与我的模型相关的问题,您可以在下面的图片中看到。如何通过asp.net中的视图创建/编辑模型mvc 5

enter image description here

正如你可以看到我有3个实体和1:N和M:N它们之间的关系。

我希望我可以通过Web界面编辑这些模型。因此,我支持(添加控制器与实体框架)这三个模型,并得到edit/delete/create/意见,当然还有一个控制器为每个实体。

但是VS没有为关系自动创建输入/字段。所以我想手动实现它们。在我想这样做之前,有一种更简单的方法来实现/支撑这个模型,所以我甚至可以编辑关系(复选框或(多)选择将是最好的)? 在此先感谢!

+0

+1 - downvote否定 http://blogs.msdn.com/b/mcsuk soldev /存档/ 2013/09/20 /管理实体 - 关系 - 与-MVC-scaffolding.aspx – InferOn 2014-09-10 18:03:16

回答

0

对于一对多您可以使用提示一个DropDownList在合作伙伴视图(请参阅Scott Allen's solution。多对多可以通过的ViewModels和JavaScript框架,如剔除处理。

0

不,支架有意这里unopinionated,因为有很多不同的方法可以处理这个问题,也许你只是想从一个选择列表中选择一个,也许你想要复选框,或者,你想实际添加/编辑相关的内联项目?最后一个,你会喜欢立刻发布所有内容或使用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; } 
} 

在这里,我已经添加了可空INT(使用可空允许它们最初未选定的,而不是仅仅设定为第一个选项)属性来跟踪选定Book的id/Partner,因为它没有出现,你在外键的实体上有明确的属性。这很好,但它不会让它稍微复杂一些,以至于稍后会看到保存关系。如果你确实有明确的外键属性,那么你应该在你的视图模型中镜像它们。

在你行动的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); 
} 

的主要区别是,你显然与现有的实例打交道,所以你需要从数据库中拉出。然后,您只需将实体中的数据映射到您的视图模型。由于您没有明确的外键属性,因此您必须执行一些额外的工作才能获取当前选定的值,否则您可以直接复制外键属性的值。另外,在这里,我只是做一个手动映射,但有第三方库可以使这个任务变得更简单(请参阅:AutoMapper)。

因此,您可以实现您的意见。一切都会像直接使用实体一样工作,你只需要进行一些修改即可。首先,您需要更改您的视图模型声明:

@model Namespace.To.TipViewModel 

然后,添加选择列表中为您的两个相关属性:

@Html.DropDownListFor(m => m.SelectedPartnerId, Model.PartnerChoices) 

... 

@Html.DropDownListFor(m => m.SelectedBookId, Model.BookChoices) 

乐趣发生在你的行动的POST版本。大部分的代码将保持从一开始的版本是相同的,但现在你将有一个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,需要凝聚您的收藏属性到ID列表:

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) 
相关问题