c# - 一个视图中的父子模型(多个模型)(ASP.NET Core (C#) + MVC + Entity Framework)
问题描述
我正在尝试制作一个在一个视图(ASP.NET Core + MVC + Entity Framework)中具有父子模型(多个模型)的 Web 应用程序。
以下为输入(输入 No.1)。这是“视图/博客/index.cshtml”
以下也被输入(输入 No.2)。这是“视图/标签/index.cshtml”
以下是我期望的输出(输出 No.1)。
我写了以下“视图/博客/cshtml”。
@model IEnumerable<urlapp12.Models.UrlTag>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Blog.Userid)
</th>
<th>
@Html.DisplayNameFor(model => model.Blog.Url)
</th>
<th>
@Html.DisplayNameFor(model => model.Blog.LastUpdatedAt_UtcDt)
</th>
<th>
@Html.DisplayNameFor(model => model.Blog.LastUpdatedAt_LocalDt)
</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Blog.Userid)
</td>
<td>
<a href="@Html.DisplayFor(modelItem => item.Blog.Url)">@Html.DisplayFor(modelItem => item.Blog.Title)</a>
</td>
<td>
@Html.DisplayFor(modelItem => item.Blog.LastUpdatedAt_UtcDt)
</td>
<td>
@Html.DisplayFor(modelItem => item.Blog.LastUpdatedAt_LocalDt)
</td>
<td>
@foreach (var childItem in item.Tag)
{
@Html.DisplayFor(modelItem => childItem.tagItem)
}
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.Blog.BlogId">Edit</a> |
<a asp-action="Details" asp-route-id="@item.Blog.BlogId">Details</a> |
<a asp-action="Delete" asp-route-id="@item.Blog.BlogId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
并执行,我得到了以下错误。(输出 No.2。真正的意外输出)
An unhandled exception occurred while processing the request.
InvalidOperationException: The model item passed into the ViewDataDictionary is of type 'System.Collections.Generic.List`1[urlapp12.Models.Blog]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable`1[urlapp12.Models.UrlTag]'.
Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.EnsureCompatible(object value)
Models/Blog.cs 如下。
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace urlapp12.Models
{
public partial class Blog
{
public Blog()
{
Post = new HashSet<Post>();
}
[Key]
public int BlogId { get; set; }
public string Userid { get; set; }
public string Url { get; set; }
public string Title { get; set; }
public string CreatedBy { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime CreatedAt_UtcDt { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime CreatedAt_LocalDt { get; set; }
public string LastUpdatedBy { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime LastUpdatedAt_UtcDt { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime LastUpdatedAt_LocalDt { get; set; }
public ICollection<Tag> Tag { get; set; }
public ICollection<Post> Post { get; set; }
/*
public List<Tag> Tag { get; set; }
public List<Post> Post { get; set; }
*/
}
}
Models/Tag.cs 如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace urlapp12.Models
{
public class Tag
{
public int Id { get; set; }
public int DispOrderNbr { get; set; }
public string tagItem { get; set; }
public int BlogId { get; set; }
public string CreatedBy { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime CreatedAt_UtcDt { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime CreatedAt_LocalDt { get; set; }
public string LastUpdatedBy { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime LastUpdatedAt_UtcDt { get; set; }
[System.ComponentModel.DataAnnotations.Schema.Column(TypeName = "datetime2")]
public DateTime LastUpdatedAt_LocalDt { get; set; }
[System.ComponentModel.DataAnnotations.Schema.ForeignKey("BlogId")]
public Blog blog { get; set; }
}
}
模型/UlrTag.cs 如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace urlapp12.Models
{
public class UrlTag
{
public Blog Blog { get; set; }
public IEnumerable<Tag> Tag { get; set; }
}
}
有人对这个亲子模型有帮助吗?先感谢您。
Blogs.Controller.cs 如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using urlapp12.Models;
namespace urlapp12.Controllers
{
public class BlogsController : Controller
{
private readonly Blogging02Context _context;
// Stores UserManager
private readonly UserManager<ApplicationUser> _manager;
private UserManager<ApplicationUser> _userManager;
public BlogsController(Blogging02Context context, UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
_context = context;
}
// GET: Blogs
public async Task<IActionResult> Index()
{
return View(await _context.Blog.ToListAsync());
}
// GET: Blogs/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var blog = await _context.Blog
.SingleOrDefaultAsync(m => m.BlogId == id);
if (blog == null)
{
return NotFound();
}
return View(blog);
}
// GET: Blogs/Create
public IActionResult Create()
{
return View();
}
// POST: Blogs/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost] [ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("BlogId,Userid,Url,Title")] Blog blog)
{
if (ModelState.IsValid)
{
/*
string strCurrentUserId;
strCurrentUserId = User.Identity.GetUserId(this IIdentity identity);
var currentUserName = User.Identity.Name ;
var user = await UserManager<ApplicationUser>.FindByIdAsync(User.Identity.GetUserId());
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new MyDbContext()));
var UserManager = new UserManager(IUserstore<ApplicationUser>);
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
var user = await GetCurrentUserAsync();
var userId = user?.Id;
string mail = user?.Email;
var userid = GetCurrentUserClaims().userid;
var userClaims = new UserClaims();
var claims = _httpContextAccessor.HttpContext.User.Claims.ToList();
var userid2 = await IGenericRepository < User > userRepository.GetByIdAsync(_currentUserGuid);
UserManager<ApplicationUser> _userManager;
SignInManager<ApplicationUser> _signInManager = new SignInManager<ApplicationUser>();
var info = await _signInManager.GetExternalLoginInfoAsync();
*/
// Stores UserManager
// private readonly UserManager<ApplicationUser> _manager;
// var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
// var result = await _userManager.CreateAsync(user, model.Password);
var user = await _userManager.GetUserAsync(HttpContext.User);
var currentLoginUserid = user.Id;
blog.Userid = user.Id;
int maxIdInDb = 0;
int BlogRecCnt = _context.Blog.Count();
if (_context.Blog.Count() == 0)
{
maxIdInDb = 0;
}
else
{
maxIdInDb = _context.Blog.Max(p => p.BlogId);
}
int NextId = maxIdInDb + 1;
blog.BlogId = NextId;
blog.CreatedAt_LocalDt = DateTime.Now;
blog.CreatedAt_UtcDt = DateTime.UtcNow;
blog.CreatedBy = user.Id;
blog.LastUpdatedAt_LocalDt = DateTime.Now;
blog.LastUpdatedAt_UtcDt = DateTime.UtcNow;
blog.LastUpdatedBy = user.Id;
_context.Add(blog);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(blog);
}
// GET: Blogs/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var blog = await _context.Blog.SingleOrDefaultAsync(m => m.BlogId == id);
if (blog == null)
{
return NotFound();
}
var user = await _userManager.GetUserAsync(HttpContext.User);
var currentLoginUserid = user.Id;
blog.Userid = user.Id;
blog.LastUpdatedAt_LocalDt = DateTime.Now;
blog.LastUpdatedAt_UtcDt = DateTime.UtcNow;
blog.LastUpdatedBy = user.Id;
return View(blog);
}
// POST: Blogs/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("BlogId,Userid,Url,Title")] Blog blog)
{
if (id != blog.BlogId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(blog);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!BlogExists(blog.BlogId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
return View(blog);
}
// GET: Blogs/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var blog = await _context.Blog
.SingleOrDefaultAsync(m => m.BlogId == id);
if (blog == null)
{
return NotFound();
}
return View(blog);
}
// POST: Blogs/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
var blog = await _context.Blog.SingleOrDefaultAsync(m => m.BlogId == id);
_context.Blog.Remove(blog);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool BlogExists(int id)
{
return _context.Blog.Any(e => e.BlogId == id);
}
}
}
TagsController.cs 如下。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using urlapp12.Models;
namespace urlapp12.Controllers
{
public class TagsController : Controller
{
private readonly Blogging02Context _context;
public TagsController(Blogging02Context context)
{
_context = context;
}
//int id, [Bind("BlogId,Userid,Url,Title")] Blog blog
// GET: Tags
// public async Task<IActionResult> Index()
public async Task<IActionResult> Index(int id, [Bind("BlogId,Userid,Url,Title")] Blog blog)
{
/*
return View(await _context.Tag.ToListAsync());
*/
var blogging02Context = _context.Tag.Include(t => t.blog);
return View(await blogging02Context.ToListAsync());
// return View (await _context.Tag.ToListAsync());
}
// GET: Tags/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var tag = await _context.Tag
.Include(t => t.blog)
.SingleOrDefaultAsync(m => m.Id == id);
if (tag == null)
{
return NotFound();
}
return View(tag);
}
// GET: Tags/Create
public IActionResult Create()
{
ViewData["BlogId"] = new SelectList(_context.Blog, "BlogId", "Title");
return View();
}
// POST: Tags/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,DispOrderNbr,tagItem,BlogId")] Tag tag)
{
if (ModelState.IsValid)
{
_context.Add(tag);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["BlogId"] = new SelectList(_context.Blog, "BlogId", "Title", tag.BlogId);
return View(tag);
}
// GET: Tags/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var tag = await _context.Tag.SingleOrDefaultAsync(m => m.Id == id);
if (tag == null)
{
return NotFound();
}
ViewData["BlogId"] = new SelectList(_context.Blog, "BlogId", "Title", tag.BlogId);
return View(tag);
}
// POST: Tags/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, [Bind("Id,DispOrderNbr,tagItem,BlogId")] Tag tag)
{
if (id != tag.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(tag);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!TagExists(tag.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["BlogId"] = new SelectList(_context.Blog, "BlogId", "Title", tag.BlogId);
return View(tag);
}
// GET: Tags/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var tag = await _context.Tag
.Include(t => t.blog)
.SingleOrDefaultAsync(m => m.Id == id);
if (tag == null)
{
return NotFound();
}
return View(tag);
}
// POST: Tags/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int? id)
{
var tag = await _context.Tag.SingleOrDefaultAsync(m => m.Id == id);
_context.Tag.Remove(tag);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
private bool TagExists(int id)
{
return _context.Tag.Any(e => e.Id == id);
}
}
}
junkongli 和 Gimly,谢谢你的回复。
我已经尝试过 Gimly 的想法。
public async Task<IActionResult> Index()
{
return View(await _context.Blog.Include(b => b.Tags).ToListAsync());
}
然后 Visual Studio 告诉我“'Blog' 不包括 'Tags' 定义”错误。所以我已将标签更改为标签,我的 Visual Studio 说没问题
public async Task<IActionResult> Index()
{
return View(await _context.Blog.Include(b => b.Tag).ToListAsync());
}
我在调试模式下运行代码,Web 应用程序返回以下错误。
处理请求时发生未处理的异常。InvalidOperationException:传递到 ViewDataDictionary 的模型项的类型为“System.Collections.Generic.List 1[urlapp12.Models.Blog]', but this ViewDataDictionary instance requires a model item of type 'System.Collections.Generic.IEnumerable
1[urlapp12.Models.UrlTag]”。Microsoft.AspNetCore.Mvc.ViewFeatures.ViewDataDictionary.EnsureCompatible(对象值)
非常感谢你。
我已将代码“/Views/Blogs/Index.cshml”更改如下,并且可以成功执行。
@model IEnumerable<urlapp12.Models.Blog>
@{
ViewData["Title"] = "Index";
}
<h2>Index</h2>
<p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.Userid)
</th>
<th>
@Html.DisplayNameFor(model => model.Url)
</th>
<th>
@Html.DisplayNameFor(model => model.LastUpdatedAt_UtcDt)
</th>
<th>
@Html.DisplayNameFor(model => model.LastUpdatedAt_LocalDt)
</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.Userid)
</td>
<td>
<a href="@Html.DisplayFor(modelItem => item.Url)">@Html.DisplayFor(modelItem => item.Title)</a>
</td>
<td>
@Html.DisplayFor(modelItem => item.LastUpdatedAt_UtcDt)
</td>
<td>
@Html.DisplayFor(modelItem => item.LastUpdatedAt_LocalDt)
</td>
<td>
@foreach (var childItem in item.Tag)
{
@Html.DisplayFor(itemItem => childItem.tagItem)
}
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.BlogId">Edit</a> |
<a asp-action="Details" asp-route-id="@item.BlogId">Details</a> |
<a asp-action="Delete" asp-route-id="@item.BlogId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
解决方案
首先,关于您遇到的异常,错误消息非常明确,@junkangli 在其评论中解释说,您没有将正确的对象返回给视图。View 需要一个IEnumerable<UrlTag>
,而您正在向它发送一个IEnumerable<Blog>
.
现在,关于问题的核心,您需要在查询中加载标签列表以获取博客列表,因此,在控制器的Index
操作中,您应该执行以下操作:
public async Task<IActionResult> Index()
{
return View(await _context.Blog.Include(b => b.Tags).ToListAsync());
}
然后,在您看来,您应该能够访问您的标签并创建一个 while 循环来显示您的所有标签。
推荐阅读
- javascript - 如何在 JavaScript 中指定最小值和最大值时使用递归创建数组
- laravel - ln:创建符号链接失败:协议错误(在 Vagrant 中)
- android - 创建apk后的Android Studio问题
- css - 你如何在反应中 mpa 一个 json const 并设置它的样式?
- python - pip install mysql-python 失败,缺少 config-win.h
- stenciljs - 如何在 StencilJS 中使用 getter/setter 处理 @Prop() 逻辑
- c++ - 如何改进以下 lambda 函数以查找向量中的前 4 个元素
- asp.net - ChangePassword 控件忽略自定义模板并呈现默认值
- pandas - 如何从熊猫“编码”数据框的列
- excel - VBA 在 Excel 中创建带有表格和签名的电子邮件