简体   繁体   English

为什么我不能使用 Entity Framework 提交带有导航属性的表单?

[英]Why can I not submit a form with a navigation property with Entity Framework?

I am learning C# and I have been running into a lot of issues with my first project around navigation properties.我正在学习 C#,我的第一个项目围绕导航属性遇到了很多问题。 The main hurdle I am having an issue with is a basic four property model (and anything that includes a navigation property).我遇到的主要障碍是基本的四个属性 model (以及包括导航属性的任何内容)。

Here is the one I am currently working with:这是我目前正在使用的一个:

Company 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; }
}

Company Type Model:公司类型 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; } = "";
}

And here is my context - just simple.这是我的背景——很简单。

    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");
        }

    }

*I removed irrelevant models in the context. *我在上下文中删除了不相关的模型。

I first used scaffolding to create the CRUD razor pages for Company.我首先使用脚手架为公司创建 CRUD razor 页面。 It would not include any navigation properties in it at all - for any model.它根本不包含任何导航属性 - 对于任何 model。 Not sure if I am doing something wrong, or if this is standard.不确定我是否做错了什么,或者这是否是标准的。 So I am trying to manually update the scaffolded pages to include CompanyType.所以我试图手动更新脚手架页面以包含 CompanyType。 I was able to generate a select list, and provide that to the UI.我能够生成一个 select 列表,并将其提供给 UI。 It gives me the options and I click submit.它给了我选项,我点击提交。 But when I click submit, it says I need to include the Company Type.但是当我点击提交时,它说我需要包括公司类型。 If I change it to not required, it will submit, but there will be no company type listed.如果我将其更改为不需要,它将提交,但不会列出任何公司类型。

I know you can just do the Id without doing the navigation property, but further in my code, I have many-to-many navigation properties, so the Id will not work for them.我知道你可以只做 Id 而不做导航属性,但在我的代码中,我有多对多的导航属性,所以 Id 对它们不起作用。 I am having the same issues with them too, but this one is much simpler to work with until I get this figured out.我也遇到了同样的问题,但是在我弄清楚之前,这个问题要简单得多。

What am I doing wrong?我究竟做错了什么?

在此处输入图像描述

在此处输入图像描述

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");
    }
}

View Page查看页面

<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>

(I'm sorry, I know its a lot of code, but I want to show everything needed!) (对不起,我知道它有很多代码,但我想展示所有需要的东西!)

Complex objects are not recognized on a form post, so the type is probably null.表单帖子上无法识别复杂对象,因此类型可能是 null。 Instead, post the foreign key of the type and it should be recognized:相反,发布该类型的外键,它应该被识别:

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; }
}

And in your form:并以您的形式:

<select asp-for="Company.CompanyType_Id" asp-items="Model.CompanyTypes" class="form-control"></select>

Haven't tested this, but pretty sure this is the issue.没有测试过这个,但很确定这是问题所在。

See my answer to this question ( Binding Complex Entities inside complex Entities to Requests ) for an explanation of what is happening when you send an entity to a View to serve as it's Model and the issues & risks you can encounter when trying to send that model back.请参阅我对这个问题的回答(将复杂实体内的复杂实体绑定到请求),以了解当您将实体发送到视图以充当其 Model 以及尝试发送该 model 时可能遇到的问题和风险时发生的情况的解释背部。

The general advice I give is to not send entities to the view because while the view engine on the server gets the entity, what comes back from the client browser is not still an entity, it is just data fields that get cast as an entity so they are either incomplete or prone to tampering.我给出的一般建议是不要将实体发送到视图,因为当服务器上的视图引擎获取实体时,从客户端浏览器返回的仍然不是实体,它只是被转换为实体的数据字段,所以它们要么不完整,要么容易被篡改。 (plus generally involve sending far more data over the wire than is needed) (加上通常涉及通过网络发送比需要更多的数据)

Your Create PageModel is a good start, but consider just embedding the fields from a Customer rather than a Customer entity (Same goes for Update/Edit) This would include a CustomerTypeId column that when you build your Customer entity within the POST call, you fetch the CustomerType reference from the DbContext and assign that to the newly created Customer.您的 Create PageModel 是一个好的开始,但考虑只嵌入来自客户而不是客户实体的字段(更新/编辑也是如此)这将包括一个 CustomerTypeId 列,当您在 POST 调用中构建您的客户实体时,您获取来自 DbContext 的 CustomerType 引用并将其分配给新创建的客户。 This has the benefit of also validating whatever FKs you receive from the client browser to ensure you are dealing with legal data, throwing an exception in a more useful spot for debugging than the final SaveChanges call.这样做的好处是还可以验证您从客户端浏览器收到的任何 FK,以确保您处理的是合法数据,在比最终的SaveChanges调用更有用的调试位置抛出异常。 The typical rationale for wanting to pass entities around is to avoid additional DB Read hits.想要传递实体的典型理由是避免额外的 DB 读取命中。 Reading related entities like this by ID is extremely fast, and even cases where you might need to load several related entities there are techniques to batch these up into a single read operation.通过 ID 读取这样的相关实体非常快,甚至在您可能需要加载多个相关实体的情况下,也有一些技术可以将它们批处理到单个读取操作中。 (Select all IDs needed, read in a single hit using a Contains , then assign from that set) (选择所有需要的 ID,使用Contains一次性读取,然后从该集合中分配)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 无法在实体框架中获取导航属性 - Can't fetch Navigation Property in Entity Framework 实体框架导航属性 - Entity Framework navigation property 当我从导航属性集合中删除实体时,为什么实体框架没有删除该实体? - Why Entity Framework does't Delete the entity when I remove it from navigation property collection? 为什么在使用实体框架时看不到本地属性? - Why can I not see the property Local when using Entity Framework? 实体框架如何通过导航属性的属性过滤我的结果? - Entity Framework How can I filter my results by a property of a navigation property? 在实体框架中将表单导航属性迁移到外键 - Migrating form Navigation Property to Foreign Key in Entity Framework 我可以使用Entity Framework 4使用“ .include”加载层次结构数据并根据某些条件过滤导航属性吗? - Can I load hierarchical data with Entity Framework 4 using “.Include” and filter a Navigation Property based on some criteria 在 Entity Framework 6 中,如何使用另一侧的导航属性创建一对多映射? - In Entity Framework 6 how can I create a one to many mapping with a navigation property on the other side? 实体框架导航属性不起作用 - Entity Framework Navigation property not working 实体框架导航属性加载 - Entity framework navigation property loading
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM