我正在使用多对多关系为我的网站帖子创建标签。我按照
Microsoft 文档,设法使用实体框架创建了
PostTags
数据库表。
我现在想在创建帖子时使用 Controller 和 ViewModel 在数据库中插入标签数据,但不知道如何继续。
我的代码和我尝试过的-
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; }
}
DatabaseContext.cs
:
public class DatabaseContext : DbContext
{
public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
{
}
public DbSet<PostModel> Posts { get; set; }
public DbSet<TagModel> Tags { get; set; }
public DbSet<PostTagModel> PostTags { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<PostModel>()
.HasMany(e => e.Tags)
.WithMany(e => e.Posts)
.UsingEntity<PostTagModel>();
}
}
ViewModel
:
public class CreatePostViewModel
{
public string? Title { get; set; }
public int? TagId { get; set; }
public List<TagModel> TagList { get; set; }
}
Controller
:
CS0029: 无法隐式转换类型“int”?到'System.Collections.GenericList
[HttpGet]
public IActionResult Create()
{
// Tags initialization for view
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(CreatePostViewModel postVM)
{
if (ModelState.IsValid)
{
var post = new PostModel
{
Title = postVM.Title,
Tags = postVM.TagId // CS0029 : cannot implicitly convert type 'int?' to 'System.Collections.GenericList<Website.Model.TagModel>
};
_postInterface.Add(post);
return RedirectToAction("Index");
}
else
{
// Error
}
return View(postVM);
}
View
:
@using SimpleWebsite.ViewModels.PostViewModel
@model CreatePostViewModel
<!-- Code above -->
<!-- Tag -->
<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 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 -->
我怀疑您是否可以将
TagId
值传递给控制器,因为复选框需要具有 name
属性:name="TagId"
。
请注意,通过循环,用户可以检查多个复选框,并建议将
TagId
属性更改为 TagIds
类型。int[]?
<label asp-for="TagIds" class="control-label"></label>
<div class="form-check-inline">
@foreach (var item in Model.TagList)
{
<input type="checkbox" class="btn-check" id="@item.Id" value="@item.Id" name="TagIds">
<label asp-for="TagIds" class="btn btn-outline-primary" for="@item.Id">@item.Title</label>
}
</div>
在控制器中,您必须从数据库中检索
public class CreatePostViewModel
{
public string? Title { get; set; }
public int[]? TagIds { get; set; }
public List<TagModel> TagList { get; set; }
}
数据并根据用户选择的
Tag
进行过滤。然后将 TagIds
与 post
一起插入。selectedTags
...
using System.Linq;
private readonly ITagInterface _tagInterface;
public PostController(DatabaseContext context, IPostInterface postInterface, ITagInterface tagInterface)
{
_context = context;
_postInterface = postInterface;
_tagInterface = tagInterface;
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreatePostViewModel postVM)
{
if (ModelState.IsValid)
{
var tags = await _tagInterface.GetAll();
List<TagModel> selectedTags = new List<TagModel>();
if (postVM.TagIds != null && postVM.TagIds.Any())
selectedTags = tags.Where(x => postVM.TagIds.Contains(x.Id))
.ToList();
var post = new PostModel
{
Title = postVM.Title,
Tags = selectedTags
};
_postInterface.Add(post);
return RedirectToAction("Index");
}
else
{
// Error
}
return View(postVM);
}
您需要相应地更新控制器:
public class CreatePostViewModel
{
public string? Title { get; set; }
public List<int> SelectedTagIds { get; set; } = new List<int>(); // To store multiple tag IDs
public List<TagModel> TagList { get; set; }
}
还有景色:
@model CreatePostViewModel
<!-- Other fields -->
<!-- Tag Selection -->
<div class="col-md-12 mb-3">
<label asp-for="SelectedTagIds" class="control-label"></label>
<div class="form-check-inline">
@foreach (var tag in Model.TagList)
{
<input type="checkbox" class="btn-check" name="SelectedTagIds" id="[email protected]" value="@tag.Id">
<label class="btn btn-outline-primary" for="[email protected]">@tag.Title</label>
}
</div>
</div>
<!-- Submit button and other code -->
使用Entity Framework时,更新数据库的方法如下:
打开命令行
@model CreatePostViewModel
<!-- Other fields -->
<!-- Tag Selection -->
<div class="col-md-12 mb-3">
<label asp-for="SelectedTagIds" class="control-label"></label>
<div class="form-check-inline">
@foreach (var tag in Model.TagList)
{
<input type="checkbox" class="btn-check" name="SelectedTagIds" id="[email protected]" value="@tag.Id">
<label class="btn btn-outline-primary" for="[email protected]">@tag.Title</label>
}
</div>
</div>
<!-- Submit button and other code -->
dotnet ef migrations add UpdatePostTagRelationship //or whatever you want to call it
您可以打开笔记本电脑的命令行或在您正在使用的IDE的命令行中执行。