Usunąć pojedynczy rekord z Entity Framework?


195

Mam tabelę SQL Server w Entity Framework o nazwie employz pojedynczą kolumną klucza o nazwie ID.

Jak usunąć pojedynczy rekord z tabeli za pomocą Entity Framework?


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

2
@CarterMedlin - choć to zadziała, są to dwa trafienia do bazy danych: jeden WYBIERZ i jeden USUŃ. Większość ludzi uważa to za wyjątkowo marnotrawstwo, zwłaszcza że wybór zajmie znacznie więcej czasu niż usunięcie.
Davor

Nie sugerowałbym używania struktury encji Remove lub RemoveRange ze względu na problemy z wydajnością. Wolałbym po prostu użyć czegoś bardzo prostego, jak następuje: var sql = "USUŃ Z TWOJEGO TABELI GDZIE TWOJA_FIELD = @ twój_parametr"; this.your_context.Database.ExecuteSqlCommand (sql, nowy SqlParameter („@ twój_parametr”, twójParameter));
ciekawyBoy

2
@curiousBoy Myślę, że podczas wykonywania instrukcji zgodnie z sugestią pamięć podręczna EF6 nie odzwierciedla zmiany.
Icchak

Odpowiedzi:


362

Najpierw nie jest konieczne zapytanie obiektu, możesz dołączyć go do kontekstu za pomocą jego identyfikatora. Lubię to:

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

Alternatywnie możesz ustawić stan dołączonego wpisu na usunięty:

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

87
Alternatywniectx.Entry(employer).State = EntityState.Deleted
Simon Belanger

12
zadziała to tylko wtedy, gdy relacje zostaną zdefiniowane jako kaskada usuwania. w przeciwnym razie powyższy kod zawiedzie w przypadku wyjątku FK.
baruchl

6
@mt_serg, patrzę 3 kroki do przodu. kiedy ostatni raz naprawdę musiałeś usunąć tak prosty rekord z DB? zazwyczaj masz do czynienia z bardziej złożonymi zapisami, które obejmują relacje FK. stąd mój komentarz.
baruchl

2
@IanWarburton Druga i trzecia linia (Dołącz i usuń)
Simon Belanger

4
@PaulZahra: czasami masz listę identyfikatorów z innego zapytania lub źródła i musisz ją usunąć. Zamiast ładować obiekty tylko po to, aby je usunąć, w ten sposób możesz usunąć według ID. Wiesz, właśnie tak działa instrukcja DELETE w SQL.
siride,

82

Możesz użyć, SingleOrDefaultaby uzyskać pojedynczy obiekt spełniający twoje kryteria, a następnie przekazać go do Removemetody tabeli EF.

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

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

5
to nie jest dobry sposób, ponieważ wybierasz wszystkie pola z bazy danych!
Ali Yousefi

2
Tak to robię.
Jack Fairfield

4
@Ali, Jack - Myślę jednak, że jest to lepsze, ponieważ najpierw sprawdza, czy dane, które próbujesz usunąć, istnieją, co może zapobiec problemom. Przyjęta odpowiedź nie ma jako takiej kontroli.
Michael Philips

4
To jest lepszy sposób. Pomyśl o tym. Co jeśli John Smith próbuje usunąć element o identyfikatorze = 1, który Susie Smith usunęła 30 sekund temu, ale John nie wie? W takim przypadku musisz trafić do bazy danych.
Jusza

4
@Yusha Dlaczego? W obu scenariuszach wynik jest taki, że rekord zniknął. Czy naprawdę obchodzi nas, czy stało się to teraz, czy 30 sekund temu? Niektóre warunki wyścigowe po prostu nie są aż tak interesujące, aby je śledzić.
Run 5

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
FirstOrDefaultjest niebezpieczny. Albo wiesz, że jest tylko jeden (użyj SingleOrDefault), albo jest więcej niż jeden i należy to zrobić w pętli.
Mark Sowul

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

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

Czy to chroni, jeśli nie ma obiektu o Id 1? Czy nie rzuciłoby to wyjątku?
Jack Fairfield

@JackFairfield Myślę, że powinieneś sprawdzić, czy nie ma obiektu zerowego. i zgodnie z nim wykonać usuń.
Jawand Singh,

Firstjest niebezpieczny. Albo wiesz, że jest tylko jeden (użyj Single), albo jest więcej niż jeden i należy to zrobić w pętli.
Mark Sowul,

5

Korzystam z platformy encji z LINQ. Poniższy kod był dla mnie pomocny;

