Supprimer un seul enregistrement d'Entity Framework?


195

J'ai une table SQL Server dans Entity Framework nommée employavec une seule colonne de clé nommée ID.

Comment supprimer un seul enregistrement de la table à l'aide d'Entity Framework?


2
db.employ.Remove (db.employ.Find (ID1))
Carter Medlin

2
@CarterMedlin - bien que cela fonctionne, ce sont deux accès à la base de données: un SELECT et un DELETE. La plupart des gens trouvent cela extrêmement inutile, d'autant plus que select prendra probablement beaucoup plus de temps qu'une suppression.
Davor

Je ne suggère pas d'utiliser le framework d'entité Remove ou RemoveRange en raison des problèmes de performances. Je préfère simplement utiliser quelque chose de super simple comme suit: var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, new SqlParameter ("@ your_parameter", yourParameter));
curiousBoy

2
@curiousBoy Je pense que lorsque vous exécutez des instructions comme vous l'avez suggéré, le cache EF6 ne reflète pas le changement.
Yitzchak

Réponses:


362

Il n'est pas nécessaire d'interroger d'abord l'objet, vous pouvez le joindre au contexte par son identifiant. Comme ça:

var employer = new Employ { Id = 1 };
ctx.Employ.Attach(employer);
ctx.Employ.Remove(employer);
ctx.SaveChanges();

Vous pouvez également définir l'état de l'entrée jointe sur supprimé:

var employer = new Employ { Id = 1 };
ctx.Entry(employer).State = EntityState.Deleted;
ctx.SaveChanges();

87
Alternativement,ctx.Entry(employer).State = EntityState.Deleted
Simon Belanger

12
cela ne fonctionnera que si les relations sont définies comme cascade de suppression. sinon le code ci-dessus échouera sur une exception FK.
baruchl

6
@mt_serg, je regarde 3 pas en avant. À quand remonte la dernière fois que vous avez vraiment dû supprimer un enregistrement aussi simple de la base de données? vous avez généralement affaire à des enregistrements plus complexes qui incluent des relations FK. d'où mon commentaire.
baruchl

2
@IanWarburton La 2e et 3e ligne (attacher et retirer)
Simon Bélanger

4
@PaulZahra: parfois, vous avez une liste d'ID d'une autre requête ou source, et vous devez en supprimer une. Plutôt que de charger les objets juste pour les supprimer, vous pouvez ainsi supprimer par ID. Vous savez, c'est ainsi que l'instruction DELETE fonctionne normalement dans SQL.
siride

82

Vous pouvez utiliser SingleOrDefaultpour obtenir un seul objet correspondant à vos critères, puis le transmettre à la Removeméthode de votre table EF.

var itemToRemove = Context.Employ.SingleOrDefault(x => x.id == 1); //returns a single item.

if (itemToRemove != null) {
    Context.Employ.Remove(itemToRemove);
    Context.SaveChanges();
}

5
ce n'est pas un bon moyen, car vous sélectionnez tous les champs de la base de données!
Ali Yousefi

2
C'est ainsi que je le fais.
Jack Fairfield

4
@Ali, Jack - Mais je pense que cela est préférable car il vérifie d'abord si les données que vous essayez de supprimer existent réellement, ce qui peut éviter tout problème. La réponse acceptée n'a pas de vérification en tant que telle.
Michael Philips

4
C'est la meilleure façon. Pensez-y. Que faire si John Smith essaie de supprimer un élément avec un id = 1 que Susie Smith a supprimé il y a 30 secondes mais John ne sait pas? Vous devez frapper la base de données dans ce cas.
Yusha

4
@Yusha Pourquoi? Dans les deux scénarios, le résultat est que le record a disparu. Nous soucions-nous vraiment si cela s'est produit maintenant ou il y a 30 secondes? Certaines conditions de course ne sont tout simplement pas si intéressantes à suivre.
9Rune5

13
  var stud = (from s1 in entities.Students
            where s1.ID== student.ID
            select s1).SingleOrDefault();

  //Delete it from memory
  entities.DeleteObject(stud);
  //Save to database
  entities.SaveChanges();

2
FirstOrDefaultest dangereux. Soit vous savez qu'il n'y en a qu'un (alors utilisez SingleOrDefault), soit il y en a plus d'un, et cela devrait être fait en boucle.
Mark Sowul

8
Employer employer = context.Employers.First(x => x.EmployerId == 1);

context.Customers.DeleteObject(employer);
context.SaveChanges();

Est-ce que cela protège s'il n'y a pas d'objet avec Id 1? Cela ne ferait-il pas exception?
Jack Fairfield

@JackFairfield je pense que vous devriez vérifier pour un objet nul. et selon elle, effectuez la suppression.
Jawand Singh

