Why does Entity Framework Core 2 Attach() method not cause subsequent changes to be tracked?

c# entity-framework-core

Question

I'm porting an application to EF Core 2, and I want to do a lot of partial updates to objects. But, I don't want to query those objects first (I already know they are there and I don't care what the previous values of the properties I'm changing are; querying them is a waste of a round trip to the DB).

In EF6, I'd simply create an object with the appropriate key value, attach it, make my changes, and save, and it'd generate an update in SQL using the tracked changes. But in EF Core 2, this does not work; the entity state remains unmodified. I know I can manually tell the tracker I've changed certain properties, but this is messy for two reasons: the code that has to query objects before a partial update doesn't have to do that, so it's confusing, and also that pattern would make me specify each property twice which is very wet.

A contrived example, supposing a MyDbContext inheriting DbContext generated from Scaffold-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; }
}

Some code that causes no updates to the database:

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();
}

Some code that does cause an update, but that gets very messy if more than one property has changed:

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();
}

For greater emphasis, some code that makes a useless query but does update the DB like I want:

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();
}

Is there some way to do this so that I don't have to make a query for the existing record before updating it, but also so that EF Core 2 tracks changes I make to the record?

1
1
10/19/2018 2:37:01 AM

Popular Answer

It is not working because I am a fool. The default CLR value for bool is false, and so in consequence, the newly constructed object already has data = false. The change tracker runs and of course detects that it's still false, and generates no change.

One solution is to set the value to a non-default so that it will appear changed:

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();
}

Another would be to use a nullable type in the class (if appropriate) and another still would be to just declare that the property is modified with .IsModified as above.

1
10/19/2018 2:40:29 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow