首页 > 解决方案 > 为什么 Entity Framework Core 2 Attach() 方法不会导致跟踪后续更改?

问题描述

我正在将应用程序移植到 EF Core 2,并且我想对对象进行大量部分更新。但是,我不想先查询这些对象(我已经知道它们在那里,我不在乎我要更改的属性的先前值是什么;查询它们是浪费往返数据库)。

在 EF6 中,我只需使用适当的键值创建一个对象、附加它、进行更改并保存,它会使用跟踪的更改在 SQL 中生成更新。但在 EF Core 2 中,这不起作用;实体状态保持不变。我知道我可以手动告诉跟踪器我已经更改了某些属性,但这很混乱有两个原因:在部分更新之前必须查询对象的代码不必这样做,所以它很混乱,还有那个模式会让我两次指定每个非常潮湿的属性。

一个人为的例子,假设 MyDbContext 继承了从 Scaffold-DbContext 生成的 DbContext:

//This is a model class for a table (id uniqueidentifier PRIMARY KEY, data int)
public partial class Record
{
    public Guid id { get; set; }
    public bool data { get; set; }
}

一些导致数据库不更新的代码:

using (var db = new MyDbContext()) {
    var rec = new Record {
       id = new Guid('bc372788-5a96-4ada-a2e0-c604d1abed92')
    }
    db.Attach(rec);
    rec.data = false;
    db.SaveChanges();
}

一些确实会导致更新的代码,但如果多个属性已更改,则会变得非常混乱:

using (var db = new MyDbContext()) {
    var rec = new Record {
       id = new Guid('bc372788-5a96-4ada-a2e0-c604d1abed92'),
       data = false
    }
    db.Attach(rec).Property(x => x.data).IsModified = true;
    db.SaveChanges();
}

为了更加强调,一些代码进行了无用的查询,但确实像我想要的那样更新了数据库:

using (var db = new MyDbContext()) {
    var rec = db.Record.Single(x => x.id == new Guid('bc372788-5a96-4ada-a2e0-c604d1abed92'));
    rec.data = false;
    db.SaveChanges();
}

有什么方法可以做到这一点,这样我就不必在更新现有记录之前对其进行查询,而且 EF Core 2 也可以跟踪我对记录所做的更改?

标签: c#entity-framework-core

解决方案


它不起作用,因为我是个傻瓜。bool 的默认 CLR 值为 false,因此,新构造的对象已经具有 data = false。更改跟踪器运行,当然检测到它仍然是错误的,并且不生成任何更改。

一种解决方案是将值设置为非默认值,以便它看起来已更改:

using (var db = new MyDbContext()) {
    var rec = new Record {
       id = new Guid('bc372788-5a96-4ada-a2e0-c604d1abed92'),
       data = true
    }
    db.Attach(rec);
    rec.data = false;
    db.SaveChanges();
}

另一种方法是在类中使用可为空的类型(如果合适),另一种方法仍然是声明该属性已使用 .IsModified 进行修改,如上所述。


推荐阅读