Einen einzelnen Datensatz aus Entity Framework löschen?

195

Ich habe eine SQL Server-Tabelle in Entity Framework employmit einer einzelnen Schlüsselspalte ID.

Wie lösche ich einen einzelnen Datensatz mit Entity Framework aus der Tabelle?

user2497476
quelle
2
db.employ.Remove (db.employ.Find (ID1))
Carter Medlin
2
@CarterMedlin - während das funktioniert, sind dies zwei Datenbanktreffer: ein SELECT und ein DELETE. Die meisten Leute finden das äußerst verschwenderisch, zumal die Auswahl wahrscheinlich wesentlich länger dauert als das Löschen.
Davor
Ich würde aufgrund der Leistungsprobleme nicht empfehlen, das Entity Framework Remove oder RemoveRange zu verwenden. Ich würde lieber etwas ganz Einfaches wie folgt verwenden: var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, neuer SqlParameter ("@ your_parameter", yourParameter));
neugierigBoy
2
@curiousBoy Ich denke, wenn Sie Anweisungen ausführen, wie Sie vorgeschlagen haben, spiegelt der EF6-Cache die Änderung nicht wider.
Yitzchak

Antworten:

362

Es ist nicht erforderlich, das Objekt zuerst abzufragen. Sie können es anhand seiner ID an den Kontext anhängen. So was:

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

Alternativ können Sie den Status des angehängten Eintrags auf gelöscht setzen:

var employer = new Employ { Id = 1 };
ctx.Entry(employer).State = EntityState.Deleted;
ctx.SaveChanges();
mt_serg
quelle
87
Alternativctx.Entry(employer).State = EntityState.Deleted
Simon Belanger
12
Dies funktioniert nur, wenn die Beziehungen als Löschkaskade definiert sind. Andernfalls schlägt der obige Code bei einer FK-Ausnahme fehl.
Baruchl
6
@mt_serg, ich schaue 3 Schritte voraus. Wann mussten Sie das letzte Mal wirklich einen so einfachen Datensatz aus der Datenbank entfernen? Normalerweise haben Sie es mit komplexeren Datensätzen zu tun, die FK-Beziehungen enthalten. daher mein Kommentar.
Baruchl
2
@ IanWarburton Die 2. und 3. Zeile (Anhängen und Entfernen)
Simon Belanger
4
@PaulZahra: Manchmal haben Sie eine Liste von IDs aus einer anderen Abfrage oder Quelle, und Sie müssen eine löschen. Anstatt die Objekte nur zum Löschen zu laden, können Sie sie auf diese Weise nach ID löschen. Sie wissen, so funktioniert die DELETE-Anweisung normalerweise in SQL.
Siride
82

Sie können SingleOrDefaultein einzelnes Objekt verwenden, das Ihren Kriterien entspricht, und dieses dann an die RemoveMethode Ihrer EF-Tabelle übergeben.

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

if (itemToRemove != null) {
    Context.Employ.Remove(itemToRemove);
    Context.SaveChanges();
}
Mansfield
quelle
5
Dies ist kein guter Weg, da Sie alle Felder aus der Datenbank auswählen!
Ali Yousefi
2
So mache ich es.
Jack Fairfield
4
@Ali, Jack - Aber ich denke, dies ist vorzuziehen, da zuerst geprüft wird, ob die Daten, die Sie löschen möchten, tatsächlich vorhanden sind, was Probleme verhindern kann. Die akzeptierte Antwort hat keine Prüfung als solche.
Michael Philips
4
Das ist der bessere Weg. Denk darüber nach. Was ist, wenn John Smith versucht, ein Element mit einer ID = 1 zu entfernen, das Susie Smith vor 30 Sekunden entfernt hat, John es jedoch nicht weiß? In diesem Fall müssen Sie die Datenbank aufrufen.
Yusha
4
@ Yusha Warum? In beiden Szenarien ist das Ergebnis, dass der Datensatz weg ist. Interessiert es uns wirklich, ob das jetzt oder vor 30 Sekunden passiert ist? Einige Rennbedingungen sind einfach nicht so interessant, um den Überblick zu behalten.
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();
Alex G.
quelle
2
FirstOrDefaultist gefährlich. Entweder wissen Sie, dass es nur eine gibt (verwenden Sie also SingleOrDefault), oder es gibt mehr als eine, und dies sollte in einer Schleife erfolgen.
Mark Sowul
8
Employer employer = context.Employers.First(x => x.EmployerId == 1);

context.Customers.DeleteObject(employer);
context.SaveChanges();
Sam Leach
quelle
Schützt dies, wenn kein Objekt mit der ID 1 vorhanden ist? Würde es nicht eine Ausnahme werfen?
Jack Fairfield
@ JackFairfield Ich denke, Sie sollten nach Null-Objekt suchen. und entsprechend durchführen entfernen.
Jawand Singh
Firstist gefährlich. Entweder wissen Sie, dass es nur eine gibt (verwenden Sie also Single), oder es gibt mehr als eine, und dies sollte in einer Schleife erfolgen.
Mark Sowul
5

Ich verwende das Entity Framework mit LINQ. Der folgende Code war hilfreich für mich;

