Comment supprimer un objet par identifiant avec le framework d'entité

105

Il me semble que je dois récupérer un objet avant de le supprimer avec un framework d'entité comme ci-dessous

var customer = context.Customers.First(c => c.Id == 1);

context.DeleteObject(customer);

context.Savechanges();

J'ai donc besoin de frapper la base de données deux fois. Y a-t-il un moyen plus simple?

Jeff
la source
j.mp/f0x0Bh est votre réponse. C'est une façon sympa et générique de le faire
BritishDeveloper

Réponses:

94

Dans Entity Framework 6, l'action de suppression est Remove. Voici un exemple

Customer customer = new Customer () { Id = id };
context.Customers.Attach(customer);
context.Customers.Remove(customer);
context.SaveChanges();
dwkd
la source
16
Pourquoi Attach? Pourquoi pas juste Removeet SaveChanges?
runeks
3
Vous devez attacher votre entité dans le contexte car si vous ne le faites pas, vous recevrez une erreur lors de la suppression. EF ne peut supprimer des entités que dans ce contexte
Pierre-Luc
3
@runeks selon le manuel, l'entité doit exister dans le contexte avant que l'opération Remove puisse être effectuée. Voir ici docs.microsoft.com/en-us/dotnet/api/…
dwkd
1
Je n'ai pas utilisé d'attache, et ça marche bien
ILIAS M. DOLAPO
58

Identique à @Nix avec une petite modification pour être fortement typé:

Si vous ne souhaitez pas le rechercher, créez simplement une entité, puis supprimez-la.

                Customer customer = new Customer () { Id = id };
                context.Customers.Attach(customer);
                context.Customers.DeleteObject(customer);
                context.SaveChanges();
Sawan
la source
7
Pas parfait car il lève une exception si l'objet est manquant: "DbUpdateConcurrencyException: l'instruction de mise à jour, d'insertion ou de suppression du magasin a affecté un nombre inattendu de lignes (0)." Je voudrais qu'il l'ignore, comme le ferait une instruction DELETE.
Dunc
désolé, cela provoque une validation qui n'est pas nécessaire et attendue toujours!
Hamed Zakery Miab
32

Question similaire ici .

Avec Entity Framework, il existe EntityFramework-Plus (bibliothèque d'extensions).
Disponible sur NuGet. Ensuite, vous pouvez écrire quelque chose comme:

// DELETE all users which has been inactive for 2 years
ctx.Users.Where(x => x.LastLoginDate < DateTime.Now.AddYears(-2))
     .Delete();

Il est également utile pour les suppressions groupées.

acarlon
la source
37
Cela ne veut pas dire que cela ne fait pas partie de la bibliothèque EF de base pour le moment.
nathanchere
1
@FerretallicA - d'accord.
acarlon
2
cette méthode est obsolète use: context.Users.Where (user => user.Id == id) .Delete ();
Manuel
Il ne fonctionne pas avec Azure SQL DataWarehouse en raison de l'erreur «Une clause FROM n'est actuellement pas prise en charge dans une instruction DELETE». Mais le SQL brut comme dans la réponse de Jonik fonctionne.
Michael Freidgeim
1
La fonction context.SaveChanges () est-elle nécessaire?
Tomas Kubes
23

Si vous ne souhaitez pas le rechercher, créez simplement une entité, puis supprimez-la.

Customer customer  = new Customer() {  Id = 1   } ; 
context.AttachTo("Customers", customer);
context.DeleteObject(customer);
context.Savechanges();
Rien
la source
6

J'utilise le code suivant dans l'un de mes projets:

    using (var _context = new DBContext(new DbContextOptions<DBContext>()))
    {
        try
        {
            _context.MyItems.Remove(new MyItem() { MyItemId = id });
            await _context.SaveChangesAsync();
        }
        catch (Exception ex)
        {
            if (!_context.MyItems.Any(i => i.MyItemId == id))
            {
                return NotFound();
            }
            else
            {
                throw ex;
            }
        }
    }

De cette façon, il interrogera la base de données deux fois uniquement si une exception se produit lors de la tentative de suppression de l'élément avec l'ID spécifié. Ensuite, si l'élément n'est pas trouvé, il renvoie un message significatif; sinon, il renvoie simplement l'exception (vous pouvez gérer cela d'une manière plus adaptée à votre cas en utilisant différents blocs catch pour différents types d'exceptions, ajoutez plus de vérifications personnalisées en utilisant des blocs if, etc.).

[J'utilise ce code dans un projet MVC .Net Core / .Net Core avec Entity Framework Core.]

démoniaque
la source
2

La requête SQL brute est le moyen le plus rapide, je suppose

public void DeleteCustomer(int id)
{
   using (var context = new Context())
   {
      const string query = "DELETE FROM [dbo].[Customers] WHERE [id]={0}";
      var rows = context.Database.ExecuteSqlCommand(query,id);
      // rows >= 1 - count of deleted rows,
      // rows = 0 - nothing to delete.
   }
}
Jonik
la source
19
Cela va à l'encontre de l'objectif d'utiliser la fonctionnalité d'objet fortement typée dans EF.
LawMan
4
Cela compromet l'argent de l'identité EF. Après cela, EF vous retournera toujours votre entité supprimée.
epox
1
Il fonctionne avec Azure SQL DataWarehouse, contrairement aux autres solutions.
Michael Freidgeim
1
Si vous faites cela, vous pourriez aussi bien ne pas utiliser d'ORM. J'imagine que cela compromettrait le cache EF.
Storm Muller
Ce style est vulnérable aux attaques par injection SQL. Dans cet exemple spécifique, vous êtes protégé car la variable est un entier, mais n'utilisez jamais ce modèle avec une variable chaîne.
thelem le
2

La réponse de dwkd a principalement fonctionné pour moi dans le cœur d'Entity Framework, sauf lorsque j'ai vu cette exception:

InvalidOperationException: l'instance du type d'entité "Client" ne peut pas être suivie car une autre instance avec la même valeur de clé pour {"Id"} est déjà en cours de suivi. Lorsque vous attachez des entités existantes, assurez-vous qu'une seule instance d'entité avec une valeur de clé donnée est attachée. Pensez à utiliser «DbContextOptionsBuilder.EnableSensitiveDataLogging» pour voir les valeurs de clé en conflit.

Pour éviter l'exception, j'ai mis à jour le code:

Customer customer = context.Customers.Local.First(c => c.Id == id);
if (customer == null) {
    customer = new Customer () { Id = id };
    context.Customers.Attach(customer);
}
context.Customers.Remove(customer);
context.SaveChanges();
Jeffrey Rennie
la source
2

Une version plus petite (par rapport aux précédentes):

var customer = context.Find(id);
context.Delete(customer);
context.SaveChanges();
Luis Gouveia
la source
Veuillez fournir un contexte à cet extrait de code, et peut-être une explication de ce qu'il fait mieux que les autres réponses laissées au cours de la dernière décennie.
miken32
1

Cette réponse est en fait tirée du cours de Scott Allen intitulé ASP.NET MVC 5 Fundamentals. J'ai pensé partager parce que je pense que c'est un peu plus simple et plus intuitif que toutes les réponses ici déjà. Notez également que selon Scott Allen et d'autres formations que j'ai effectuées, la méthode find est un moyen optimisé de récupérer une ressource de la base de données qui peut utiliser la mise en cache si elle a déjà été récupérée. Dans ce code, collection fait référence à un DBSet d'objets. L'objet peut être n'importe quel type d'objet générique.

        var object = context.collection.Find(id);  
        context.collection.Remove(object);
        context.SaveChanges();
andy_coder
la source