web-dev-qa-db-fra.com

Mettre à jour un enregistrement sans d'abord interroger?

Disons que j'interroge la base de données et charge une liste d'éléments. J'ouvre ensuite l'un des éléments dans un formulaire de vue détaillée et, au lieu de réinterroger l'élément en dehors de la base de données, je crée une instance de l'élément à partir de la source de données dans la liste.

Est-il possible de mettre à jour l'enregistrement de base de données sans extraire l'enregistrement de l'élément en question?

Voici un exemple de la façon dont je le fais maintenant:

dataItem itemToUpdate = (from t in dataEntity.items
                                 where t.id == id
                                 select t).FirstOrDefault();

Puis, après avoir extrait l’enregistrement, je mets à jour certaines valeurs de l’article et pousse l’enregistrement:

itemToUpdate.itemstatus = newStatus;
dataEntity.SaveChanges();

Je penserais qu'il y aurait une meilleure façon de faire ceci, des idées?

85
Shane Grant

Vous devriez utiliser la méthode Attach () .

Attacher et détacher des objets

64
CD..

Vous pouvez également utiliser le SQL direct sur la base de données en utilisant le contexte du magasin de données. Exemple:

dataEntity.ExecuteStoreCommand
   ("UPDATE items SET itemstatus = 'some status' WHERE id = 123 ");

Pour des raisons de performances, vous souhaiterez peut-être transmettre des variables plutôt qu'une chaîne SQL codée en dur. Cela permettra à SQL Server de mettre en cache la requête et de le réutiliser avec des paramètres. Exemple:

dataEntity.ExecuteStoreCommand
   ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 });

UPDATE - pour EF 6.0

dataEntity.Database.ExecuteSqlCommand
       ("UPDATE items SET itemstatus = 'some status' WHERE id = {0}", new object[] { 123 });
32
barrypicker

Si la DataItem a des champs EF sera pré-validé (comme les champs non nullables), nous devrons désactiver cette validation pour ce contexte:

DataItem itemToUpdate = new DataItem { Id = id, Itemstatus = newStatus };
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true;
dataEntity.Configuration.ValidateOnSaveEnabled = false;
dataEntity.SaveChanges();
//dataEntity.Configuration.ValidateOnSaveEnabled = true;

Sinon, nous pouvons essayer de satisfaire la pré-validation et de ne mettre à jour que la colonne unique:

DataItem itemToUpdate = new DataItem
{
    Id = id,
    Itemstatus = newStatus,
    NonNullableColumn = "this value is disregarded - the db original will remain"
};
dataEntity.Entry(itemToUpdate).Property(x => x.Itemstatus).IsModified = true;
dataEntity.SaveChanges();

En supposant que dataEntity est un System.Data.Entity.DbContext

Vous pouvez vérifier la requête générée en l'ajoutant à la DbContext:

/*dataEntity.*/Database.Log = m => System.Diagnostics.Debug.Write(m);
7
Aske B.

Le code:

ExampleEntity exampleEntity = dbcontext.ExampleEntities.Attach(new ExampleEntity { Id = 1 });
exampleEntity.ExampleProperty = "abc";
dbcontext.Entry<ExampleEntity>(exampleEntity).Property(ee => ee.ExampleProperty).IsModified = true;
dbcontext.Configuration.ValidateOnSaveEnabled = false;
dbcontext.SaveChanges();

Le résultat TSQL:

exec sp_executesql N'UPDATE [dbo].[ExampleEntities]
SET [ExampleProperty ] = @0
WHERE ([Id] = @1)
',N'@0 nvarchar(32),@1 bigint',@0='abc',@1=1

Remarque:

La ligne "IsModified = true" est nécessaire car, lorsque vous créez le nouvel objet ExampleEntity (uniquement avec la propriété Id renseignée), toutes les autres propriétés ont leurs valeurs par défaut (0, null, etc.). Si vous souhaitez mettre à jour la base de données avec une "valeur par défaut", la modification ne sera pas détectée par la structure de l'entité, puis la base de données ne sera pas mise à jour.

Par exemple: 

exampleEntity.ExampleProperty = null;

ne fonctionnera pas sans la ligne "IsModified = true", car la propriété ExampleProperty est déjà nulle lorsque vous avez créé l'objet ExampleEntity vide. Vous devez donc indiquer à EF que cette colonne doit être mise à jour.

6
tecla

Cet article faisant partie de Prise en main de Microsoft explique les états des entités et comment procéder:

Ajouter/attacher et états d'entité

Regardez la section 'Attacher une entité existante mais modifiée au contexte'

Maintenant, je pars pour lire le reste de ces tutoriels.

2
Simon_Weaver

En règle générale, si vous avez utilisé Entity Framework pour interroger tous les éléments et que vous avez enregistré l'objet entité, vous pouvez mettre à jour les éléments individuels dans l'objet entité et appeler SaveChanges() lorsque vous avez terminé. Par exemple:

var items = dataEntity.Include("items").items;
// For each one you want to change:
items.First(item => item.id == theIdYouWant).itemstatus = newStatus;
// After all changes:
dataEntity.SaveChanges();

La récupération de l'élément souhaité ne doit pas générer de nouvelle requête.

0
Andrew

Cela fonctionne un peu différemment dans EF Core:

Il existe peut-être un moyen plus rapide de le faire dans EF Core, mais les éléments suivants garantissent une mise à jour sans devoir effectuer de sélection (testé avec EF Core 2 et JET sur .NET Framework 4.6.2):

Assurez-vous que votre modèle n'a pas de propriétés IsRequired

Ensuite, utilisez le modèle suivant (dans VB.NET):

    Using dbContext = new MyContext()
        Dim bewegung = dbContext.MyTable.Attach(New MyTable())
        bewegung.Entity.myKey = someKey
        bewegung.Entity.myOtherField = "1"

        dbContext.Entry(bewegung.Entity).State = EntityState.Modified
        dbContext.Update(bewegung.Entity)

        Dim BewegungenDescription = (From tp In dbContext.Model.GetEntityTypes() Where tp.ClrType.Name = "MyTable" Select tp).First()
        For Each p In (From prop In BewegungenDescription.GetProperties() Select prop)
            Dim pp = dbContext.Entry(bewegung.Entity).Property(p.Name)
            pp.IsModified = False
        Next
        dbContext.Entry(bewegung.Entity).Property(Function(row) row.myOtherField).IsModified = True
        dbContext.SaveChanges()
    End Using
0
Wolfgang Grinfeld