c# -实体框架不更新实体
本文关键字:实体 更新 框架 | 更新日期: 2023-09-27 18:11:20
我有一个简单的应用程序,执行标准的CRUD操作。
我的问题是,目前,它似乎没有在数据库中编辑值。我已经调试了整个过程,看到它在上下文中的set.Attach(entity)
行上失败了。
[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; }
}
API控制器动作
[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
}
<<p> 上下文方法/strong> public void SetModified<T>(T entity) where T : class
{
var set = Set<T>();
set.Attach(entity); //FAILS HERE
Entry(entity).State = EntityState.Modified;
}
我已经检查了对象的ID等是否已填充,以便实体框架可以找到现有的记录,我现在没有想法了。
我没有得到任何错误信息。我所看到的是,一旦它试图附加实体,它去到我的UnityResolver的Dispose()
方法。
任何帮助都将是非常感激的。
谢谢! !
错误是自描述的。原因是,你从上下文获得实体之前附加它通过这个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
添加另一个名为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
方法。
public void UpdateRepack(RepackRequest repack)
{
// Do needed operations
// Remove this line. You are supposed to save changes in the end using _uow.Save(); -> _context.Save();
}
您试图附加一个不属于上下文的实体。你需要通过键来获取那个对象,修改获取的对象,然后附加并保存(或者只是保存它)。更多细节在这里
你的代码应该是这样的(如在注释中讨论的):
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.
}