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

本文关键字:记录 单个 LINQ 结果 查询 一个 SelectList 有一个 ViewModel | 更新日期: 2023-09-27 18:14:47

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

  1. LINQ查询中只返回一条记录的query result type
  2. A SelectList

换句话说,假设我们有一个基于所选ID只显示单个电影的视图。我们想分配一年的发布,从年的下拉列表的电影,我如何在以下视图模型和控制器中填写???? ?

注意:在以下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文章定义了一个视图模型MovieGenreViewModel,但在那里他们使用列表,并在他们的视图中迭代多个电影。我试图模仿他们的例子,但在我的情况下,这是一个单一的记录(不是记录列表)与SelectList。我如何用一条记录模拟那种场景,而不能在视图模型中包含模型所具有的大量模型属性?

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

因为你想要更新一个Movie记录,所有你需要得到的电影记录是它的唯一Id。那么为什么不向视图模型添加一个MovieId属性呢?如果您希望在UI中显示MovieName,您也可以添加一个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语句返回一个元素的集合。不能将Movies集合分配给Movie类型的属性。你可以使用FirstOrDefault()方法来获取单个对象。

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

为什么不能使用Movie作为myMovie属性的类型?然后,您可以使用该对象来显示名称。即 movie.Name 。您还可以将movieId存储在一个隐藏字段中,以便在您发回时可以在服务器端使用它。您可以使用LINQ从数据库检索该对象,如下所示:

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

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

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

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