使用实体框架(.edmx 模型)和创建 MVC3 的下拉列表剃刀视图 &&将数据库记录插入多个表

发布于 2024-10-22 00:17:03 字数 919 浏览 3 评论 0原文

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

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

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

在此处输入图像描述

目标:

  1. 创建一名员工(我使用 StaffNotify 复选框的部分视图制作了 Create.cshtml(强类型)){我在 Notify 部分视图中使用了一个单独的 @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 应用程序。

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

After reading 100's of articles on here about how to create a DropDown List in MVC 3 with Razor Views, I could not find one that fit my case.

Situation:
I am ultimately trying to create a View to Add an Employee to a Database.

Here is an image of the .EDMX Model that I am using (the tables that will be used by the create().):

enter image description here

Objectives:

  1. Create an Employee (I have the Create.cshtml (strongly typed) made with a Partial View for the StaffNotify Checkboxes) {I am using a separate @model in the Notify Partial View from the Create View not sure if that is safe??? @model ShadowVenue.Models.Employee & @model ShadowVenue.Models.StaffNotify)

  2. Create a Dropdown box for StaffTypeId (that will insert the [StaffTypeId] value from the Table "StaffType" (which has a 1 to many relationship), but will show the [Type] string value in the dropdown)

  3. Create a Dropdown box for GenderId (that will insert the [GenderId] value from the Table "Genders" (which has a 1 to many relationship), but will show the [Gender] string value in the dropdown)

  4. Insert the Record into the database (I have the Staff Notifications in a separate table with a 1 to 1 relationship on the StaffId Primary Key)

I seem to be having the trouble with the Controller code for this.

I am not sure if I should create Stored Procedure within the EDMX model, or come up with some query or method syntax, not sure which is the best way.

This my First Large MVC3 App using Entity Framework Model.

(if you need to know any of the Navigation Property Names in order to help with the solution just let me know, I will provide them to you)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

路还长,别太狂 2024-10-29 00:17:03

不要将数据库模型直接传递到您的视图。您很幸运能够使用 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
    }
}

Controller:

[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"))

按评论更新

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

@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

当一组数据不经常更改但仍然需要枚举时,我喜欢使用这些表时不时地。

希望这有帮助!

Don't pass db models directly to your views. You're lucky enough to be using MVC, so encapsulate using view models.

Create a view model class like this:

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
    }
}

Controller:

[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);
}

Then, finally in your view (which you can use Visual Studio to scaffold it first), change the inherited type to ShadowVenue.Models.EmployeeAddViewModel. Also, where the drop down lists go, use:

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

and similarly for the gender dropdown

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

Update per comments

For gender, you could also do this if you can be without the genderTypes in the above suggested view model (though, on second thought, maybe I'd generate this server side in the view model as IEnumerable). So, in place of new SelectList... below, you would use your IEnumerable.

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

Finally, another option is a Lookup table. Basically, you keep key-value pairs associated with a Lookup type. One example of a type may be gender, while another may be State, etc. I like to structure mine like this:

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

I like to use these tables when a set of data doesn't change very often, but still needs to be enumerated from time to time.

Hope this helps!

小清晰的声音 2024-10-29 00:17:03

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

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

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

我会使用 AutoMapper 或 ValueInjecter 之类的工具在 ViewModel< 之间进行映射/代码> 和型号。
AutoMapper 似乎确实有更好的语法和感觉,但当前版本缺乏
非常严重的主题:它无法执行从 ViewModel 到 Model 的映射(在某些情况下,例如扁平化等,但这不是主题)
所以目前我更喜欢使用ValueInjecter

因此,您使用视图中所需的字段创建一个 ViewModel
您添加所需的 SelectList 项目作为查找。
并且您已经将它们添加为 SelectList。因此,您可以从启用 LINQ 的源进行查询,选择 ID 和文本字段并将其存储为选择列表:
您发现不必创建新类型(字典)作为查找,只需将新 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 元素中回调 Back,您必须采用 ViewModel 类型的参数。然后您检查验证。
如果验证失败,您必须记住重新填充 viewModel.StaffTypes SelectList,因为进入 post 函数时此项将为空。
所以我倾向于将这些人口事物分成一个函数。
如果出现任何问题,您只需回调return new View(viewModel)即可。
MVC3 发现的验证错误将自动显示在视图中。

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

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

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

如果您有更新,您首先将当前的数据库项放入模型中。然后,您可以将值从 viewModel 复制回模型(再次使用 ValueInjecter 可以非常快速地完成此操作)。
之后,您可以SaveChanges并完成。

如果有任何不清楚的地方,请随时询问。

Well, actually I'll have to say David is right with his solution, but there are some topics disturbing me:

  1. You should never send your model to the view => This is correct
  2. If you create a ViewModel, and include the Model as member in the ViewModel, then you effectively sent your model to the View => this is BAD
  3. Using dictionaries to send the options to the view => this not good style

So how can you create a better coupling?

I would use a tool like AutoMapper or ValueInjecter to map between ViewModel and Model.
AutoMapper does seem to have the better syntax and feel to it, but the current version lacks a
very severe topic: It is not able to perform the mapping from ViewModel to Model (under certain circumstances like flattening, etc., but this is off topic)
So at present I prefer to use ValueInjecter.

So you create a ViewModel with the fields you need in the view.
You add the SelectList items you need as lookups.
And you add them as SelectLists already. So you can query from a LINQ enabled sourc, select the ID and text field and store it as a selectlist:
You gain that you do not have to create a new type (dictionary) as lookup and you just move the new SelectList from the view to the controller.

  // 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
    );

In the view you just have to call

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

Back in the post element of your method in the controller you have to take a parameter of the type of your ViewModel. You then check for validation.
If the validation fails, you have to remember to re-populate the viewModel.StaffTypes SelectList, because this item will be null on entering the post function.
So I tend to have those population things separated into a function.
You just call back return new View(viewModel) if anything is wrong.
Validation errors found by MVC3 will automatically be shown in the view.

If you have your own validation code you can add validation errors by specifying which field they belong to. Check documentation on ModelState to get info on that.

If the viewModel is valid you have to perform the next step:

If it is a create of a new item, you have to populate a model from the viewModel (best suited is ValueInjecter). Then you can add it to the EF collection of that type and commit changes.

If you have an update, you get the current db item first into a model. Then you can copy the values from the viewModel back to the model (again using ValueInjecter gets you do that very quick).
After that you can SaveChanges and are done.

Feel free to ask if anything is unclear.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文