【问题标题】:.Net Core 3.1 Entity Framework: Inserting Simultaneously in One-To-Many Relationship.Net Core 3.1 Entity Framework:在一对多关系中同时插入
【发布时间】:2021-10-04 13:12:34
【问题描述】:

简介:

我正在使用 .Net Core 3.1 构建一个 Web 应用程序,并且有两个模型: 1- InvoiceHeader, 2- InvoiceLine

其中一个 InvoiceHeader 将包含多个 InvoiceLine(即一对多关系)。

问题 我正在尝试创建 InvoiceHeader 并在同一视图中向其添加多个 InvoiceLine。当我使用以下代码启动应用程序时,出现此错误:ArgumentNullException: Value cannot be null。 (参数 'entity') 当我尝试在运行时将数据添加到我的数据库时,从 Create.cshtml.cs 文件中引用 _context.InvoiceLine.Add(InvoiceLine);

目标:在同一页面/表单中同时创建 InvoiceHeader 和 InvoiceLine。 具体来说,我想知道这是如何通过PageModel代码(create.cshtml.cs)处理的。

我的代码:

InvoiceHeader.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;

namespace PRArchivalSystem.Model
{
    public class InvoiceHeader
    {
        public int InvoiceHeaderId { get; set; }
        [Required]
        public string InvoiceNumber { get; set; }
        [Required]
        public DateTime InvoiceDate { get; set; }
        [Required]
        public string InvoiceVendor{get; set;}
        [Required]
        public double InvoiceTotal { get; set; }
        public ICollection<InvoiceLine> InvoiceLines { get; set; }
    }
}

InvoiceLine.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

using System.Linq;
using System.Threading.Tasks;

namespace PRArchivalSystem.Model
{
    public class InvoiceLine
    {
        public int InvoiceLineId { get; set; }
        public string LineDescription { get; set; }
        public double LineAmount { get; set; }
        public double LineQuantity { get; set; }
        public bool LineIsTaxed { get; set; }
        public double LineTax { get; set; }
        public double LineTotal { get; set; }
        public int InvoiceHeaderId { get; set; }
        public InvoiceHeader InvoiceHeader { get; set; }
    }
}

ApplicationDbContext.cs

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace PRArchivalSystem.Model
{
    public class ApplicationDbContext : IdentityDbContext 
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        public DbSet<Order> Order { get; set; }
        public DbSet<Vendor> Vendor { get; set; }
        public DbSet<Department> Department { get; set; }
        public DbSet<InvoiceHeader> InvoiceHeader { get; set; }
        public DbSet<InvoiceLine> InvoiceLine { get; set; }
    }
}

模型页面:Create.cshtml

@page
@model PRArchivalSystem.Pages.InvH.CreateModel

<h4>InvoiceHeader</h4>
<hr />
<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="InvoiceHeader.InvoiceNumber" class="control-label"></label>
                <input asp-for="InvoiceHeader.InvoiceNumber" class="form-control" />
                <span asp-validation-for="InvoiceHeader.InvoiceNumber" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceHeader.InvoiceDate" class="control-label"></label>
                <input asp-for="InvoiceHeader.InvoiceDate" class="form-control" />
                <span asp-validation-for="InvoiceHeader.InvoiceDate" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceHeader.InvoiceVendor" class="control-label"></label>
                <input asp-for="InvoiceHeader.InvoiceVendor" class="form-control" />
                <span asp-validation-for="InvoiceHeader.InvoiceVendor" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceHeader.InvoiceTotal" class="control-label"></label>
                <input asp-for="InvoiceHeader.InvoiceTotal" class="form-control" />
                <span asp-validation-for="InvoiceHeader.InvoiceTotal" class="text-danger"></span>
            </div>
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="InvoiceLine.LineDescription" class="control-label"></label>
                <input asp-for="InvoiceLine.LineDescription" class="form-control" />
                <span asp-validation-for="InvoiceLine.LineDescription" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceLine.LineAmount" class="control-label"></label>
                <input asp-for="InvoiceLine.LineAmount" class="form-control" />
                <span asp-validation-for="InvoiceLine.LineAmount" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceLine.LineQuantity" class="control-label"></label>
                <input asp-for="InvoiceLine.LineQuantity" class="form-control" />
                <span asp-validation-for="InvoiceLine.LineQuantity" class="text-danger"></span>
            </div>
            <div class="form-group form-check">
                <label class="form-check-label">
                    <input class="form-check-input" asp-for="InvoiceLine.LineIsTaxed" /> @Html.DisplayNameFor(model => model.InvoiceLine.LineIsTaxed)
                </label>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceLine.LineTax" class="control-label"></label>
                <input asp-for="InvoiceLine.LineTax" class="form-control" />
                <span asp-validation-for="InvoiceLine.LineTax" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="InvoiceLine.LineTotal" class="control-label"></label>
                <input asp-for="InvoiceLine.LineTotal" class="form-control" />
                <span asp-validation-for="InvoiceLine.LineTotal" class="text-danger"></span>
            </div>

            <div class="form-group">
                <input type="submit" value="Create" class="btn btn-primary" />
            </div>
        </form>
    </div>
