web-dev-qa-db-fra.com

Un moyen efficace de mettre à jour la liste des entités

Je travaille sur un projet qui permet à l'utilisateur de modifier une liste d'entités. Je mappe ces entités pour visualiser les modèles et les afficher avec les champs de l'éditeur. Lorsque l'utilisateur appuie sur le bouton Soumettre, je passe en revue chaque modèle et le mets à jour comme suit:

foreach (var viewModel in viewModels)
{
    //Find the database model and set the value and update
    var entity = unit.EntityRepository.GetByID(fieldModel.ID);
    entity.Value = viewModel.Value;
    unit.EntityRepository.Update(entity);
}

Le code ci-dessus fonctionne, cependant, comme vous pouvez le voir, nous devons frapper la base de données deux fois pour chaque entité (une à récupérer et une autre à mettre à jour). Existe-t-il un moyen plus efficace de le faire en utilisant Entity Framework? J'ai remarqué que chaque mise à jour génère une instruction SQL distincte. Existe-t-il un moyen de valider toutes les mises à jour une fois la boucle terminée?

26
Stefan Bossbaly

Voici deux méthodes que je connais pour mettre à jour une entité dans la base de données sans effectuer d'abord une récupération de l'entité:

//Assuming person is detached from the context
//for both examples
public class Person
{
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime BornOn { get; set; }   
}

public void UpdatePerson(Person person)
{
  this.Context.Persons.Attach(person)
  DbEntityEntry<Person> entry = Context.Entry(person);
  entry.State = System.Data.EntityState.Modified;
  Context.SaveChanges();
}

Devrait céder:

Update [schema].[table]
Set Name = @p__linq__0, BornOn = @p__linq__1
Where id = @p__linq__2

Ou vous pouvez simplement spécifier des champs si vous en avez besoin (probablement bon pour les tableaux avec une tonne de colonnes, ou pour des raisons de sécurité, ne permet de mettre à jour que des colonnes spécifiques:

public void UpdatePersonNameOnly(Person person)
{
  this.Context.Persons.Attach(person)
  DbEntityEntry<Person> entry = Context.Entry(person);
  entry.Property(e => e.Name).IsModified = true;
  Context.SaveChanges();
}

Devrait céder:

Update [schema].[table]
Set Name = @p__linq__0
Where id = @p__linq__1
19
Erik Philips

Vous pouvez essayer ce qui suit pour minimiser les requêtes:

using (var ctx = new MyContext())
{
    var entityDict = ctx.Entities
        .Where(e => viewModels.Select(v => v.ID).Contains(e.ID))
        .ToDictionary(e => e.ID); // one DB query

    foreach (var viewModel in viewModels)
    {
        Entity entity;
        if (entityDict.TryGetValue(viewModel.ID, out entity))
            entity.Value = viewModel.Value;
    }

    ctx.SaveChanges(); //single transaction with multiple UPDATE statements
}

Soyez conscient que Contains peut être potentiellement lent si la liste de viewModels est très longue. Mais il n'exécutera qu'une seule requête.

6
Slauma