实体框架主动加载-传递数据到视图模型
本文关键字:数据 视图 模型 框架 加载 实体 | 更新日期: 2023-09-27 18:06:46
. NET MVC核心应用程序,从一个动作方法如下所示,我传递博客数据及其相关数据从Posts表到视图作为return View(await _context.Blogs.Include(p => p.Posts).ToListAsync());
因为我从两个表传递数据,我需要使用如下所示的ViewModel。问题:我如何使用ViewModel从我的控制器动作方法传递相关数据Test()
查看下图?
在下面的代码中,我得到了明显的错误:
InvalidOperationException:传入ViewDataDictionary的模型项的类型是'System.Collections.Generic.List'1[asp_core_logs . models . error]。,但是这个ViewDataDictionary实例需要一个类型为' system . collections . general . 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());
}
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; }
}
<<p> 视图/strong>: @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>
您需要使用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>
在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/)
用于将数据作为ViewModel从Action传递到view。首先创建一个视图模型的新实例,并通过调用上下文查询(无论您的Linq查询是什么)为每个属性赋值,并返回视图列表作为视图模型变量。
var blogWithRelatedPost = new BolblogWithRelatedPost();
// your logic here for assigning value to property or LINQ query
return View(blogWithRelatedPost);