</div>

<div>
    <a asp-page="Index">Back to List</a>
</div>

模型控制器:Create.cshtml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Mvc.Rendering;
using PRArchivalSystem.Model;

namespace PRArchivalSystem.Pages.InvH
{
    public class CreateModel : PageModel
    {
        private readonly PRArchivalSystem.Model.ApplicationDbContext _context;

        public CreateModel(PRArchivalSystem.Model.ApplicationDbContext context)
        {
            _context = context;
        }

        public IActionResult OnGet()
        {
            return Page();
        }

        [BindProperty]
        public InvoiceHeader InvoiceHeader { get; set; }
        public InvoiceLine InvoiceLine { get; set; }


        // To protect from overposting attacks, enable the specific properties you want to bind to, for
        // more details, see https://aka.ms/RazorPagesCRUD.
        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }
            
            _context.InvoiceHeader.Add(InvoiceHeader);
            _context.InvoiceLine.Add(InvoiceLine);
            await _context.SaveChangesAsync();

            return RedirectToPage("./Index");
        }
    }
}

任何帮助都将不胜感激,因为我是 C# 和 .Net EF 的新手。

谢谢

【问题讨论】:

  • 您在哪一行得到错误?还有其他错误吗?
  • 提交后运行时出现的错误,指的是Create.cshtml.cs上的以下行:_context.InvoiceLine.Add(InvoiceLine);将更新帖子,谢谢询问
  • InvoiceHeaderInvoiceLine 为空。谁应该初始化这些属性?可能是你的代码。
  • 只有InvoiceHeader 具有[BindProperty] 属性。所以InvoiceLine 将不受 MVC 的约束,将保持为null
  • @SvyatoslavDanyliv 我是否必须显式初始化属性?我的理解是 .cshtml 组件“asp-for”已经在处理这个问题。

标签: c# asp.net-core entity-framework-core insert one-to-many


【解决方案1】:

当我使用以下代码启动应用程序时,我收到此错误:ArgumentNullException: Value cannot be null。 (参数“实体”)

此错误是由InvoiceLine 的空对象值引起的。您需要添加[BindProperty]

此外,您还需要修改下面的后端代码以使插入操作成功:

[BindProperty]
public InvoiceHeader InvoiceHeader { get; set; }
[BindProperty]
public InvoiceLine InvoiceLine { get; set; }

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }
    
    _context.InvoiceHeader.Add(InvoiceHeader);
    //_context.InvoiceLine.Add(InvoiceLine);
    InvoiceHeader.InvoiceLines = new List<InvoiceLine>();
    InvoiceHeader.InvoiceLines.Add(InvoiceLine);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

【讨论】:

  • 经过测试和出色的工作!谢谢。如果我可以更进一步,关于如何在将更改保存到 _context 之前继续添加到列表中的任何建议。再次感谢。
猜你喜欢
  • 2018-06-24
  • 1970-01-01
  • 2020-11-05
  • 1970-01-01
  • 1970-01-01
  • 2020-03-12
  • 1970-01-01
  • 2021-03-16
  • 1970-01-01
相关资源
最近更新 更多