ASP.NET结账保存数据库触发INSERT外键约束fk_Transaction_ctmID报错如何解决
问题原因
该报错为外键约束冲突,本质是插入Transaction表的ctmID值,在User_Customer表的ctmID列中不存在,违反了你定义的外键关联规则。
代码核心错误
看你的Checkout接口代码,存在两处致命问题:
- 你新建了
User_Customer ctm = new User_Customer();对象后,既没有给这个对象填写任何必填字段,也没有将它写入数据库,直接就取ctm.ctmID赋值给Transaction的ctmID。 User_Customer的ctmID是自增主键,只有写入数据库后才会生成有效值,你刚new出来的对象ctmID默认是0,你的User_Customer表里不可能存在ctmID为0的记录,所以触发外键冲突。
解决方案
根据你的业务场景二选一即可:
场景1:结账用户是已登录的已有用户
不需要新建用户,直接从当前登录状态获取对应用户的ctmID即可:
public ActionResult Checkout(string contact, string address) { if (ModelState.IsValid) { // 从登录态取当前用户的ID,ASP.NET Identity 可用如下方法 var currentUserId = User.Identity.GetUserId(); // 到User_Customer表查对应的用户记录 var currentCustomer = db.User_Customer.FirstOrDefault(u => u.userId == currentUserId); if (currentCustomer == null) { // 找不到对应用户的逻辑,比如跳转到注册/登录页 return RedirectToAction("Login", "Account"); } List<Cart> li2 = TempData["cart"] as List<Cart>; Transaction iv = new Transaction(); // 直接用已有用户的ctmID iv.ctmID = currentCustomer.ctmID; iv.invoice_date = System.DateTime.Now; iv.invoice_bill = (int)TempData["total"]; iv.invoice_payment = "cash"; db.Transactions.Add(iv); db.SaveChanges(); // 后续订单逻辑不变 foreach (var item in li2) { Order od = new Order(); od.productID = item.productID; od.ctm_email = contact; od.ctm_address = address; od.order_day = System.DateTime.Now; od.transID = iv.transID; od.order_qty = item.cart_qty; od.order_unit = item.cart_price; od.order_payment = item.cart_bill; db.Orders.Add(od); db.SaveChanges(); } TempData.Remove("total"); TempData.Remove("cart"); return RedirectToAction("Index"); } TempData.Keep(); return View(); }
场景2:结账时需要新建用户
先填全新用户的所有必填字段,写入数据库拿到生成的ctmID后,再创建Transaction记录:
public ActionResult Checkout(string contact, string address, string firstName, string lastName, string gender, string cardType) { if (ModelState.IsValid) { List<Cart> li2 = TempData["cart"] as List<Cart>; // 新建用户,填写所有必填字段(示例参数从表单提交获取,你需要在视图里加对应输入框) User_Customer ctm = new User_Customer(); ctm.userId = User.Identity.GetUserId(); // 关联AspNetUsers表的用户ID ctm.ctm_firstname = firstName; ctm.ctm_lastname = lastName; ctm.ctm_gender = gender; ctm.ctm_cardtype = cardType; ctm.ctm_email = contact; ctm.ctm_address = address; // 先把用户写入数据库,此时会自动生成自增的ctmID db.User_Customer.Add(ctm); db.SaveChanges(); Transaction iv = new Transaction(); // 用刚生成的用户ID iv.ctmID = ctm.ctmID; iv.invoice_date = System.DateTime.Now; iv.invoice_bill = (int)TempData["total"]; iv.invoice_payment = "cash"; db.Transactions.Add(iv); db.SaveChanges(); // 后续订单逻辑不变 foreach (var item in li2) { Order od = new Order(); od.productID = item.productID; od.ctm_email = contact; od.ctm_address = address; od.order_day = System.DateTime.Now; od.transID = iv.transID; od.order_qty = item.cart_qty; od.order_unit = item.cart_price; od.order_payment = item.cart_bill; db.Orders.Add(od); db.SaveChanges(); } TempData.Remove("total"); TempData.Remove("cart"); return RedirectToAction("Index"); } TempData.Keep(); return View(); }
额外注意事项
- 你的
Transaction表定义中ctmID是允许为空的,但实体类里ctmID是int非空类型,二者不匹配。如果允许无用户的交易,需要把实体类的ctmID改成int?类型。 - 当前你的Checkout视图里没有
contact、address以及新建用户所需的必填字段输入框,需要补充到表单里,否则提交时这些参数都会为空,触发字段非空验证报错。
内容的提问来源于stack exchange,提问作者Khánh Nguyễn
相关产品推荐
相关产品推荐

