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

时间:2016-10-04 07:25:00

标签: c# entity-framework

我有一个执行标准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; } 方法。

非常感谢任何帮助。

感谢!!!!

2 个答案:

答案 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.
}