1- W przypadku wielu rekordów

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

2- Dla pojedynczego rekordu

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

Dla pojedynczego rekordu, dlaczego nie użyć SingleOrDefaultzamiast FirstOrDefault?
Mark Sowul,

Ilekroć używasz SingleOrDefault, wyraźnie stwierdzasz, że zapytanie powinno dać maksymalnie jeden wynik. Z drugiej strony, gdy używana jest FirstOrDefault, zapytanie może zwrócić dowolną liczbę wyników, ale stwierdzasz, że chcesz tylko pierwszy stackoverflow.com/a/1745716/3131402
Baqer Naqvi

1
Tak, więc dlaczego poprawne byłoby usunięcie dowolnego zapisu, jeśli istnieje więcej niż jeden? Szczególnie w tym przypadku identyfikator jest kluczem, więc powinien być jeden: jeśli jest więcej niż jeden, jest to błąd (który Single
wykryłby

@MarkSowul masz rację. Zredagowałem odpowiedź, aby użyć FirstOrDefault.
Baqer Naqvi

@BaqerNaqvi RemoveRange to okropny sposób na usunięcie jednostki z perspektywy wydajności. Zwłaszcza gdy twoja jednostka jest obciążona wszystkimi właściwościami nawigacyjnymi według kluczy obcych. Wolałbym użyć var ​​sql = "USUŃ Z TWOJEGO TABELI GDZIE TWOJE_FIELD = @ twój_parametr"; this.your_context.Database.ExecuteSqlCommand (sql, nowy SqlParameter („@ twój_parametr”, twójParameter));
ciekawyBoy

2

Bardziej ogólne podejście

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

Z Entity Framework 6 możesz korzystać Remove. Jest to również dobra taktyka, aby usingupewnić się, że połączenie jest zamknięte.

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

1

Chciałem tylko wnieść trzy metody, którymi się podskakiwałem.

Metoda 1:

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

Metoda 2:

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

Jednym z powodów, dla których wolę stosować Metodę 2, jest to, że w przypadku ustawienia EF lub EFCore na QueryTrackingBehavior.NoTracking, bezpieczniej jest to zrobić.

Jest też metoda 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;

Wykorzystuje to podejście polegające na łagodnym usuwaniu poprzez ustawienie właściwości rekordu DeletedOni nadal jest w stanie zachować rekord do przyszłego użytku, cokolwiek to może być. Zasadniczo umieszczenie go w Koszu .


Ponadto, w odniesieniu do metody 3 , zamiast ustawić cały rekord do modyfikacji:

entry.State = EntityState.Modified;

Po prostu ustawisz tylko kolumnę DeletedOnjako zmodyfikowaną:

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

Co sądzisz o tym, proste czy nie, możesz również spróbować:

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

0

W przypadku ogólnego DAO moja praca ostatecznie to:

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


0

możesz to zrobić po prostu w ten sposób

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

Model

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

} 

widok, z którego go nazwiesz

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

mam nadzieję, że będzie to dla ciebie łatwe do zrozumienia


0

Możesz zrobić coś takiego w zdarzeniu kliknięcia lub celldoubleclick swojej siatki (jeśli takiego użyłeś)

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

Następnie zrób coś takiego w swoim przycisku usuwania:

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
}

Alternatywnie można użyć zapytania LINQ zamiast zapytania LINQ To Entities:

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

seek.Id jest używany jako parametr filtrujący, który został już przekazany ze zdarzenia CellDoubleClick Twojego DataGridView.


Idea kryjąca się za kodem polega na tym, że łączysz identyfikator (zatrudniany) identyfikatora rekordu, który chcesz usunąć z modelem (klasa pracownika), a następnie dołączasz go do rzeczywistej tabeli z kontekstu, a następnie wykonujesz w pamięci metodę Remove (), a następnie na koniec wykonaj rzeczywiste zapisywanie w bazie danych za pomocą metody SaveChanges (). Chociaż zapytanie LINQ również działa dobrze, ale nie podoba mi się pomysł zapytania do tabeli tylko po to, aby uzyskać identyfikator rekordu.
arvin aquio

0

Oto bezpieczny sposób:

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

Tutaj możesz zebrać wszystkie potrzebne zmiany, dzięki czemu możesz wykonać serię usuwania przed SaveChanges i Commit, więc zostaną one zastosowane tylko wtedy, gdy wszystkie zakończą się powodzeniem.


0

Najlepszym sposobem jest sprawdzenie, a następnie usunięcie

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.