DbSet.Attach(entity) vs DbContext.Entry(entity).St

2019-01-07 02:49发布

问题:

When I am in a detached scenario and get a dto from the client which I map into an entity to save it I do this:

context.Entry(entity).State = EntityState.Modified;
context.SaveChanges();

For what is then the DbSet.Attach(entity)

or why should I use the .Attach method when EntityState.Modified already attaches the entity?

回答1:

When you do context.Entry(entity).State = EntityState.Modified;, you are not only attaching the entity to the DbContext, you are also marking the whole entity as dirty. This means that when you do context.SaveChanges(), EF will generate an update statement that will update all the fields of the entity.

This is not always desired.

On the other hand, DbSet.Attach(entity) attaches the entity to the context without marking it dirty. It is equivalent to doing context.Entry(entity).State = EntityState.Unchanged;

When attaching this way, unless you then proceed to update a property on the entity, the next time you call context.SaveChanges(), EF will not generate a database update for this entity.

Even if you are planning on making an update to an entity, if the entity has a lot of properties (db columns) but you only want to update a few, you may find it advantageous to do a DbSet.Attach(entity), and then only update the few properties that need updating. Doing it this way will generate a more efficient update statement from EF. EF will only update the properties you modified (in contrast to context.Entry(entity).State = EntityState.Modified; which will cause all properties/columns to be updated)

Relevant documentation: Add/Attach and Entity States.

Code example

Let's say you have the following entity:

public class Person
{
    public int Id { get; set; } // primary key
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

If your code looks like this:

context.Entry(personEntity).State = EntityState.Modified;
context.SaveChanges();

The SQL generated will look something like this:

UPDATE person
SET FirstName = 'whatever first name is',
    LastName = 'whatever last name is'
WHERE Id = 123; -- whatever Id is.

Notice how the above update statement will update all the columns, regardless or whether you've actually changed the values or not.

In contrast, if your code uses the "normal" Attach like this:

context.People.Attach(personEntity); // State = Unchanged
personEntity.FirstName = "John"; // State = Modified, and only the FirstName property is dirty.
context.SaveChanges();

Then the generated update statement is different:

UPDATE person
SET FirstName = 'John'
WHERE Id = 123; -- whatever Id is.

As you can see, the update statement only updates the values that were actually changed after you attached the entity to the context. Depending on the structure of your table, this can have a positive performance impact.

Now, which option is better for you depends entirely on what you are trying to do.



回答2:

When you use the DbSet.Update method, Entity Framework marks all properties of your entity as EntityState.Modified, so tracks them. If you want to change only some of your properties, not all of them, use DbSet.Attach. This method makes all of your properties EntityState.Unchanged, so you must make your properties that you want to update EntityState.Modified. Thus when the app hits to DbContext.SaveChanges, it will only operate modified properties.