.Net Core 3.1 Entity Framework:在一对多关系中同时插入
.Net Core 3.1 Entity Framework: Inserting Simultaneously in One-To-Many Relationship
简介:
我正在使用 .Net Core 3.1 构建 Web 应用程序并有两个模型:
1- InvoiceHeader,
2- 发票行.
其中 InvoiceHeader 将包含多个 InvoiceLine(即一对多关系)。
问题
我正在尝试创建 InvoiceHeader 并在同一视图中向其添加多个 InvoiceLine。当我使用以下代码启动应用程序时,出现此错误:ArgumentNullException:值不能为空。 (参数 'entity') 当我尝试在 运行 时向我的数据库添加数据时,从 Create.cshtml.cs[= 引用 _context.InvoiceLine.Add(InvoiceLine);
58=] 文件.
目标: 在同一个 Page/Form 中同时创建 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>
模特Controller: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 的新手。
谢谢
When I Launch the app with the below code I get this error: ArgumentNullException: Value cannot be null. (Parameter 'entity')
此错误是由 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");
}
简介:
我正在使用 .Net Core 3.1 构建 Web 应用程序并有两个模型: 1- InvoiceHeader, 2- 发票行.
其中 InvoiceHeader 将包含多个 InvoiceLine(即一对多关系)。
问题
我正在尝试创建 InvoiceHeader 并在同一视图中向其添加多个 InvoiceLine。当我使用以下代码启动应用程序时,出现此错误:ArgumentNullException:值不能为空。 (参数 'entity') 当我尝试在 运行 时向我的数据库添加数据时,从 Create.cshtml.cs[= 引用 _context.InvoiceLine.Add(InvoiceLine);
58=] 文件.
目标: 在同一个 Page/Form 中同时创建 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>
模特Controller: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 的新手。
谢谢
When I Launch the app with the below code I get this error: ArgumentNullException: Value cannot be null. (Parameter 'entity')
此错误是由 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");
}