web-dev-qa-db-fra.com

DbSet.Attach (entité) vs DbContext.Entry (entité) .State = EntityState.Modified

Lorsque je suis dans un scénario détaché et que j'obtiens un dto du client que je mappe dans une entité pour le sauvegarder, je fais ceci:

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

Pour ce qui est alors la DbSet.Attach(entity)

ou pourquoi devrais-je utiliser la méthode .Attach quand EntityState.Modified attache déjà l'entité?

99
Elisabeth

Lorsque vous faites context.Entry(entity).State = EntityState.Modified;, vous n'attachez pas seulement l'entité au DbContext, vous marquez également l'entité entière comme étant sale. Cela signifie que lorsque vous faites context.SaveChanges(), EF génère une instruction de mise à jour qui met à jour all les champs de l'entité.

Ce n'est pas toujours souhaité.

Par contre, DbSet.Attach(entity) attache l'entité au contexte sans , ce qui la rend sale. . Cela équivaut à faire context.Entry(entity).State = EntityState.Unchanged;

Lorsque vous associez cette méthode, à moins que vous ne procédiez ensuite à la mise à jour d'une propriété sur l'entité, la prochaine fois que vous appelez context.SaveChanges(), EF ne générera pas de mise à jour de base de données pour cette entité.

Même si vous envisagez de mettre à jour une entité, si celle-ci possède de nombreuses propriétés (colonnes de la base de données) mais que vous ne souhaitez en mettre à jour que quelques-unes, il peut être avantageux de faire une DbSet.Attach(entity), puis ne mettez à jour que les quelques propriétés nécessitant une mise à jour. En procédant ainsi, vous générerez une déclaration de mise à jour plus efficace à partir de EF. EF mettra uniquement à jour les propriétés que vous avez modifiées (contrairement à context.Entry(entity).State = EntityState.Modified; qui entraînera la mise à jour de toutes les propriétés/colonnes)

Documentation pertinente: Ajouter/Attacher et États de l'entité .

Exemple de code

Disons que vous avez l'entité suivante:

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

Si votre code ressemble à ceci:

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

Le SQL généré ressemblera à quelque chose comme ceci:

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

Remarquez comment l'instruction de mise à jour ci-dessus met à jour toutes les colonnes, que vous ayez ou non modifié les valeurs.

En revanche, si votre code utilise l’attachement "normal" comme ceci:

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

Ensuite, la déclaration de mise à jour générée est différente:

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

Comme vous pouvez le constater, la déclaration de mise à jour uniquement met à jour les valeurs qui ont été modifiées après que vous ayez joint le entité au contexte. Selon la structure de votre table, cela peut avoir un impact positif sur les performances.

Maintenant, quelle option est la meilleure pour vous dépend entièrement de ce que vous essayez de faire.

248
sstan

Lorsque vous utilisez la méthode DbSet.Update, Entity Framework marque toutes les propriétés de votre entité comme étant EntityState.Modified, afin de les suivre. Si vous souhaitez modifier seulement certaines de vos propriétés, pas toutes, utilisez DbSet.Attach. Cette méthode rend toutes vos propriétés EntityState.Unchanged, vous devez donc définir les propriétés que vous souhaitez mettre à jour EntityState.Modified. Ainsi, lorsque l'application utilisera DbContext.SaveChanges, elle n'utilisera que les propriétés modifiées.

0
Orhun