【问题标题】:Why I get this kind of error The UPDATE statement conflicted with the FOREIGN KEY constraint为什么会出现这种错误 UPDATE 语句与 FOREIGN KEY 约束冲突
【发布时间】:2021-06-21 04:52:39
【问题描述】:

我正在尝试更新表格中的一列,当我按下更新按钮时出现错误

The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_Tickets_AspNetUsers_UserId". The conflict occurred in database "CarPlatzz", table "dbo.AspNetUsers", column 'Id'. The statement has been terminated.

在我的模型中,我有类似的东西

public class Ticket
    {
        [Key]
        public int Id { get; set; }

        [Display(Name = "Opis")]
        public string Description { get; set; }

        [Display(Name = "Datum i vrijeme slanja")]
        public string DateAndTime { get; set; } = DateTime.Now.ToString("dd/MM/yyyy HH:mm");

        [Display(Name = "Datum i vrijeme zavrsetka")]
        public DateTime Answered { get; set; }

        [Display(Name = "Vrsta tiketa")]
        public int TicketTypeID { get; set; }

        [ForeignKey("TicketTypeID")]
        public virtual TicketType TicketType { get; set; }

        public int UserId { get; set; }

        [ForeignKey("UserId")]
        public virtual ApplicationUser ApplicationUser { get; set; }

        public int? ClientId { get; set; }
        [ForeignKey("ClientId")]
        public virtual Client Client { get; set; }

        public string Status { get; set; } = TicketStatus.Otvoren.ToString();


    }

这是我在控制器中的操作

 public IActionResult Upsert(TicketVM ticketVM)
        {
            var userName = User.FindFirstValue(ClaimTypes.Email);
            var user = HttpContext.User.Identity.Name;

            if (ModelState.IsValid)
            {
                if (ticketVM.Ticket.Id == 0)
                {
                    ticketVM.Ticket.ApplicationUser = _db.ApplicationUsers.FirstOrDefault(u => u.Email == userName);
                    ticketVM.Ticket.Status = TicketStatus.Otvoren.ToString();
                    _unitOfwork.Ticket.Add(ticketVM.Ticket);
                }
                else
                {
                    ticketVM.Ticket.Status = ((TicketStatus)Convert.ToInt32(ticketVM.Ticket.Status)).ToString();
                    _unitOfwork.Ticket.Update(ticketVM.Ticket);
                    
                }
                _unitOfwork.Save();
                return RedirectToAction(nameof(Index));
            }
            return View(ticketVM);
        }

我在这里查看了几篇帖子,但没有任何帮助。 所以我改变了

public int UserId {get;set;} 

public int? UserId {get;set;}

但这里的问题是,在 NULL 中更新列 UserId 后,这对我来说不是解决方案。 所以问题出在我在 ELSE block 中的 Upsert 方法中

else
                {
                    ticketVM.Ticket.Status = ((TicketStatus)Convert.ToInt32(ticketVM.Ticket.Status)).ToString();
                    _unitOfwork.Ticket.Update(ticketVM.Ticket);
                    
                }

ApplicationUser.cs

public class ApplicationUser : IdentityUser<int>
    {
        
        [Required]
        [Display(Name = "Ime")]
        public string Name { get; set; }

        [Required]
        [Display(Name = "Adresa")]
        public string StreetAddress { get; set; }

        [Required]
        [Display(Name = "Grad")]
        public string City { get; set; }

        [Required]
        [Display(Name = "Postanski broj")]
        public string PostalCode { get; set; }

        public int? ClientId { get; set; }
        [ForeignKey("ClientId")]
        public Client Client { get; set; }

        [NotMapped]
        public string Role { get; set; }      

        [NotMapped]
        public IEnumerable<SelectListItem> RoleList { get; set; }

        [NotMapped]
        public IEnumerable<SelectListItem> ClientList { get; set; }
    }

参考在这里

LINK 1

LINK 2

LINK 3

LINK 4

【问题讨论】:

    标签: c# entity-framework asp.net-core-mvc


    【解决方案1】:

    我可以看到您的方法存在一些严重问题。引发警报的罪魁祸首是:

    ticketVM.Ticket.ApplicationUser = _db.ApplicationUsers.FirstOrDefault(u => u.Email == userName);
    

    接着是:

    _unitOfwork.Ticket.Add(ticketVM.Ticket);
    

    你为什么要使用_unitOfWork,然后去一些_db 引用,它看起来像一个直接的DbContext。工作单元包装了一个 DbContext 实例,因此 所有 实体应从该单个 DbContext 解析。我希望看到类似的东西:

    ticketVM.Ticket.ApplicationUser = _unitOfWork.ApplicationUsers.Single(u => u.Email == userName);
    

    如果 ApplicationUser 是从与 Ticket 被持久化到的不同的 DbContext 实例中提取的,则第二个 DbContext 将不会跟踪该实例,并可能导致尝试插入重复的 User。

    根据方法的插入或更新性质,您可能希望 ApplicationUser 引用的设置仅发生在插入场景中,以便用户引用不会在更新时更改,除非这是应该发生的情况.

    第二个警告标志是使用FirstOrDefault。此方法确实需要在 Linq 中进行限制,以使其在没有 OrderBy 的情况下无法运行,例如 SkipTake 方法。如果您希望返回记录,最好使用Single,如果找不到预期的匹配行,它将引发异常。使用FirstOrDefault,如果电子邮件匹配没有对齐,您可能会得到一个空引用,并且会尝试从工单中删除用户引用。

    下一个建议是避免混合实体和视图模型。实体代表数据状态。视图模型代表视图状态。将实体序列化到视图模型中意味着发送比视图实际需要的更多的数据,并且当序列化程序开始“接触”导航属性以触发延迟加载时,可能会导致性能问题。将视图模型保留为 POCO,并将所需的实体值投影到视图模型属性中。序列化身份用户及其可能的相关详细信息几乎肯定是您不希望通过线路发送到 Web 客户端的内容。

    语句如下:

    _unitOfwork.Ticket.Update(ticketVM.Ticket);
    

    是系统内数据篡改的高风险。虽然您的 UI 可能只显示用户可能修改的一些预期字段,但使用此方法时,整个实体都可以修改。更新数据时,从数据状态加载实体并从视图模型中复制经过验证的详细信息,然后保存实体。

    【讨论】:

    • 感谢您的发帖和回答。现在,我在ticketVM.Ticket.ApplicationUser = _unitOfWork.ApplicationUsers.Single(u =&gt; u.Email == userName); 中遇到错误,因为我的UnitOfWork 中没有实现 Single
    • 这将取决于您的工作单元实施,因为它似乎暴露了 DbSet 或类似的东西。 (即_unitOfWork.Ticket)工作单元的目的应该是提供访问 DbContext 的范围,而不是从代码中抽象出 DbContext。理想情况下,UoW 应该能够提供对 DbContext 的访问并启用 DbContext 可以提供的所有 Linq 功能。
    【解决方案2】:

    错误消息是不言自明的。您的应用程序似乎尝试更新表中的一行,而引用的表中不存在该值,这破坏了引用完整性并导致错误。

    【讨论】:

    • 好的,我明白了。但是如何解决这个问题呢?
    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 2014-07-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多