Firstest dangereux. Soit vous savez qu'il n'y en a qu'un (alors utilisez Single), soit il y en a plus d'un, et cela devrait être fait en boucle.
Mark Sowul

5

J'utilise le framework d'entité avec LINQ. Le code suivant m'a été utile;

1- Pour plusieurs enregistrements

 using (var dbContext = new Chat_ServerEntities())
 {
     var allRec= dbContext.myEntities;
     dbContext.myEntities.RemoveRange(allRec);
     dbContext.SaveChanges();
 }

2- Pour un enregistrement unique

 using (var dbContext = new Chat_ServerEntities())
 {
     var singleRec = dbContext.ChatUserConnections.FirstOrDefault( x => x.ID ==1);// object your want to delete
     dbContext.ChatUserConnections.Remove(singleRec);
     dbContext.SaveChanges();
 }

Pour Single record pourquoi ne pas utiliser à la SingleOrDefaultplace de FirstOrDefault?
Mark Sowul

Chaque fois que vous utilisez SingleOrDefault, vous indiquez clairement que la requête doit aboutir au maximum à un résultat unique. D'un autre côté, lorsque FirstOrDefault est utilisé, la requête peut renvoyer n'importe quelle quantité de résultats mais vous déclarez que vous ne voulez que le premier stackoverflow.com/a/1745716/3131402
Baqer Naqvi

1
Oui, alors pourquoi serait-il correct de supprimer un enregistrement arbitraire, s'il y en a plusieurs? En particulier dans ce cas, l'id est la clé, donc il devrait y en avoir un: s'il y en a plus d'un, c'est un bug (que Single détecterait)
Mark Sowul

@MarkSowul vous avez raison. J'ai modifié la réponse pour utiliser FirstOrDefault.
Baqer Naqvi

@BaqerNaqvi RemoveRange est un moyen terrible de supprimer l'entité du point de vue des performances .. Surtout lorsque votre entité est lourde de toutes les propriétés de navigation par des clés étrangères. Je préfère utiliser var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, new SqlParameter ("@ your_parameter", yourParameter));
curiousBoy

2

Approche plus générique

public virtual void Delete<T>(int id) where T : BaseEntity, new()
{
    T instance = Activator.CreateInstance<T>();
    instance.Id = id;
    if (dbContext.Entry<T>(entity).State == EntityState.Detached)
    {
        dbContext.Set<T>().Attach(entity);
    }

    dbContext.Set<T>().Remove(entity);
}

2

Avec Entity Framework 6, vous pouvez utiliser Remove. C'est aussi une bonne tactique à utiliser usingpour être sûr que votre connexion est fermée.

using (var context = new EmployDbContext())
{
    Employ emp = context.Employ.Where(x => x.Id == id).Single<Employ>();
    context.Employ.Remove(emp);
    context.SaveChanges();
}

1

Je voulais juste contribuer aux trois méthodes avec lesquelles j'ai rebondi.

Méthode 1:

var record = ctx.Records.FirstOrDefault();
ctx.Records.Remove(record);
ctx.SaveChanges();

Méthode 2:

var record = ctx.Records.FirstOfDefault();
ctx.Entry(record).State = EntityState.Deleted;
ctx.SaveChanges();
ctx.Entry(record).State = EntityState.Detached;

L'une des raisons pour lesquelles je préfère utiliser la méthode 2 est que dans le cas de la définition de EF ou EFCore QueryTrackingBehavior.NoTracking, il est plus sûr de le faire.

Ensuite, il y a la méthode 3:

var record = ctx.Records.FirstOrDefault();
var entry = ctx.Entry(record);
record.DeletedOn = DateTimeOffset.Now;
entry.State = EntityState.Modified;
ctx.SaveChanges();
entry.State = EntityState.Detached;

Cela utilise une approche de suppression logicielle en définissant la DeletedOnpropriété de l'enregistrement et en étant toujours en mesure de conserver l'enregistrement pour une utilisation future, quelle qu'elle soit. Fondamentalement, le mettre dans la corbeille .


En outre, en ce qui concerne la méthode 3 , au lieu de définir l'enregistrement entier à modifier:

entry.State = EntityState.Modified;

Vous devez également simplement définir uniquement la colonne DeletedOntelle que modifiée:

entry.Property(x => x.DeletedOn).IsModified = true;

0
    [HttpPost]
    public JsonResult DeleteCotnact(int id)
    {
        using (MycasedbEntities dbde = new MycasedbEntities())
        {
            Contact rowcontact = (from c in dbde.Contact
                                     where c.Id == id
                                     select c).FirstOrDefault();

            dbde.Contact.Remove(rowcontact);
            dbde.SaveChanges();

            return Json(id);
        }
    }

