当我离开实体框架来自动管理我的映射时,我似乎无法更新我的桥接表。
课程:
public class Tool
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public List<TargetType> TargetTypes { get; } = [];
}
public class TargetType
{
public Guid Id { get; set; }
public string Name { get; set; } = string.Empty;
public List<Tool> Tools { get; } = [];
}
当我进入“编辑/工具”页面时,我希望能够更改与工具关联的
TargetTypes
。
代码在调试时似乎工作正常 - 我在视图中加载所有目标类型,用户可以选择它们,然后按保存按钮。但是,桥接表中没有添加任何内容。实体框架表示它会在本文中自动处理所有这些,因此我真的不想创建自定义类。
为什么我的数据库中的桥接表没有更新?
特性:
[BindProperty]
public Tool Tool { get; set; }
[BindProperty]
public List<Target> Targets { get; set; } = new List<Target>();
[BindProperty]
public List<Guid> SelectedTargetTypes { get; set; } = new List<Guid>();
[BindProperty]
public List<SelectListItem> TargetTypesList { get; set; } = new List<SelectListItem>();
OnPost
方法:
public async Task<IActionResult> OnPostAsync()
{
// we want to update the tool options here
if (!ModelState.IsValid)
{
return Page();
}
// Handle the target types
foreach (var type in SelectedTargetTypes)
{
var target = await _context.TargetTypes.FindAsync(type);
if (target != null)
{
Tool.TargetTypes.Add(target);
}
}
_context.Attach(Tool).State = EntityState.Modified;
try
{
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ToolExists(Tool.Id))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToPage("./Index");
}
.cshtml
我的观点:
<div class="container">
<form method="post">
<h3>Tool Settings</h3>
<hr />
<div class="container">
<div class="form-group col-md-6">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Tool.Id" />
<label asp-for="Tool.Name" class="control-label"></label>
<input asp-for="Tool.Name" class="form-control" />
<span asp-validation-for="Tool.Name" class="text-danger"></span>
</div>
<div class="form-group col-md-6">
<label asp-for="Tool.Description" class="control-label"></label>
<input asp-for="Tool.Description" class="form-control" />
<span asp-validation-for="Tool.Description" class="text-danger"></span>
<label asp-for="Tool.ToolType" class="control-label"></label>
<select id="ToolTypeSelect" class="form-control" asp-items="Html.GetEnumSelectList<AttackSurfaceReview.ASRData.Model.ToolType>()"></select>
<span asp-validation-for="Tool.ToolType" class="text-danger"></span>
</div>
<div class="form-group" style="margin-bottom: 10px;">
<div class="col-md-12">
<label asp-for="Tool.ImageUrl" class="control-label"></label>
<input asp-for="Tool.ImageUrl" class="form-control" />
<span asp-validation-for="Tool.ImageUrl" class="text-danger"></span>
</div>
</div>
<label class="control-label">Allowed Targets</label>
@foreach (var targetType in Model.TargetTypesList)
{
<div class="form-check form-switch">
<input name="SelectedTargetTypes" class="form-check-input" type="checkbox" value="@targetType.Value" />
<label class="form-check-label">@targetType.Text</label>
</div>
}
<div class="form-group">
<input style="margin-bottom: 10px;" type="submit" value="Save" class="btn col-md-4 btn-primary" />
</div>
</div>
</form>
</div>
其实这和EF core如何处理关系实体有关。
默认情况下,
var target = await _context.TargetTypes.FindAsync(type);
它不会跟踪关系实体工具。
如果还想更新该工具,您应该从上下文已跟踪的实体的导航属性中引用新实体,然后该实体将被发现并插入到数据库中。
更多详情,可以参考以下代码:
var target = await _context.TargetTypes.Include(b => b.Tools).FindAsync(type);
if (target != null)
{
Tool.TargetTypes.Add(target);
}
这与在添加 TargetTypes 之前放置
_context.Attach(Tool).State = EntityState.Modified;
相同。