Модель «родитель-потомок» (несколько моделей) в одном представлении (ASP.NET Core (C #) + MVC + Entity Framework) - PullRequest
0 голосов
/ 30 апреля 2018

Я пытаюсь создать веб-приложение с моделью Parent-Child (несколько моделей) в одном представлении (ASP.NET Core + MVC + Entity Framework).

Следующее является входом (вход № 1). Это "Views / Blogs / index.cshtml"

Image of Views/Blogs/index.cshtml

Следующее также является входом (вход № 2). Это "Views / Tags / index.cshtml"

Image of Views/Tags/index.cshtml

Ниже приведены мои ожидаемые результаты (выход № 1).
Image of Views/Blogs/index.cshtml

Я написал следующее "Views / Blogs / 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>

И, выполнив, я получил следующую ошибку. (вывод №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);
        }
    }
}

junkangli и Gimly, спасибо за ответ.

Я испробовал идею Джимли.

public async Task<IActionResult> Index()
{
    return View(await _context.Blog.Include(b => b.Tags).ToListAsync());
}

Затем Visual Studio сказала мне, что ошибка «Блог» не содержит определение «Теги». Поэтому я изменил теги на теги, My Visual Studio говорит, что это O.K.

public async Task<IActionResult> Index()
{
    return View(await _context.Blog.Include(b => b.Tag).ToListAsync());
}

Я запускаю свои коды для режима отладки, веб-приложение вернуло следующую ошибку.

Произошло необработанное исключение при обработке запроса. 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>

1 Ответ

0 голосов
/ 30 апреля 2018

Во-первых, об исключении, которое вы получаете, сообщение об ошибке довольно явное, и @junkangli объяснил это в своем комментарии: вы не возвращаете правильный объект в View. View ожидает IEnumerable<UrlTag>, а вы отправляете IEnumerable<Blog>.

Теперь, что касается сути вашей проблемы, вы захотите загрузить список тегов в своем запросе для получения списка блогов, поэтому в действии Index вашего контроллера вы должны сделать что-то вроде:

public async Task<IActionResult> Index()
{
    return View(await _context.Blog.Include(b => b.Tags).ToListAsync());
}

Затем, по вашему мнению, вы сможете получить доступ к своим тегам и создать цикл while для отображения всех ваших тегов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...