Que pensez-vous de cela, simple ou non, vous pouvez également essayer ceci:

        var productrow = cnn.Product.Find(id);
        cnn.Product.Remove(productrow);
        cnn.SaveChanges();

0

Pour le DAO générique mon travail enfin ceci:

    public void Detele(T entity)
    {
        db.Entry(entity).State = EntityState.Deleted;
        db.SaveChanges();
    }


0

tu peux le faire comme ça

   public ActionResult Delete(int? id)
    {
        using (var db = new RegistrationEntities())
        {
            Models.RegisterTable Obj = new Models.RegisterTable();
            Registration.DAL.RegisterDbTable personalDetail = db.RegisterDbTable.Find(id);
            if (personalDetail == null)
            {
                return HttpNotFound();
            }
            else
            {
                Obj.UserID = personalDetail.UserID;
                Obj.FirstName = personalDetail.FName;
                Obj.LastName = personalDetail.LName;
                Obj.City = personalDetail.City;

            }
            return View(Obj);
        }
    }


    [HttpPost, ActionName("Delete")]

    public ActionResult DeleteConfirmed(int? id)
    {
        using (var db = new RegistrationEntities())
        {
            Registration.DAL.RegisterDbTable personalDetail = db.RegisterDbTable.Find(id);
            db.RegisterDbTable.Remove(personalDetail);
            db.SaveChanges();
            return RedirectToAction("where u want it to redirect");
        }
    }

modèle

 public class RegisterTable
{

    public int UserID
    { get; set; }


    public string FirstName
    { get; set; }


    public string LastName
    { get; set; }


    public string Password
    { get; set; }


    public string City
    { get; set; }

} 

vue d'où tu l'appelleras

 <table class="table">
    <tr>
        <th>
            FirstName
        </th>
        <th>
            LastName
        </th>

        <th>
            City
        </th>
        <th></th>
    </tr>

    @foreach (var item in Model)
    {
        <tr>
            <td> @item.FirstName </td>
            <td> @item.LastName </td>
            <td> @item.City</td>
            <td>
                <a href="@Url.Action("Edit", "Registeration", new { id = item.UserID })">Edit</a> |
                <a href="@Url.Action("Details", "Registeration", new { id = item.UserID })">Details</a> |
                <a href="@Url.Action("Delete", "Registeration", new { id = item.UserID })">Delete</a>

            </td>
        </tr>

    }

</table>

j'espère que ce sera facile à comprendre


0

Vous pouvez faire quelque chose comme ça dans votre événement click ou celldoubleclick de votre grille (si vous en avez utilisé un)

if(dgEmp.CurrentRow.Index != -1)
 {
    employ.Id = (Int32)dgEmp.CurrentRow.Cells["Id"].Value;
    //Some other stuff here
 }

Ensuite, faites quelque chose comme ceci dans votre bouton Supprimer:

using(Context context = new Context())
{
     var entry = context.Entry(employ);
     if(entry.State == EntityState.Detached)
     {
        //Attached it since the record is already being tracked
        context.Employee.Attach(employ);
     }                             
     //Use Remove method to remove it virtually from the memory               
     context.Employee.Remove(employ);
     //Finally, execute SaveChanges method to finalized the delete command 
     //to the actual table
     context.SaveChanges();

     //Some stuff here
}

Vous pouvez également utiliser une requête LINQ au lieu d'utiliser la requête LINQ To Entities:

var query = (from emp in db.Employee
where emp.Id == employ.Id
select emp).Single();

employ.Id est utilisé comme paramètre de filtrage qui a déjà été transmis à partir de l'événement CellDoubleClick de votre DataGridView.


L'idée derrière le code est de câbler l'id (employ.Id) de l'enregistrement que vous souhaitez supprimer au modèle (classe d'employé), puis de le joindre à la table réelle du contexte, puis d'exécuter la méthode Remove () en mémoire, puis enfin exécuter l'enregistrement réel dans la base de données à l'aide de la méthode SaveChanges (). Bien que la requête LINQ fonctionne également bien, mais je n'aime pas l'idée d'interroger la table juste pour obtenir l'ID de l'enregistrement.
arvin aquio

0

Voici un moyen sûr:

using (var transitron = ctx.Database.BeginTransaction())
{
  try
  {
    var employer = new Employ { Id = 1 };
    ctx.Entry(employer).State = EntityState.Deleted;
    ctx.SaveChanges();
    transitron.Commit();
  }
  catch (Exception ex)
  {
    transitron.Rollback();
    //capture exception like: entity does not exist, Id property does not exist, etc...
  }
}

Ici, vous pouvez empiler toutes les modifications souhaitées, vous pouvez donc effectuer une série de suppressions avant les modifications et les validations, de sorte qu'elles ne seront appliquées que si elles réussissent toutes.


0

La meilleure façon est de vérifier puis de supprimer

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.