49

在阅读了 100 篇关于如何在 MVC 3 中使用 Razor 视图创建下拉列表的文章后,我找不到适合我的情况的文章。

情况: 我最终试图创建一个视图以将员工添加到数据库。

这是我正在使用的 .EDMX 模型的图像(create() 将使用的表。):

在此处输入图像描述

目标:

  1. 创建员工(我使用 StaffNotify 复选框的部分视图制作了 Create.cshtml(强类型)){我在创建视图的通知部分视图中使用单独的 @model 不确定这是否安全???@model ShadowVenue.Models.Employee & @model ShadowVenue.Models.StaffNotify)

  2. 为 StaffTypeId 创建一个下拉框(将插入表“StaffType”(具有一对多关系)中的 [StaffTypeId] 值,但将在下拉列表中显示 [Type] 字符串值)

  3. 为 GenderId 创建一个下拉框(将插入表“Genders”(具有一对多关系)中的 [GenderId] 值,但将在下拉列表中显示 [Gender] 字符串值)

  4. 将记录插入数据库(我将员工通知放在单独的表中,在 StaffId 主键上具有 1 对 1 的关系)

我似乎遇到了控制器代码的问题。

我不确定是否应该在 EDMX 模型中创建存储过程,或者提出一些查询或方法语法,不确定哪种方法是最好的。

这是我的第一个使用实体框架模型的大型 MVC3 应用程序。

(如果您需要知道任何导航属性名称以帮助解决问题,请告诉我,我会提供给您)

4

2 回答 2

76

不要将 db 模型直接传递给您的视图。您很幸运能够使用 MVC,因此请使用视图模型进行封装。

像这样创建一个视图模型类:

public class EmployeeAddViewModel
{
    public Employee employee { get; set; }
    public Dictionary<int, string> staffTypes { get; set; }
    // really? a 1-to-many for genders
    public Dictionary<int, string> genderTypes { get; set; }

    public EmployeeAddViewModel() { }
    public EmployeeAddViewModel(int id)
    {
        employee = someEntityContext.Employees
            .Where(e => e.ID == id).SingleOrDefault();

        // instantiate your dictionaries

        foreach(var staffType in someEntityContext.StaffTypes)
        {
            staffTypes.Add(staffType.ID, staffType.Type);
        }

        // repeat similar loop for gender types
    }
}

控制器:

[HttpGet]
public ActionResult Add()
{
    return View(new EmployeeAddViewModel());
}

[HttpPost]
public ActionResult Add(EmployeeAddViewModel vm)
{
    if(ModelState.IsValid)
    {
        Employee.Add(vm.Employee);
        return View("Index"); // or wherever you go after successful add
    }

    return View(vm);
}

然后,最后在您的视图中(您可以先使用 Visual Studio 构建它),将继承的类型更改为 ShadowVenue.Models.EmployeeAddViewModel。此外,在下拉列表所在的位置,使用:

@Html.DropDownListFor(model => model.employee.staffTypeID,
    new SelectList(model.staffTypes, "ID", "Type"))

同样对于性别下拉列表

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(model.genderTypes, "ID", "Gender"))

根据评论更新

对于性别,如果您在上述建议的视图模型中没有genderTypes,您也​​可以这样做(不过,再想一想,也许我会在视图模型中将此服务器端生成为IEnumerable)。因此,代替new SelectList...下面,您将使用您的 IEnumerable。

@Html.DropDownListFor(model => model.employee.genderID,
    new SelectList(new SelectList()
    {
        new { ID = 1, Gender = "Male" },
        new { ID = 2, Gender = "Female" }
    }, "ID", "Gender"))

最后,另一个选项是查找表。基本上,您保留与查找类型相关联的键值对。一种类型的一个例子可能是性别,而另一个可能是状态,等等。我喜欢这样构造我的:

ID | LookupType | LookupKey | LookupValue | LookupDescription | Active
1  | Gender     | 1         | Male        | male gender       | 1
2  | State      | 50        | Hawaii      | 50th state        | 1
3  | Gender     | 2         | Female      | female gender     | 1
4  | State      | 49        | Alaska      | 49th state        | 1
5  | OrderType  | 1         | Web         | online order      | 1

我喜欢在一组数据不经常变化,但仍需要不时枚举时使用这些表。

希望这可以帮助!

于 2011-03-16T17:39:33.130 回答
23

好吧,实际上我不得不说大卫的解决方案是正确的,但有一些话题让我感到不安:

  1. 您永远不应该将模型发送到视图=> 这是正确的
  2. 如果您创建一个ViewModel,并将模型作为成员包含在 中ViewModel,那么您有效地将模型发送到视图=> 这很糟糕
  3. 使用字典将选项发送到视图=> 这种不好的风格

那么如何创建更好的耦合呢?

我会使用像 ValueInjecter 这样的工具AutoMapperModelViewModel和 Model 之间进行映射。AutoMapper似乎确实有更好的语法和感觉,但是当前版本缺少一个非常严重的主题:它无法执行从ViewModel模型到模型的映射(在某些情况下,例如展平等,但这不是主题)所以目前我更喜欢使用ValueInjecter.

ViewModel因此,您使用视图中所需的字段创建一个。您将需要的 SelectList 项目添加为查找。您已经将它们添加为 SelectLists。因此,您可以从启用 LINQ 的源中查询,选择 ID 和文本字段并将其存储为选择列表:您无需创建新类型(字典)作为查找,只需将new SelectList视图从视图移动到控制器。

  // StaffTypes is an IEnumerable<StaffType> from dbContext
  // viewModel is the viewModel initialized to copy content of Model Employee  
  // viewModel.StaffTypes is of type SelectList

  viewModel.StaffTypes =
    new SelectList(
        StaffTypes.OrderBy( item => item.Name )
        "StaffTypeID",
        "Type",
        viewModel.StaffTypeID
    );

在视图中你只需要调用

@Html.DropDownListFor( model => mode.StaffTypeID, model.StaffTypes )

回到控制器中方法的 post 元素,您必须采用ViewModel. 然后检查验证。如果验证失败,您必须记住重新填充viewModel.StaffTypesSelectList,因为该项目在进入 post 函数时将为空。所以我倾向于将那些人口的东西分成一个函数。return new View(viewModel)如果有任何问题,您只需回电即可。MVC3 发现的验证错误将自动显示在视图中。

如果您有自己的验证代码,则可以通过指定它们属于哪个字段来添加验证错误。检查文档ModelState以获取有关信息。

如果viewModel有效,您必须执行下一步:

如果它是新项目的创建,您必须从viewModel(最适合的是ValueInjecter)填充模型。然后,您可以将其添加到该类型的 EF 集合并提交更改。

如果您有更新,则首先将当前数据库项放入模型中。然后,您可以将值从viewModel背面复制到模型(再次使用ValueInjecter让您非常快速地做到这一点)。之后你就可以SaveChanges完成了。

随意询问是否有任何不清楚的地方。

于 2011-03-16T18:29:49.127 回答