为什么我们要在 Entity Framework 中更新之前附加模型?

Why should we attach model before update in Entity Framework?

我对 Entity Framework 中的更改跟踪器有疑问。我在 MSDN 上阅读了更改跟踪器文档——它说如果你将一个模型插入数据库,它在上下文中的状态将是 Added,当你执行 SaveChanges() 时,它会插入一个新行到数据库及其状态变为 unchanged.

那么为什么我们要在 Entity Framework 中更新之前附加模型?

public virtual void Update(TEntity entity)
{
    _dbset.Attach(entity); => ???
    _context.Entry(entity).State = EntityState.Modified;
    _context.SaveChanges();
}

更新 :

因为 EntityFramework 仅更改了存在于 ChangeTracker 中的实体。

并且当您将一个实体附加到 DbContext 时,entity framework 知道一个实体已经跟踪并且可能包含更改并在 SaveChanges 之后应用 DataBase 中的更改。

虽然实体在 DbContext 的范围内被更改,并且没有加载 /w AsNoTracking,但当您调用 SaveChanges 时,该 DbContext 的更改跟踪器将获取更改并应用更新.在您给出的示例中,在许多情况下,您可能正在处理当前 不再 被 DbContext 跟踪的实体。

举个简单的例子:(跟踪的实体)

public void UpdateDescription(int orderId, string description)
{
    using (var context = new AppDbContext())
    {
        var order = context.Orders.Single(x => x.OrderId == orderId);
        order.Description = description;
        context.SaveChanges();
    }
}

在此示例中,Order 实体在单个 DbContext 的范围内加载、跟踪和更新。相反,如果我们有这样的方法结构:

public Order GetOrderById(int orderId)
{
    using (var context = new AppDbContext())
    {
        return context.Orders.Single(x => x.OrderId == orderId);
    }
}

public void UpdateOrder(Order order)
{
    using (var context = new AppDbContext())
    {
        context.Attach(order);
        context.Entity(order).State = EntityState.Modified;
        context.SaveChanges();
    }
}

例如在 Web 应用程序中,编辑页面检索订单实体并将其传递给视图。当用户更新模型页面上的某些字段并提交时,将通过模型进行单独的更新调用。通过“GetOrderById”调用,Order 实体由 DbContext 的一个实例加载。当“UpdateOrder”调用发生时,该订单实际上是一个反序列化的 POCO,不再是一个被跟踪的实体。这就是为什么您需要将它附加到 Update 将使用的 DbContext 实例,并将其实体状态设置为已修改,以便 EF 将其视为需要更新的实体。

值得注意的是,在第一个跟踪示例中,UPDATE SQL 语句实际上类似于:

UPDATE Orders SET Description = 'newDescription' WHERE OrderId = 1

在第二个示例中,UPDATE 语句更像是:

UPDATE Orders SET OrderNumber = 21, CustomerId = 12, Description = 'newDescription' /* + all fields/FKs in Order table... */ WHERE OrderId = 1 

通过附加实体状态并将其设置为已修改,EF 将更新实体的 all non-PK 属性,即使您只 intend/expect 一个字段已被修改。在 Web 应用程序的情况下,将实体传回控制器以通过这种方式进行更新会使您的系统容易受到数据篡改的影响。 (更改您的 UI 不允许的 fields/FKs)这也意味着您需要始终传递一个完整的实体,以避免数据可能被意外擦除,这会增加消息负载大小来回客户端和服务器。