Entity Framework Eager Loading - pass data to ViewModel

asp.net-mvc c# entity-framework-core linq-to-entities visual-studio-2015

Question

In my ASP.NET MVC Core app, from an action method shown below, I'm passing Blogs data and its related data from Posts table to a view as return View(await _context.Blogs.Include(p => p.Posts).ToListAsync()); Since I'm passing data from two tables, I need to use a ViewModel shown below. Question: How can I use ViewModel to pass the related data from my Controller Action method Test() to view shown below?

In the code below I'm getting the obvious error:

InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List'1[ASP_Core_Blogs.Models.Blog]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IList'1[ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel]'.

Model:

public class BloggingContext : DbContext
{
    public BloggingContext(DbContextOptions<BloggingContext> options)
        : base(options)
    { }

    public DbSet<Blog> Blogs { get; set; }
    public DbSet<Post> Posts { get; set; }
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int PostYear { get; set; }
    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Controller:

[HttpGet]
public async Task<IActionResult> Test(string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    return View(await _context.Blogs.Include(p => p.Posts).ToListAsync());
}

ViewModel:

public class BlogsWithRelatedPostsViewModel
{
    public int BlogID { get; set; }
    public int PostID { get; set; }
    public string Url { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public int PostYear { get; set; }
}

View:

@model IList<ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel>

<div class="row">
    <div class="col-md-12">
        <form asp-controller="DbRelated" asp-action="EnterGrantNumbers" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post">
            <table class="table">
                <thead>
                    <tr>
                        <th></th>
                        <th></th>
                        <th>Url</th>
                        <th>Title</th>
                        <th>Content</th>
                    </tr>
                </thead>
                <tbody>
                    @for (int t = 0; t < Model.Count; t++)
                    {
                        <tr>
                            <td><input type="hidden" asp-for="@Model[t].BlogID" /></td>
                            <td><input type="hidden" asp-for="@Model[t].PostID" /></td>
                            <td>
                                <input type="text" asp-for="@Model[t].Url" style="border:0;" readonly /> <!--Not using /*Html.DisplayFor(modelItem => Model[t].Url)*/ since it does not submit stateName on Post. Not using <label asp-for=.....> since Bootstrap bold the text of <label> tag-->
                            </td>
                            <td>
                                <input asp-for="@Model[t].Title" />
                            </td>
                            <td>
                                <input asp-for="@Model[t].Content" />
                            </td>
                        </tr>
                    }
                </tbody>
            </table>
            <button type="submit" class="btn btn-default">Save</button>
        </form>
    </div>
</div>
1
2
9/12/2016 9:45:48 PM

Accepted Answer

You need to project your query using your BlogsWithRelatedPostsViewModel class:

     return View( _context.Blogs
                          .Include(p => p.Posts)
                          .SelectMany(e=> e.Posts.Select(p=> new BlogsWithRelatedPostsViewModel
                                                             {
                                                              BlogId= e.BlogId,
                                                              PostId=p.PostId,
                                                              Url=e.Url,
                                                              ...
                                                             })
                          .ToList()); 

SelectMany extension method allows you flatten each projection from e.Posts into one sequence, so at the end you will get a List<BlogsWithRelatedPostsViewModel>

2
9/12/2016 9:55:52 PM

Popular Answer

For passing data from Action to view as ViewModel. Create a new instance of your View Model first and assign value to each propery by calling your context query(whatever your Linq query is) and return the list of view as your View model variable.

var blogWithRelatedPost = new BolblogWithRelatedPost();
// your logic here for assigning value to property or LINQ query
return View(blogWithRelatedPost);


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow