[英]Why can I not submit a form with a navigation property with Entity Framework?
我正在学习 C#,我的第一个项目围绕导航属性遇到了很多问题。 我遇到的主要障碍是基本的四个属性 model (以及包括导航属性的任何内容)。
这是我目前正在使用的一个:
公司 Model:
public class Company
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Display(Name = "Id")]
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
public CompanyType Type { get; set; }
public ICollection<Contact>? Contacts { get; set; }
}
公司类型 Model:
public class CompanyType
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Display(Name = "Id")]
public int Id { get; set; }
[Display(Name = "Company Type")]
public string Type { get; set; } = "";
}
这是我的背景——很简单。
public class SRMContext : DbContext
{
public DbSet<Company> Companies { get; set; }
public DbSet<Contact> Contacts { get; set; }
public DbSet<CompanyType> CompanyTypes { get; set; }
public SRMContext (DbContextOptions<SRMContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Company>().ToTable("Companies");
modelBuilder.Entity<Contact>().ToTable("Contacts");
modelBuilder.Entity<CompanyType>().ToTable("CompanyTypes");
}
}
*我在上下文中删除了不相关的模型。
我首先使用脚手架为公司创建 CRUD razor 页面。 它根本不包含任何导航属性 - 对于任何 model。 不确定我是否做错了什么,或者这是否是标准的。 所以我试图手动更新脚手架页面以包含 CompanyType。 我能够生成一个 select 列表,并将其提供给 UI。 它给了我选项,我点击提交。 但是当我点击提交时,它说我需要包括公司类型。 如果我将其更改为不需要,它将提交,但不会列出任何公司类型。
我知道你可以只做 Id 而不做导航属性,但在我的代码中,我有多对多的导航属性,所以 Id 对它们不起作用。 我也遇到了同样的问题,但是在我弄清楚之前,这个问题要简单得多。
我究竟做错了什么?
public class CreateModel : PageModel
{
private readonly SRMContext _context;
public SelectList CompanyTypes { get; set; }
public CreateModel(SRMContext context)
{
_context = context;
}
public async Task<IActionResult> OnGetAsync()
{
CompanyTypes = new SelectList(_context.CompanyTypes, nameof(CompanyType.Id), nameof(CompanyType.Type));
return Page();
}
[BindProperty]
public Company Company { get; set; }
// To protect from overposting attacks, see https://aka.ms/RazorPagesCRUD
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Companies.Add(Company);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
查看页面
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Company.Name" class="control-label"></label>
<input asp-for="Company.Name" class="form-control" />
<span asp-validation-for="Company.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Company.Type" class="control-label"></label>
<select asp-for="Company.Type" asp-items="Model.CompanyTypes" class="form-control"></select>
<span asp-validation-for="Company.Type" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
(对不起,我知道它有很多代码,但我想展示所有需要的东西!)
表单帖子上无法识别复杂对象,因此类型可能是 null。 相反,发布该类型的外键,它应该被识别:
public class Company
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
[Display(Name = "Id")]
public int Id { get; set; }
[Display(Name = "Name")]
public string Name { get; set; }
public int CompanyType_Id { get; set; }
[ForeignKey("CompanyType_Id")]
public CompanyType Type { get; set; }
public ICollection<Contact>? Contacts { get; set; }
}
并以您的形式:
<select asp-for="Company.CompanyType_Id" asp-items="Model.CompanyTypes" class="form-control"></select>
没有测试过这个,但很确定这是问题所在。
请参阅我对这个问题的回答(将复杂实体内的复杂实体绑定到请求),以了解当您将实体发送到视图以充当其 Model 以及尝试发送该 model 时可能遇到的问题和风险时发生的情况的解释背部。
我给出的一般建议是不要将实体发送到视图,因为当服务器上的视图引擎获取实体时,从客户端浏览器返回的仍然不是实体,它只是被转换为实体的数据字段,所以它们要么不完整,要么容易被篡改。 (加上通常涉及通过网络发送比需要更多的数据)
您的 Create PageModel 是一个好的开始,但考虑只嵌入来自客户而不是客户实体的字段(更新/编辑也是如此)这将包括一个 CustomerTypeId 列,当您在 POST 调用中构建您的客户实体时,您获取来自 DbContext 的 CustomerType 引用并将其分配给新创建的客户。 这样做的好处是还可以验证您从客户端浏览器收到的任何 FK,以确保您处理的是合法数据,在比最终的SaveChanges
调用更有用的调试位置抛出异常。 想要传递实体的典型理由是避免额外的 DB 读取命中。 通过 ID 读取这样的相关实体非常快,甚至在您可能需要加载多个相关实体的情况下,也有一些技术可以将它们批处理到单个读取操作中。 (选择所有需要的 ID,使用Contains
一次性读取,然后从该集合中分配)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.