c# - ef核心一对多关系抛出异常无法添加或更新子行
问题描述
My Shop 和 Product 实体有一对多的关系,请查看我的模型
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
public string Tag { get; set; }
public string Brand { get; set; }
public string Place { get; set; }
public int ShopID { get; set; }
public Shop Shop { get; set; }
}
public class Shop
{
public int ID { get; set; }
public string Name { get; set; }
public string Comment { get; set; }
public string Number { get; set; }
public ICollection<Product> Products { get; set; }
}
public class ShopContext : DbContext
{
public ShopContext(DbContextOptions<ShopContext> options) : base(options)
{
}
public DbSet<Shop> Shops { get; set; }
public DbSet<Product> Products { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Shop>().ToTable("shop");
modelBuilder.Entity<Product>().ToTable("product");
}
}
public class CreateModel : PageModel
{
private readonly ShopContext _context;
public CreateModel(ShopContext context)
{
_context = context;
}
public IActionResult OnGet()
{
ViewData["Shop"] = new SelectList(_context.Shops, "ID", "Name");
return Page();
}
[BindProperty]
public Product Product { get; set; }
public async Task<IActionResult> OnPostAsync()
{
if (!ModelState.IsValid)
{
return Page();
}
_context.Products.Add(Product);
await _context.SaveChangesAsync();
return RedirectToPage("./Index");
}
}
创建页面中的shop是一个下拉列表,当我将新产品发布到handler时,我可以看到product.ShopID是存在于Shop表中的ID,product.Shop.ID与product.ShopID相同. 但是当我调用 saveChangesAsync() 时,它会抛出一个异常:
MySqlException:无法添加或更新子行:外键约束失败(shopdb
. product
, CONSTRAINT FK_product_shop_ShopID
FOREIGN KEY ( ShopID
) REFERENCES shop
( ID
) ON DELETE CASCADE)
我尝试在调用 saveChangesAsync 方法之前将 product.Shop 设置为 null,但仍然无法正常工作,有人可以帮忙吗?
ASP.NET Core 2.0 Razor Pages 应用程序,Nuget:Pomelo.EntityFrameworkCore.MySql v2.0.1
解决方案
如果设计要求,您不应该将ShopID
其设为可空。
您遇到的问题是因为Add
方法还递归地将所有实体实例标记为可通过导航属性访问,并且当前未被上下文跟踪为Added
(即新的)。
可以通过多种方式解决:
将实体条目设置为
Added
而不是Add
方法:_context.Entry(Product).State = EntityState.Added; await _context.SaveChangesAsync();
在调用
null
之前将导航属性设置为Add
:Product.Shop = null; _context.Products.Add(Product); await _context.SaveChangesAsync();
在调用之前附加导航属性对象
Add
:if (Product.Shop != null) _context.Attach(Product.Shop); _context.Products.Add(Product); await _context.SaveChangesAsync();
使用
Update
而不是Add
:_context.Products.Update(Product); await _context.SaveChangesAsync();
最后一种技术在保存数据 - 断开连接的实体 - 新实体和现有实体的混合中进行了解释:
使用自动生成的键,Update 可以再次用于插入和更新,即使图形包含需要插入和需要更新的实体的混合
由于它仅在所有实体都使用自动生成的 PK 时才有效,并且还会对相关实体产生不必要的更新,因此我不推荐它。
推荐阅读
- java - ORA-28040: 没有匹配的身份验证协议 Oracle
- javascript - 如何连接对象中的变量名
- python - 如何导入python模块一次然后在python脚本中持续使用模块
- .net - .Net Core Dependency Injection - 在子范围内替换依赖项
- c++ - win32 c++ 我想在 STATIC 标签的 TEXT 之后直接插入一个 EDIT 控件
- c++ - 将 CMake 和 vc142 与 boost 一起使用时出现链接错误 LNK1104
- vue.js - 修复 Vue 中的表格宽度,并在文本超出时添加工具提示
- c# - 如何使用 xaml 将内容动态添加到 wpf 应用程序中的富文本框
- python - 从数据框中删除异常值和周围数据
- c# - app.config 中的修改在执行项目时没有反映