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()方法。

任何帮助都将是非常感激的。

谢谢! !

c# -实体框架不更新实体

错误是自描述的。原因是,你从上下文获得实体之前附加它通过这个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.
}