简体   繁体   中英

How to declare List of anonymous type

In this official ASP.NET MVC Core tutorial they have defined a ViewModel as follows where Movie is a class. Then in the Index(...) method (towards the end of the tutorial they are populating the ViewModel from a simple LINQ query as shown in the Controller below:

ViewModel :

public class MovieGenreViewModel
{
    public List<Movie> movies;
    public SelectList genres;
    public string movieGenre { get; set; }
}

Controller :

public async Task<IActionResult> Index(string movieGenre, string searchString)
{
    // Use LINQ to get list of genres.
    IQueryable<string> genreQuery = from m in _context.Movie
                                    orderby m.Genre
                                    select m.Genre;

    var movies = from m in _context.Movie
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (!String.IsNullOrEmpty(movieGenre))
    {
        movies = movies.Where(x => x.Genre == movieGenre);
    }

    var movieGenreVM = new MovieGenreViewModel();
    movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
    movieGenreVM.movies = await movies.ToListAsync();

    return View(movieGenreVM);
}

Question : In the above ViewModel the property movies was of type List<movie> and the query used in the Index(...) method was a simple query involving just one table (movies). But what if the query involves an INNER JOIN with two tables and hence returns an object of anonymous type as shown below. In that case how would we declare a list of anonymous type List<.?.> in a ViewModel and then populate that property of type List<.?.> in the ViewModel? In the example below I defined a ViewModel with List<dynamic> or List<object> and tried myViewModel.list = leftOuterJoinQuery.ToListAsync() but got the error as Cannot implicitly convert type 'List<<anonymous type: int CategoryId, string CategoryName, string ProdName>>>' to 'System.Collections.Generic.List<dynamic> :

LINQ INNER JOIN Query :

var innerJoinQuery =
    from category in categories
    join prod in products on category.ID equals prod.CategoryID
    select new { ProductName = prod.Name, Category = category.Name }; //produces flat sequence

UPDATE :

As @StephenMuecke suggested below, the problem can be solved by creating another View Model containing the properties returned by my query. But I'm thinking if there is a way to avoid creating an extra View Model.

There is way to accomplish it without creating new VM, but i'm not sure it is the right way.

First, I'll turn the VM as below

public class MovieGenreViewModel
{
    public ICollection movies;
    public SelectList genres;
    public string movieGenre { get; set; }
}

Define a helper method to compose list from anonymous objects

public static List<T> CreateList<T>(params T[] elements)
{
     return new List<T>(elements);
}

Finally, change the line inside Index() method

from

movieGenreVM.movies = await movies.ToListAsync();

to

   var output = await innerJoinQuery.ToListAsync();
   movieGenreVM.movies = CreateList(output);

Hope this helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM