Reputation: 23749
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.
Upvotes: 1
Views: 5282
Reputation: 6322
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.
Upvotes: 2