带有 SelectList 的 ViewModel 和带有单个记录的 LINQ 查询结果

ViewModel with a SelectList and a LINQ Query result with a single reocrd

我们如何使用以下两个属性填充 ViewModel:

  1. 来自 LINQ 查询的 query result type returns 只有一条记录
  2. 一个SelectList类型

换句话说,假设我们有一个视图,它根据所选 ID 仅显示一部电影。而我们想从年份下拉列表中为该电影指定发行年份,我该如何填写以下 ViewModel 和 Controller 中的 ????

注意:在下面的 ViewModel 中,如果我使用 IQueryable<Movie> 类型的 myMovie 属性 并将 ViewModel 的 属性 分配给查询来自以下控制器的 qrySingleMovie 我收到错误 the name qrySingleMovie does not exist in the current context

型号

public class Movie
{
    public int ID { get; set; }
    public string Title { get; set; }
    public DateTime ReleaseDate { get; set; }
    public string Genre { get; set; }
    public decimal Price { get; set; }
}

public class Year
{
  public int YearId {get; set;}
  public int MovieYear {get; set;}
}

ViewModel

public class MovieGenreViewModel
{
    public ???? myMovie;
    public SelectList MovieReleaseYears;
    public int ReleasedYr { get; set; }
}

控制器

public async Task<IActionResult> Index(int MovieID)
{
    // Use LINQ to get list of Release years.
    IQueryable<string> YearQuery = from m in _context.Years
                                    orderby m.MovieYear
                                    select m.MovieYear;

    //Following query selects only a single movie based on Primary Key ID
    var qrysingleMovie = from m in _context.Movies
                 where m.ID == movieID
                 select m;

    var movieReleaseYrVM = new MovieGenreViewModel();
    movieReleaseYrVM.MovieReleaseYears = new SelectList(await YearQuery.ToListAsync());
    movieReleaseYrVM.myMovie = ????

    return View(movieReleaseYrVM);
}

更新

在我的真实项目中,模型有很多属性,对应的View也显示了大部分属性。我在想是否有一种更简单的方法来定义一个不包含模型所有属性的 ViewModel,例如这个 ASP.NET Article 定义了一个视图模型 MovieGenreViewModel 但他们正在使用 List 并在他们的 View他们正在遍历多部电影。我试图模仿他们的示例,但在我的例子中,它是带有 SelectList 的单个记录(不是记录列表)。我怎样才能用一条记录模拟这种场景,而不能在视图模型中包含该模型具有的大量模型属性?

既然你想更新一个电影记录,你只需要获取电影记录的唯一ID。那么为什么不将 MovieId 属性 添加到您的视图模型。如果您希望在 UI 中显示电影名称,您也可以添加 MovieName 属性。

记住视图模型是特定于视图的。创建视图模型时,没有必要模仿整个实体模型。仅添加您的视图绝对需要的那些属性。

public class MovieGenreViewModel
{
    public int MovieId;
    public string MovieName { set;get;}
    public SelectList MovieReleaseYears;
    public int ReleasedYr { get; set; }
}

现在在您的 GET 操作中设置这些 属性 值。

public async Task<IActionResult> Index(int MovieID)
{
    var vm = new MovieGenreViewModel();

    var movie =  _context.Movies.FirstOrDefault(x=>x.ID==movieID);

    if(movie==null)
       return Content("Movie not found"); // to do :Return a view with "not found" message

    IQueryable<string> YearQuery = from m in _context.Years
                                    orderby m.MovieYear
                                    select m.MovieYear;   

    // set the property values. 
    vm .MovieReleaseYears = new SelectList(await YearQuery.ToListAsync());
    vm .MovieId= movie.ID;
    vm .MovieName= movie.Name;

    return View(vm );
}

现在在您的视图中,您将电影 ID 保存在一个隐藏字段中,这样当您提交表单时,它将被提交给处理表单提交的 HttpPost 操作方法。

@model MovieGenreViewModel
@using(Html.BeginForm("AssignYear","Home"))
{
    <p>@Model.MovieName</p>
    @Html.HiddenFor(s=>s.MovieId)
    @Html.DropDownListFor(d=>d.ReleasedYr, Model.MovieReleaseYears)
    <input type="submit"/>
}

您可以使用与 AssignYear 操作方法参数相同的视图模型

[HttpPost]
public ActionResult AssignYear(MovieGenreViewModel model)
{
  // check model.MovieId and model.ReleasedYr
  // to do : Save data and return something
}

如果您不想只将视图所需的那些属性添加到视图模型,而是想显示电影的大量属性,您可以考虑添加一个新的 属性 类型 Movie 到您的视图模型

public class MovieGenreViewModel
{
    public Movie Movie { set;get;}
    public SelectList MovieReleaseYears;
    public int ReleasedYr { get; set; }
}

您现有的 LINQ 语句 returns 一个元素的集合。您不能将电影集合分配给 属性 类型的电影。您可以使用 FirstOrDefault() 方法获取单个对象。

var movie =  _context.Movies.FirstOrDefault(x=>x.ID==movieID);
 //After null check
vm.Movie = movie;

为什么不能使用 Movie 作为 "myMovie" 属性 的类型? 然后您可以使用 object 来显示 example.ie movie.Name 的名称。 您还可以将 movieId 存储在隐藏字段中,这样当您 post 返回时,您可以在服务器端使用它。 您可以使用 LINQ 从数据库中检索 object,如下所示:

var qrysingleMovie = _context.Movies.Single(m=> m.ID == movieID);

或者,您可以使用 2 个属性而不是整个 object。一个用于标题,即:string MovieName,另一个用于 id int MovieId

public string MovieName  { get; set; }
public int MovieId  { get; set; }

注意:请记住,使用 "Single" 意味着您需要在数据库中拥有电影,否则会抛出异常。