ef 核心一对多关系抛出异常无法添加或更新子行
ef core one to many relationship throw exception Cannot add or update a child row
我的商店和产品实体是一对多的关系,请看我的模型
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");
}
}
创建页面中的商店是一个下拉列表,当我post向处理程序添加新产品时,我可以看到product.ShopID是商店table中存在的ID , product.Shop.ID 与 product.ShopID 相同。但是当我调用 saveChangesAsync() 时,它抛出异常:
MySqlException: 无法添加或更新子行:外键约束失败 (shopdb
.product
, CONSTRAINT FK_product_shop_ShopID
FOREIGN KEY (ShopID
) REFERENCES shop
(ID
) 删除级联)
我尝试在调用 saveChangesAsync 方法之前将 product.Shop 设置为 null,但仍然无效,有人可以帮忙吗?
ASP.NET Core 2.0 Razor Pages 应用程序,
Nuget: Pomelo.EntityFrameworkCore.MySql v2.0.1
在 Product
table 中声明 ShopID
可以为空,你正在做 product.Shop = null;
,因此它会尝试插入 ShopID
值 null
在本专栏中。由于 Product
table 中的 ShopID
列不可为空,这就是它给出错误的原因。因为 Shop
table 中没有可空的 Id
。所以它给出了 foreign key constraint fails 异常。因此,您所要做的就是使用可为空的外键,例如 public int? ShopID
.
如果设计需要,您不应该让 ShopID
可以为空。
您遇到的问题是因为 Add
方法还递归地将所有实体实例标记为可通过导航属性访问并且当前未被上下文跟踪为 Added
(即新的)。
可以通过多种方式解决:
将实体条目设置为 Added
而不是 Add
方法:
_context.Entry(Product).State = EntityState.Added;
await _context.SaveChangesAsync();
设置导航 属性 到 null
before calling 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();
最后一个技术在Saving Data - Disconnected Entities - Mix of new and existing entities中有解释:
With auto-generated keys, Update can again be used for both inserts and updates, even if the graph contains a mix of entities that require inserting and those that require updating
由于它仅在所有实体都使用自动生成的 PK 时才有效,并且还会对相关实体产生不必要的更新,因此我不推荐它。
我的商店和产品实体是一对多的关系,请看我的模型
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");
}
}
创建页面中的商店是一个下拉列表,当我post向处理程序添加新产品时,我可以看到product.ShopID是商店table中存在的ID , product.Shop.ID 与 product.ShopID 相同。但是当我调用 saveChangesAsync() 时,它抛出异常:
MySqlException: 无法添加或更新子行:外键约束失败 (shopdb
.product
, CONSTRAINT FK_product_shop_ShopID
FOREIGN KEY (ShopID
) REFERENCES shop
(ID
) 删除级联)
我尝试在调用 saveChangesAsync 方法之前将 product.Shop 设置为 null,但仍然无效,有人可以帮忙吗?
ASP.NET Core 2.0 Razor Pages 应用程序, Nuget: Pomelo.EntityFrameworkCore.MySql v2.0.1
在 Product
table 中声明 ShopID
可以为空,你正在做 product.Shop = null;
,因此它会尝试插入 ShopID
值 null
在本专栏中。由于 Product
table 中的 ShopID
列不可为空,这就是它给出错误的原因。因为 Shop
table 中没有可空的 Id
。所以它给出了 foreign key constraint fails 异常。因此,您所要做的就是使用可为空的外键,例如 public int? ShopID
.
如果设计需要,您不应该让 ShopID
可以为空。
您遇到的问题是因为 Add
方法还递归地将所有实体实例标记为可通过导航属性访问并且当前未被上下文跟踪为 Added
(即新的)。
可以通过多种方式解决:
将实体条目设置为
Added
而不是Add
方法:_context.Entry(Product).State = EntityState.Added; await _context.SaveChangesAsync();
设置导航 属性 到
null
before callingAdd
: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();
最后一个技术在Saving Data - Disconnected Entities - Mix of new and existing entities中有解释:
With auto-generated keys, Update can again be used for both inserts and updates, even if the graph contains a mix of entities that require inserting and those that require updating
由于它仅在所有实体都使用自动生成的 PK 时才有效,并且还会对相关实体产生不必要的更新,因此我不推荐它。