在 ASP.NET Core MVC 中编辑多对多关系数据

问题描述 投票:0回答:1

我使用多对多关系数据表为我的网站帖子创建了标签。我想使用控制器和视图模型来编辑/更新数据库表中的标签数据

Models

public class PostModel
{
    [Key]
    public int Id { get; set; }
    public string? Title { get; set; }

    public List<TagModel> Tags { get; set; }
    public List<PostTagModel> PostTags { get; set; }
}


public class TagModel
{
    [Key]
    public int Id { get; set; }
    public string? Title { get; set; }

    public List<PostModel> Posts { get; set; }
    public List<PostTagModel> PostTags { get; set; }
}


public class PostTagModel
{
    public int PostId { get; set; }
    public int TagId { get; set; }

    public PostModel Post { get; set; }
    public TagModel Tag { get; set; }
}

ViewModel

public class EditPostViewModel
{
    public string? Title { get; set; }
    public string? Description { get; set; }
    public List<int>? TagId { get; set; }

    public List<TagModel>? TagList { get; set; }
}

Controller

[HttpGet]
public async Task<IActionResult> Edit(int id)
{
    // Id Check
    var post = await _postInterface.GetByIdAsync(id);

    // Check
    if (post == null)
    {
        return View("Error");
    }


    var postVM = new EditPostViewModel
    {
        Title = post.Title,
        Description = post.Description,
        TagId = post.Tags, // Gives error CS0029

        // List
        TagList = await _context.Tags.ToListAsync()
    };

    return View(postVM);
}

[HttpPost] 
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, EditPostViewModel postVM)
{
    // Check
    if (!ModelState.IsValid)
    {
        ModelState.AddModelError("", "Failed to edit post");

        return View("Edit", postVM);
    }

    // Id Select
    var userPost = await _postInterface.GetByIdAsyncNoTracking(id);

    // Selected Tag
    var tags = await _tagInterface.GetAll();

    List<TagModel> selectedTags = new List<TagModel>();

    if (postVM.TagId != null && postVM.TagId.Any())
    {
        selectedTags = tags.Where(x => postVM.TagId.Contains(x.Id)).ToList();
    }



    if (userPost != null)
    {
        var post = new PostModel
        {
            Id = id,
            Title = postVM.Title,
            Description = postVM.Description,
            Tags = selectedTags
        };

        _postInterface.Update(post);

        return RedirectToAction("Index");
    }
    else
    {
        return View(postVM);
    }
}

View

@using SimpleWebsite.ViewModels.PostViewModel

@model EditPostViewModel

<!-- Code above -->


<!-- Tag -->
@if (Model.TagList != null)
{
    <div class="col-md-12 mb-3">
        <label asp-for="TagId" class="control-label"></label>

        <div class="form-check-inline">
            @foreach (var item in Model.TagList)
            {
                <input name="TagId" type="checkbox" class="btn-check" id="@item.Id" value="@item.Id">
                <label asp-for="TagId" class="btn btn-outline-primary" for="@item.Id">@item.Title</label>
            }
        </div>

        <span asp-validation-for="TagId" class="text-danger"></span>
    </div>
}

<!-- Code Below -->
c# asp.net-core-mvc many-to-many
1个回答
0
投票

我已经解决了我的问题。我还更新了我的 GitHub 存储库上的代码。

Models:

virtual
添加到所有模型中的多对多数据库表中。无需迁移或更新数据库

public class PostModel
{
    [Key]
    public int Id { get; set; }
    public string? Title { get; set; }
    public string Description { get; set; }

    public List<TagModel> Tags { get; set; }
    public virtual List<PostTagModel> PostTags { get; set; }
}


public class TagModel
{
    [Key]
    public int Id { get; set; }
    public string? Title { get; set; }
    public string Description { get; set; }

    public List<PostModel> Posts { get; set; }
    public virtual List<PostTagModel> PostTags { get; set; }
}


public class PostTagModel
{
    public int PostId { get; set; }
    public int TagId { get; set; }

    public virtual PostModel Post { get; set; }
    public virtual TagModel Tag { get; set; }
}

ViewModels
:添加了SelectedItemViewModel

public class SelectedItemViewModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool Selected { get; set; }
}


public class EditPostViewModel
{
    public string? Title { get; set; }
    public string? Description { get; set; }
    public List<SelectedItemViewModel> Tag { get; set; }
}

Controller

[HttpGet]
public async Task<IActionResult> Edit(int id)
{
    // Id Check
    var post = await _postInterface.GetByIdAsync(id);

    // Check
    if (post == null)
    {
        return View("Error");
    }

    // Initialize Selected Tags
    var Results = from t in _context.Tags
                  select new
                  {
                      t.Id,
                      t.Title,
                      t.Description,
                      Checked = ((from pt in _context.PostTags
                                  where (pt.PostId == id) &
                                        (pt.TagId == t.Id)
                                  select pt).Count() > 0),

                  };

    // Tags List
    var TagList = new List<SelectedItemViewModel>();

    // Selected Tags
    foreach (var item in Results)
    {
        TagList.Add(new SelectedItemViewModel
        {
            Id = item.Id,
            Name = item.Title,
            Description = item.Description,
            Selected = item.Checked
        });
    }

    var postVM = new EditPostViewModel
    {
        Title = post.Title,
        Description = post.Description,
        Tag = TagList
    };

    return View(postVM);
}


[HttpPost] 
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, EditPostViewModel postVM)
{
    // Check
    if (ModelState.IsValid)
    {
        ModelState.AddModelError("", "Failed to edit post");

        return View("Edit", postVM);
    }

    // Id Select
    var userPost = await _postInterface.GetByIdAsyncNoTracking(id);

    if (userPost != null)
    {
        var post = new PostModel
        {
            Id = id,
            Title = postVM.Title,
            Description = postVM.Description,
        };

        // Delete Selected Tags
        foreach (var item in _context.PostTags)
        {
            if (item.PostId == id)
            {
                _context.Entry(item).State = EntityState.Deleted;
            }
        }

        // Update Selected tags
        foreach (var item in postVM.Tag)
        {
            if (item.Selected)
            {
                _context.PostTags.Add(new PostTagModel()
                {
                    PostId = id,
                    TagId = item.Id
                });
            }
        }

        _postInterface.Update(post);

        return RedirectToAction("Index");
    }
    else
    {
        return View(postVM);
    }
}

View

@using SimpleWebsite.ViewModels.PostViewModel

@model EditPostViewModel

<!-- Code above -->


<!-- Tag -->
@if (Model.Tag != null)
{
    <div class="col-md-12 mb-3">
        <label asp-for="Tag" class="control-label"></label>

        <br />

        <div class="form-check-inline">
            @for (int i = 0; i < Model.Tag.Count(); i++)
            {
                <input type="checkbox" asp-for="@Model.Tag[i].Selected" class="form-check-input" id="@Model.Tag[i].Id">
                <label class="form-check-label me-3" title="@Model.Tag[i].Description" for="@Model.Tag[i].Id">@Model.Tag[i].Name</label>

                <input type="hidden" asp-for="@Model.Tag[i].Id">
            }
        </div>

        <span asp-validation-for="Tag" class="text-danger"></span>
    </div>
}

<!-- Code Below -->
© www.soinside.com 2019 - 2024. All rights reserved.