Entity Framework "lost" 错误后的行,仍然可以导航到行详细信息

Entity Framework "lost" a row after an error, can still navigate to row details

我在工作中处理的一个应用程序有一个有趣的错误,我们无法找到它,而且我在搜索中也找不到任何类似的东西。

我的公司建立了一个帮助台系统来跟踪用户问题,在提交错误后,工单从所有工单列表中“消失”了。它在数据库中仍然可见,并没有在任何地方被过滤掉。可以通过将 URL 更改为工单 ID 来导航到工单,所有详细信息都与保存错误之前相同。

我们最终通过重启网络应用解决了这个问题,但我们想找出该行从列表中消失的原因。

我继承了这个应用程序,它有很多我们已经知道的问题,所以我倾向于需要从头开始重建的整个事情,以使保存方法完全异步而不是我们目前得到的一半。

不太确定 post 的代码在绝大多数情况下都能正常工作,但显然其中有些地方不对。

编辑添加:这是来自控制器的编辑post方法

        [HttpPost]
    public async Task<ActionResult> Edit(EditTicketViewModel ticket)
    {
        try
        {
            var tech = (ticket.Technician_ID != null) ? this.UserService.Get(ticket.Technician_ID) : this.UserService.Get(this.User.Identity.GetUserId());
            var cust = this.UserService.Get(ticket.Customer_ID);
            var ogticket = this.TicketService.Get(ticket.Id);
            var dateEdited = DateTime.UtcNow;
            var productVersionId = OrganisationService.GetOrgProduct(ticket.OrgId, true).First(x => x.ProductID == ticket.ProductID).Product_Version.Id; ;

            await this.TicketService.Edit(ticket.Id, ticket.Title, ticket.Description, dateEdited, ticket.Date_Closed, ticket.Customer_ID, ticket.State_Code, ticket.Priority_Code, ticket.Technician_ID, ticket.ProductID, productVersionId, ticket.Ticket_Type_ID);

            if (ticket.State_Code == (int)StateCode.Closed)
            {
                await this.IntegrationService.SendEmailAsync(new EmailProperties()
                {
                    Email = cust.Email,
                    Subject = "Ticket Closed",
                    Body = "Your ticket '{ticket.Title}' has now been closed.\n\n"//+
                    //$"Log into the portal to view it now -> <a href='https://helpdesk.rubixx.co.uk/Ticket/Details/{ticket.Id}'>Ticket {ticket.Id}</a>"
                });
                await this.IntegrationService.PrepareTeamsMessageAsync(new MessageProperties()
                {
                    Summary = $"{this.UserService.Get(this.User).FullName} has closed a ticket",
                    Ticket_Id = ticket.Id,
                    Note_Id = null,
                    Type = TeamsMessageType.Closed
                });
            }
            else await this.IntegrationService.PrepareTeamsMessageAsync(new MessageProperties()
            {
                Summary = $"{this.UserService.Get(this.User).FullName} has updated a ticket",
                Ticket_Id = ticket.Id,
                Note_Id = null,
                Type = TeamsMessageType.Updated
            });

            this.TicketService.CreateTimelineEvent(ticket.Id, this.User.Identity.GetUserId(), DateTime.UtcNow.ToLocalTime(), "", TimelineEventType.TicketEdited);

            this.AddToastMessage("Success", "Edited Successfully", ToastType.Success);
            return Redirect(ticket.ReturnUrl);
        }
        catch (Exception ex)
        {
            this.IntegrationService.LogMessage($"Exception occurred: {ex.Message}");
            this.AddToastMessage("Error: ", "An internal error has occurred", ToastType.Error);
            return this.Redirect("/");
        }
    }

以及实际保存修改的服务函数:

        public async Task Edit(int ID, string Title, string Description, DateTime? dateedited, DateTime? dateclosed, string CustomerId, int StateCode, int Prioritycode, string TechnicianId, int Productid, int? productVersionId, int ticketType = (int)TicketTypeEnum.Support)
    {
        var originalTicket = Context.Tickets.Find(ID);
        originalTicket.Title = Title;
        originalTicket.Technician_ID = TechnicianId;
        originalTicket.State_Code = ticketType == (int)TicketTypeEnum.FeatureRequest ? (int)Enums.StateCode.FeatureSuggestion : StateCode;
        originalTicket.Priority_Code = ticketType == (int)TicketTypeEnum.FeatureRequest ? (int)PriorityCode.FeatureSuggestion : Prioritycode;
        originalTicket.Description = Description;
        originalTicket.Date_Edited = dateedited;
        originalTicket.Date_Closed = dateclosed;
        originalTicket.Customer_ID = CustomerId;
        originalTicket.ProductID = Productid;
        originalTicket.Product_Version_ID = productVersionId;
        originalTicket.Ticket_Type_ID = ticketType;

        await Context.SaveChangesAsync();
    }

这是 CreateTimelineEvent 代码:

        public void CreateTimelineEvent(int ticketno, string raisedby, DateTime dateadded, string details, TimelineEventType type, string assignedto = null)
    {
        try
        {
            var timelineEvent = new TimelineEvent()
            {
                Ticket_Number = ticketno,
                Raised_By = raisedby,
                DateAdded = dateadded,
                Details = details,
                Type = (int)type,
                Assigned_To = assignedto
            };
            Context.TimelineEvents.Add(timelineEvent);
            Context.SaveChanges();
        }
        catch (Exception ex)
        {
            throw ex;
        }
    }

GetTickets 函数:

        public IEnumerable<Ticket> GetTickets(FilterType type, string current_user_id, TicketTypeEnum ticketType = TicketTypeEnum.Support)
    {
        IEnumerable<Ticket> tickets = null;

        switch (ticketType)
        {
            case TicketTypeEnum.Support:
                tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer).SupportTickets();
                break;
            case TicketTypeEnum.FeatureRequest:
                tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer).FeatureRequestTickets();
                break;
            default:
                tickets = Context.Tickets.Include(e => e.Tech).Include(e => e.Customer);
                break;
        }

        switch (type)
        {
            case FilterType.OpenTickets:
                return tickets.OpenTickets();
            case FilterType.ClosedTickets:
                return tickets.ClosedTickets();
            case FilterType.MyOpenTickets:
                return tickets.MyOpenTickets(current_user_id);
            case FilterType.OpenedToday:
                return tickets.OpenedToday();
            case FilterType.DueToday:
                return tickets.DueToday();
            default:
                return tickets;
        }
    }

抱歉花了这么长时间才回到这个问题,但在我发布这个问题后不久,我设法将问题追溯到一个本地开发的依赖注入系统,它创建了一个 DBContext 的静态实例。

我们已经决定在 .Net Core 中重新编写系统以利用内置的依赖注入。