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 中重新编写系统以利用内置的依赖注入。
我在工作中处理的一个应用程序有一个有趣的错误,我们无法找到它,而且我在搜索中也找不到任何类似的东西。
我的公司建立了一个帮助台系统来跟踪用户问题,在提交错误后,工单从所有工单列表中“消失”了。它在数据库中仍然可见,并没有在任何地方被过滤掉。可以通过将 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 中重新编写系统以利用内置的依赖注入。