2

在我的ASP.NET MVC Core应用程序中,从下面显示的操作方法中,我将博客数据及其相关数据从Posts表传递到视图,因为我是从两个表传递数据,我需要使用下面显示的ViewModel。 问题:如何使用ViewModel从我的控制器操作方法 Test()传递相关数据以查看下面显示的内容?实体框架Eager Loading - 将数据传递给ViewModel

在下面的代码我得到了明显错误

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]'.

型号

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; } 
} 

控制器

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

视图模型

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; } 
} 

查看

@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

您需要使用您的BlogsWithRelatedPostsViewModel类项目查询:

 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扩展方法允许你从压扁每个投影e.Posts到最后你会得到一个List<BlogsWithRelatedPostsViewModel>

+0

我得到上'ToLisAsync的误差()'为:'的IEnumerable “不包含一个定义‘ToListAsync’和没有扩展方法‘ToListAsync’接受型的第一参数”的IEnumerable 'BlogsWithRelatedPostsViewModel>'可以找到' – nam

+0

'ToList()'我收到错误:InvalidOperationException:传递给ViewDataDictionary的模型项目类型为'Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable'1 [ASP_Core_Blogs。 Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel]',但是这个ViewDataDictionary实例需要一个'System.Collections.Generic.List'1 [ASP_Core_Blogs.Models.BlogPostViewModels.BlogsWithRelatedPostsViewModel]'。'类型的模型项。在@model指令的视图中,我确实在获取此错误之前将'IList <...>'更改为'List <...>'。 – nam

+0

这没什么意义,它就像传递查询结果但不调用ToList。你确定这是行动吗? – octavioccl

0

在Octavioccl的顶部,答案有一个很好的小扩展方法,我一直在使用(我不知道作者,但如果其他人知道,我会很高兴地更新我的答案,以信贷)。这样,你不必写出每个属性。

public static T Cast<T>(this object myobj) 
{ 
    var target = typeof(T); 
    var x = Activator.CreateInstance(target, false); 
    var d = from source in target.GetMembers().ToList() 
      where source.MemberType == MemberTypes.Property 
      select source; 
    var memberInfos = d as MemberInfo[] ?? d.ToArray(); 
    var members = memberInfos.Where(memberInfo => memberInfos.Select(c => c.Name) 
     .ToList().Contains(memberInfo.Name)).ToList(); 
    foreach (var memberInfo in members) 
    { 
     var propertyInfo = typeof(T).GetProperty(memberInfo.Name); 
     if (myobj.GetType().GetProperty(memberInfo.Name) == null) continue; 
     var value = myobj.GetType().GetProperty(memberInfo.Name).GetValue(myobj, null); 
     propertyInfo.SetValue(x, value, null); 
    } 
    return (T)x; 
} 

用法:

var ViewModelList = ModelList.Select(model => model.Cast<ViewModel>()).ToList(); 

还为这一特定问题建立了一个很好的支持框架。称为AutoMapper(http://automapper.org/)。

0

用于从Action中传递数据以查看ViewModel。首先创建View Model的新实例,并通过调用上下文查询(无论您的Linq查询是什么)并将视图列表作为View模型变量返回,为每个Propery赋值。

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