ASP.NET Core 5 MVC 使用带枚举的视图模型

ASP.NET Core 5 MVC Using View Models with enumeration

我有2个模型; TypeOneProject_Screen。我需要一个视图,使 2 tables 具有来自这两个 tables 的信息。我尝试使用本指南来制作一个视图模型,它有所帮助,但与我做的事情并不完全相同:https://dotnettutorials.net/lesson/view-model-asp-net-core-mvc/

这是我制作的视图模型:

 public class MyProjectsViewModel
    {
        public Project_Screen Project_Screen { get; set; }
        public TypeOne TypeOne { get; set; }
    }

这是控制器:

 public class ProfileController : Controller
    {
        private readonly Natural_ResourcesContext _context;

        public ProfileController(Natural_ResourcesContext context)
        {
            _context = context;
        }
        // GET: Profile
        public ActionResult Index()
        {
            Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
                                                            where s.DSN_PM == User.Identity.Name
                                                            select s);
            TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
                                        where x.Name == User.Identity.Name
                                        select x);
            MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
            {
                Project_Screen = project_Screen,
                TypeOne = typeOne
            };

            return View(myProjectsViewModel);
        }
    }

可以看到,project_ScreentypeOne都是Manager = Name.

的记录

然后在视图中我想显示如下内容:

@model EnvApp.ViewModels.MyProjectsViewModel

@{
    ViewData["Title"] = "Projects";
}

<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th>
                Coordinates
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.State_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Federal_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Project_Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.County)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Coordinates)
                </td>
                <td>
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> 
                </td>
            </tr>
        }
    </tbody>
</table>

<br />
<hr />

<h4>Type One Projects</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th>
                Coordinates
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model)
        {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.State_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Federal_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Project_Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.County)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Coordinates)
            </td>
            <td>
                <a asp-action="Details" asp-route-id="@item.ID">Details</a>
            </td>
        </tr>
        }
    </tbody>
</table>

