我有一个执行标准CRUD操作的简单应用程序。
我的问题是,目前它似乎没有在数据库中编辑值。我已经通过该过程进行了调试,并发现它在上下文中的<%
if(session.getAttribute("email") == null) {
response.sendRedirect("login.jsp");
return ;
}
%>
行上失败了。
模型
set.Attach(entity)
API控制器操作
[Table("RepackRequest")]
public partial class RepackRequest
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public RepackRequest()
{
}
public int ID { get; set; }
[Required]
public string FromItem { get; set; }
[Required]
public string ToItem { get; set; }
public int Quantity { get; set; }
public int? QuantityCompleted { get; set; }
[Column(TypeName = "date")]
public DateTime DateRequested { get; set; }
[Required]
public string RequestedBy { get; set; }
[Required]
public string RequestedByEmail { get; set; }
public string ActionRequired { get; set; }
[Required]
public string Division { get; set; }
[Required]
[StringLength(1)]
public string Status { get; set; }
[Column(TypeName = "date")]
public DateTime? CompletionDate { get; set; }
[Required]
public string Customer { get; set; }
[Required]
public string Priority { get; set; }
[Required]
public string EnteredBy { get; set; }
public string CompletedBy { get; set; }
public string FromLocation { get; set; }
public string ToLocation { get; set; }
public string ReworkedBy { get; set; }
public string OriginalDriver { get; set; }
public string FromItemDriver { get; set; }
public string FromLocationDriver { get; set; }
public string ToLocationDriver { get; set; }
public string Workforce { get; set; }
[Required]
public string OrderNum { get; set; }
[Column(TypeName = "date")]
public DateTime PlannedCompletion { get; set; }
[Column(TypeName = "date")]
public DateTime? StartDate { get; set; }
}
服务方法
[HttpPost, Route("api/Repack/Update")]
public async Task<HttpResponseMessage> UpdateRepack([FromBody] RepackRequest repack)
{
var oldStatus = _uow.RepackService.Get(repack.ID).Status;
_uow.RepackService.UpdateRepack(repack);
_uow.Save();
if (repack.Status == "C")
await _helper.SendCompletedRepackEmail(repack);
else if (repack.Status != oldStatus)
await _helper.SendStatusChangeEmail(repack, oldStatus);
return Request.CreateResponse(HttpStatusCode.OK, repack.ID);
}
上下文方法
public void UpdateRepack(RepackRequest repack)
{
_context.SetModified(repack);
_context.Save(); //_context.SaveChanges() called inside here
}
我已经检查过对象的ID等已经填写好,以便Entity Framework可以找到现有的记录,而且我现在已经没想到了。
我根本没有收到任何错误消息。我所看到的是,一旦它试图附加实体,它就会转到我的UnityResolver的public void SetModified<T>(T entity) where T : class
{
var set = Set<T>();
set.Attach(entity); //FAILS HERE
Entry(entity).State = EntityState.Modified;
}
方法。
非常感谢任何帮助。
感谢!!!!
答案 0 :(得分:1)
错误是自我描述。原因是您在通过此var oldStatus = _uow.RepackService.Get(repack.ID).Status;
代码行附加实体之前从上下文获取实体,并且实体框架将其保留在上下文中。您有两种解决方法:
在UpdateRepack
中使用其ID从上下文中重新获取实体,并将值设置为新值。
public void UpdateRepack(RepackRequest repack)
{
RepackRequest fromDatabase = _uow.RepackService.Get(repack.ID);
// Set current values to new values.
_context.SetValues(fromDatabase, repack);
_context.Save(); //_context.SaveChanges() called inside here
}
public void SetValues<T>(T entity, T currentEntity) where T : class
{
var entry = Entry(entity);
entry.CurrentValues.SetValues(currentEntity);
}
不要担心,从上下文获取数据不会是昂贵的操作,因为它已经在上下文中。通过使用此方法,将发送更新查询以仅更新已更改的属性,而如果将实体状态设置为已修改,则将发送更新查询以更新所有列值。
您可以使用AsNoTracking
告诉EntityFramework不要在上下文中存储收到的实体。但通过这样做,每次你试图获得对象查询将对数据库执行。此外,将发送更新查询以更新所有列值,并且它比仅更新所需值要昂贵得多。为此,您应该为名为RepackService
的{{1}}工作单元添加另一种方法,并按以下方式实现:
GetAsNoTracking
然后你应该使用public Repack GetAsNoTracking(int id)
{
return _context.Set<Repack>()
.AsNoTracking()
.First(m => m.ID == id);
}
获取你的重新包装而不是触及当前代码的剩余部分。因为它没有存储在上下文附加中,所以不会导致错误。
GetAsNoTracking
注意:保存每项操作的数据并不是一种好习惯。在工作单元模式中,您应该提交一次而不是为每个操作调用[HttpPost, Route("api/Repack/Update")]
public async Task<HttpResponseMessage> UpdateRepack([FromBody] RepackRequest repack)
{
var oldStatus = _uow.RepackService.GetAsNoTracking(repack.ID).Status;
.........
}
方法。从您的代码中我看到您有SaveChanges
方法,我相信您在此方法中调用_uow.Save();
方法。通过这样做,您应该避免在诸如_context.SaveChanges()
方法之类的crud函数中调用SaveChanges
。
UpdateRepack
答案 1 :(得分:0)
您尝试附加不属于上下文的实体。你需要通过键来引入该对象,修改获取的对象然后附加并保存(或者只保存它)。更多详情here
您的代码应该是(如评论中所述):
public void SetModified<T>(T entity) where T : class
{
var set = Set<T>();
var entityFromCtx = set.Where(x => x.Id == entity.Id).FirstOrDefault();
Entry(entityFromCtx).CurrentValues.SetValues(entity);
//set.Attach(entity); // you don't need this anymore since you're not disposing the context yet.
Entry(entityFromCtx).State = EntityState.Modified;
//set.SaveChanges(); // I don't know if this fits here, but just don't forget it.
}