1- Für mehrere Datensätze

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

2- Für einzelne Aufzeichnung

 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();
 }
Baqer Naqvi
quelle
Für Single Record warum nicht SingleOrDefaultanstelle von verwenden FirstOrDefault?
Mark Sowul
Wenn Sie SingleOrDefault verwenden, geben Sie eindeutig an, dass die Abfrage höchstens zu einem einzigen Ergebnis führen soll. Wenn FirstOrDefault verwendet wird, kann die Abfrage eine beliebige Anzahl von Ergebnissen zurückgeben. Sie geben jedoch an, dass Sie nur den ersten Stackoverflow.com/a/1745716/3131402
Baqer Naqvi
1
Ja, warum sollte es dann richtig sein, einen beliebigen Datensatz zu löschen, wenn es mehr als einen gibt? Besonders in diesem Fall ist die ID der Schlüssel, also sollte es einen geben: Wenn es mehr als einen gibt, ist es ein Fehler (den Single erkennen würde)
Mark Sowul
@ MarkSowul du hast recht. Ich habe die Antwort bearbeitet, um FirstOrDefault zu verwenden.
Baqer Naqvi
@BaqerNaqvi RemoveRange ist eine schreckliche Möglichkeit, Entitäten aus der Leistungsperspektive zu entfernen. Insbesondere, wenn Ihre Entität mit allen Navigationseigenschaften von Fremdschlüsseln überfüllt ist. Ich würde lieber var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter" verwenden; this.your_context.Database.ExecuteSqlCommand (sql, neuer SqlParameter ("@ your_parameter", yourParameter));
neugierigBoy
2

Allgemeiner Ansatz

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);
}
Valentasmus
quelle
2

Mit Entity Framework 6 können Sie verwenden Remove. Es ist auch eine gute Taktik, um usingsicherzustellen, dass Ihre Verbindung geschlossen ist.

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

Ich wollte nur die drei Methoden beisteuern, mit denen ich hin und her gesprungen bin.

Methode 1:

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

Methode 2:

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

Einer der Gründe, warum ich mich für Methode 2 entscheide, ist QueryTrackingBehavior.NoTracking, dass es sicherer ist, EF oder EFCore auf zu setzen.

Dann gibt es Methode 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;

Dies verwendet einen Soft-Delete-Ansatz, indem die DeletedOnEigenschaft des Datensatzes festgelegt wird und der Datensatz dennoch für die zukünftige Verwendung aufbewahrt werden kann, was auch immer dies sein mag. Im Grunde genommen in den Papierkorb legen .


Auch in Bezug auf Methode 3 , anstatt den gesamten Datensatz so zu ändern, dass er geändert wird:

entry.State = EntityState.Modified;

Sie würden auch einfach nur die Spalte DeletedOnals geändert festlegen :

entry.Property(x => x.DeletedOn).IsModified = true;
LatentDenis
quelle
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);
        }
    }

Was denkst du darüber, einfach oder nicht, du könntest es auch versuchen:

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

Für generische DAO meine Arbeit finnaly dies:

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

Die Verwendung von EntityFramework.Plus kann eine Option sein:

dbContext.Employ.Where(e => e.Id == 1).Delete();

Weitere Beispiele finden Sie hier

Mohammad Reza Sadreddini
quelle
0

Du kannst es einfach so machen

   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");
        }
    }

Modell-

 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; }

} 

Ansicht, von der aus Sie es nennen werden

 <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>

Ich hoffe, das wird für dich leicht zu verstehen sein

Sikander Iqbal
quelle
0

Sie können so etwas in Ihrem Klick- oder Celldoubleclick-Ereignis Ihres Rasters tun (falls Sie eines verwendet haben).

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

Dann machen Sie so etwas in Ihrer Löschtaste:

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
}

Alternativ können Sie eine LINQ-Abfrage anstelle der LINQ-Abfrage für Entitäten verwenden:

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

Employ.Id wird als Filterparameter verwendet, der bereits vom CellDoubleClick-Ereignis Ihrer DataGridView übergeben wurde.

Arvin Aquio
quelle
Die Idee hinter dem Code ist, dass Sie die ID (Employ.Id) des Datensatzes, den Sie löschen möchten, mit dem Modell (Employee Class) verbinden und sie dann aus dem Kontext an die eigentliche Tabelle anhängen und dann die In-Memory-Methode Remove () ausführen Führen Sie schließlich das eigentliche Speichern in der Datenbank mit der SaveChanges () -Methode aus. Die LINQ-Abfrage funktioniert zwar auch einwandfrei, aber ich mag die Idee nicht, die Tabelle abzufragen, nur um die ID des Datensatzes zu erhalten.
Arvin Aquio
0

Hier ist ein sicherer Weg:

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...
  }
}

Hier können Sie alle gewünschten Änderungen stapeln, sodass Sie vor SaveChanges und Commit eine Reihe von Löschvorgängen durchführen können, damit sie nur angewendet werden, wenn sie alle erfolgreich sind.

Emilio.NT
quelle
0

Der beste Weg ist zu überprüfen und dann zu löschen

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
dE Quelle
quelle