我在 ````Model``` 上收到编译器错误 CS1579:

foreach statement cannot operate on variables of type 'MyProjectsViewModel' because 'MyProjectsViewModel' does not contain a public instance or extension definition for 'GetEnumorator'

我认为这是有道理的,因为我没有将 Project_ScreenTypeOne 表示为一个包含多条记录的对象,但我不太确定该怎么做。

我是在正确的轨道上还是我误解了这一点?我错过了什么?

编辑 1:

我完全按照 Md Farid Uddin Kiron 所说的进行操作,因此他的回答中的代码反映了我的视图模型和视图。但是我的控制器仍然有问题。

  using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using EnvApp.ViewModels;
using EnvApp.Models.DB;

namespace EnvApp.Controllers
{
    public class ProfileController : Controller
    {
        private readonly Natural_ResourcesContext _context;

        public ProfileController(Natural_ResourcesContext context)
        {
            _context = context;
        }
        // GET: Profile
        public ActionResult Index()
        {
            Project_Screen project_Screen = (Project_Screen)(from s in _context.Project_Screen
                                                            where s.DSN_PM == User.Identity.Name
                                                            select s);
            TypeOne typeOne = (TypeOne)(from x in _context.TypeOne
                                        where x.Name == User.Identity.Name
                                        select x);
            MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
            {
                Project_Screen = project_Screen,
                TypeOne = typeOne
            };

            return View(myProjectsViewModel);
        }
    }
}

问题是 project_ScreentypeOne 不是列表或 IEnumerable 类型,这是有道理的,但我不是使它们可枚举的语法。

如果您需要查看,这是我的视图模型:

public class MyProjectsViewModel
    {
        public List<Project_Screen> Project_Screen { get; set; }
        public List<TypeOne> TypeOne { get; set; }
    }

这是视图:

<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th>
                Coordinates
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Project_Screen)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.State_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Federal_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Project_Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.County)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Coordinates)
                </td>
                <td>
                    <a asp-action="Details" asp-route-id="@item.ID">Details</a> 
                </td>
            </tr>
        }
    </tbody>
</table>

<br />
<hr />

<h4>Type One Projects</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th>
                Coordinates
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.TypeOne)
        {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.State_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Federal_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.County)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Coordinates)
            </td>
            <td>
                <a asp-action="Details" asp-route-id="@item.ID">Details</a>
            </td>
        </tr>
        }
    </tbody>
</table>

同样,问题是 project_ScreentypeOne 不是控制器中的列表或 IEnumerable 类型。它们实际上是列表,除了控制器之外无处不在,但它们必须是。错误在行

MyProjectsViewModel myProjectsViewModel = new MyProjectsViewModel()
            {
                Project_Screen = project_Screen,
                TypeOne = typeOne
            };

project_ScreentypeOne 上读取

cannot implicitly convert type Envapp.Models.DB.Project_Screen to System.Collection.Generic.List<Envapp.Models.DB.Project_Screen>

这似乎正在发生,因为那里的代码试图指向 Project_Screen 的数据库模型 table,而不是 Project_Screen 模型中项目的 ViewModel 表示。我该如何解决这个问题?

编辑 2:

我不确定它是什么,但我的代码中的某些内容似乎真的让人们感到困惑。我发布了我所有的模型以供澄清:

Project_Screen.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;

#nullable disable

namespace EnvApp.Models.DB
{
    public partial class Project_Screen
    {
        [Key]
        public long ID { get; set; }
        public string State_Project_Number { get; set; }
        public string? Federal_Project_Number { get; set; }
        public string Project_Name { get; set; }
        public string County { get; set; }
        public DateTime? Memo_Date { get; set; }
        public string From { get; set; }
        public string? Authorization { get; set; }
        public string DSN_PM { get; set; }
        public string? History { get; set; }
        public string History_PM { get; set; }
        public bool Review_Exempt_H { get; set; }
        public bool SHPO_Approval_H { get; set; }
        public string? Archaeology { get; set; }
        public string Archaeology_PM { get; set; }
        public bool Review_Exempt_A { get; set; }
        public bool SHPO_Approval_A { get; set; }
        public bool ESA_Key { get; set; }
        public bool Crayfish { get; set; }
        public bool Crayfish_Habitat_Assessment { get; set; }
        public bool NLEB_4D { get; set; }
        public bool USFWS { get; set; }
        public string USFWS_Type { get; set; }
        public bool Mussel_Habitat { get; set; }
        public bool Mussel_Stream { get; set; }
        public string Within_Airport { get; set; }
        public string? ToPo_Quad_Name { get; set; }
        public bool Bat_Habitat { get; set; }
        public string? Bars { get; set; }
        public string Coordinates { get; set; }
        public string? Natural_Resources_Notes { get; set; }
        public string Adduser { get; set; }
        public DateTime? Date_Added { get; set; }
        public string Crayfish_Notes { get; set; }
        public string Mussel_Notes { get; set; }

    }
}

TypeOne.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

#nullable disable

namespace EnvApp.Models.DB
{
    [Table("Type_One")]
    public partial class TypeOne
    {
        [Key]
        public long ID { get; set; }
        [MaxLength(50)]
        public string State_Project_Number { get; set; }
        [MaxLength(50)]
        public string Federal_Project_Number { get; set; }
        [MaxLength(50)]
        public string Name { get; set; }
        [MaxLength(50)]
        public string Route_Number { get; set; }
        public string County { get; set; }
        [MaxLength(50)]
        public string Work_Type { get; set; }
        [MaxLength(100)]
        public string Coordinates { get; set; }
        public string Project_Description { get; set; }
        public bool? Federal_Aid { get; set; }
        public bool? Minimal_Project_Verification { get; set; }
        [MaxLength(3)]
        public string CE_Category { get; set; }
        [MaxLength(10)]
        public string Amms { get; set; }
        public bool Activities_Agreement { get; set; }
        public string Arch_RE { get; set; }
        public string Hist_RE { get; set; }
        public DateTime? Arch_RE_Date { get; set; }
        public DateTime? Hist_RE_Date { get; set; }
        public bool? Through_Lanes { get; set; }
        public bool? Close_Road { get; set; }
        public bool? ROW_Acquisition { get; set; }
        public bool? Access_Control { get; set; }
        public bool? Fifty_Year_Structure { get; set; }
        public bool? Agency_Coordination { get; set; }
        public bool? IPAC_Screening_Zone { get; set; }
        public bool? Section_404_Permit { get; set; }
        public bool? Ground_Disturbance { get; set; }
        public bool? Waterway { get; set; }
        public bool? Special_Use_Permit { get; set; }
        public bool? Floodplain { get; set; }
        public string Prepared_By { get; set; }
        public string Approved_By { get; set; }
        public string Adduser { get; set; }
        public DateTime? Date_Added { get; set; }
    }
}

Natural_ResourcesContext

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

#nullable disable

namespace EnvApp.Models.DB
{
    public partial class Natural_ResourcesContext : DbContext
    {
        public Natural_ResourcesContext()
        {
        }

        public Natural_ResourcesContext(DbContextOptions<Natural_ResourcesContext> options)
            : base(options)
        {
        }

        public virtual DbSet<NR_User> NR_Users { get; set; }
        public virtual DbSet<Project_Screen> Project_Screen { get; set; }
        public virtual DbSet<TypeOne> TypeOne { get; set; }
        partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
    } 
}

该错误是因为您在视图模型本身而不是您要枚举的属性上使用 foreach。

对于Project_Screen和TypeOne,将它们声明为可枚举类型(例如Array、List、IEnumerable等)。

public class MyProjectsViewModel
{
    public IEnumerable<Project_Screen> Project_Screen { get; set; }
    public IEnumerable<TypeOne> TypeOne { get; set; }
}

您将需要使用来自控制器的一组值来填充它们

var viewModel = new MyProjectsViewModel();

viewModel.Project_Screen = _context.Project_Screen.Where(x => SOME_CONDITION);
viewModel.TypeOne = _context.TypeOne.Where(x => SOME_CONDITION);

在视图中,您将枚举这些属性(而不是模型本身)。

@foreach (var item in Model.Project_Screen)

@foreach (var item in Model.TypeOne)

你已经足够接近了。从我们了解到的视图迭代中,您的 Project_ScreenType_One 似乎应该是 class 的列表。如果是这样,那么你的 MyProjectsViewModel 应该是这样的:

View Model:

public class MyProjectsViewModel
    {
        public List<Project_Screen> ProjectScreen { get; set; }
        public List<Type_One>   TypeOne { get; set; }
    }

Controller:

 public ActionResult ViewModelEnumeration()
    {
        var proScreen = new List<Project_Screen>()
        {
            new Project_Screen(){ State_Project_Number = 1,Federal_Project_Number =1,Project_Name = "Project-1",  County = "USA"},
            new Project_Screen(){ State_Project_Number = 2,Federal_Project_Number =2,Project_Name = "Project-2",  County = "CA"},
            new Project_Screen(){ State_Project_Number = 3,Federal_Project_Number =3,Project_Name = "Project-3",  County = "UK"},
        };
        var typeOne = new List<Type_One>()
        {
            new Type_One(){ State_Project_Number = 101,Federal_Project_Number =101,Project_Name = "Type-One-Project-1",  County = "USA"},
            new Type_One(){ State_Project_Number = 102,Federal_Project_Number =102,Project_Name = "Type-One-Project-2",  County = "CA"},
            new Type_One(){ State_Project_Number = 103,Federal_Project_Number =103,Project_Name = "Type-One-Project-3",  County = "UK"},
        };
        //Bind to View Model
        MyProjectsViewModel viewModel = new MyProjectsViewModel();
        viewModel.ProjectScreen = proScreen;
        viewModel.TypeOne = typeOne;


        return View(viewModel);
    }

Note: I am binding demo seeder property into the list. Feel free to change as per your requirement.Just getting you into the point.

View:

@model MVCApps.Models.MyProjectsViewModel
@{
    ViewData["Title"] = "ViewModelEnumeration";
}

<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.ProjectScreen)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.State_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Federal_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Project_Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.County)
                </td>
            </tr>
        }
    </tbody>
</table>

<br />
<hr />

<h4>Type One Projects</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
         
            <th></th>
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.TypeOne)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.State_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Federal_Project_Number)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.Project_Name)
                </td>
                <td>
                    @Html.DisplayFor(modelItem => item.County)
                </td>
            </tr>
        }
    </tbody>
</table>

Output:

Note: So according to your scenario you can use like this @foreach (var item in Model.Project_Screen). Additionally, be conscious about your naming convention like Project_Screen Project_Screen is confusing either practice like Project_Screen ProjectScreen or ProjectScreen Project_Screen.

希望以上步骤能相应地指导您。您可以在我们的 official document here

上进一步增强您的想法

更新:

As per your comment I am also adding the example in case of single object means when you have other than List or IEnumerable

View Model:

 public class ProjectsScreenTypeOneViewModel
    {
        public Project_Screen ProjectScreen { get; set; }
        public Type_One TypeOne { get; set; }
    }

Controller:

public ActionResult ViewModelFromSingleObject()
        {
            //Binding Project_Screen Object
            var _proScreen = new Project_Screen();
            _proScreen.Project_Name = "Test Project-202";
            _proScreen.State_Project_Number = 1111;
            _proScreen.Federal_Project_Number = 11112021;
            _proScreen.County = "USA";

            //Binding Type_One Object
            var _typeOne = new Type_One();
            _typeOne.Project_Name = "Test Type One Project-101";
            _typeOne.State_Project_Number = 1010;
            _typeOne.Federal_Project_Number = 202121;
            _typeOne.County = "UK";
            //Binding to view model
            var _viewModel = new ProjectsScreenTypeOneViewModel();
            _viewModel.ProjectScreen = _proScreen;
            _viewModel.TypeOne = _typeOne;
            return View(_viewModel);
        }

View:

@model MVCApps.Models.ProjectsScreenTypeOneViewModel

@{
    ViewData["Title"] = "ViewModelFromSingleObject";
}

<h2>ViewModelFromSingleObject</h2>

<h1>My Projects</h1>
<hr />
<h4>Screening Forms</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                @Html.DisplayFor(modelItem => Model.ProjectScreen.State_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.ProjectScreen.Federal_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.ProjectScreen.Project_Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.ProjectScreen.County)
            </td>
        </tr>
    </tbody>
</table>

<br />
<hr />

<h4>Type One Projects</h4>
<table class="table">
    <thead>
        <tr>
            <th>
                State Project Number
            </th>
            <th>
                Federal Project Number
            </th>
            <th>
                Project Name
            </th>
            <th>
                County
            </th>

            <th></th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>
                @Html.DisplayFor(modelItem => Model.TypeOne.State_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.TypeOne.Federal_Project_Number)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.TypeOne.Project_Name)
            </td>
            <td>
                @Html.DisplayFor(modelItem => Model.TypeOne.County)
            </td>
        </tr>
    </tbody>
</table>

Output:

Note: Now as you can see I have added both single and List kind of example which will guided you accordingly. If you still encounter any further issue feel free to share.