231

I have a SQL Server table in Entity Framework named employ with a single key column named ID.

How do I delete a single record from the table using Entity Framework?

CharithJ
  • 46,289
  • 20
  • 116
  • 131
user2497476
  • 2,413
  • 2
  • 13
  • 6
  • 3
    db.employ.Remove(db.employ.Find(ID1)) – Carter Medlin Dec 01 '16 at 19:17
  • 2
    @CarterMedlin - while that will work, those are two database hits: one SELECT and one DELETE. Most people find that extremely wasteful, especially since select will probably take significantly more time than a delete. – Davor Jul 04 '17 at 13:48
  • I would not suggest to use entity framework Remove or RemoveRange due to the performance issues. I would rather just use something super simple as following: var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD= @your_parameter"; this.your_context.Database.ExecuteSqlCommand(sql, new SqlParameter("@your_parameter", yourParameter)); – curiousBoy Apr 24 '18 at 00:44
  • 2
    @curiousBoy I think that when you execute statements like you suggested, the EF6 cache doesn't reflect the change. – Yitzchak Jul 08 '18 at 10:09

15 Answers15

418

It's not necessary to query the object first, you can attach it to the context by its id. Like this:

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

Alternatively, you can set the attached entry's state to deleted :

var employer = new Employ { Id = 1 };
ctx.Entry(employer).State = EntityState.Deleted;
ctx.SaveChanges();
Brian Webster
  • 30,033
  • 48
  • 152
  • 225
mt_serg
  • 7,487
  • 4
  • 29
  • 45
  • 97
    Alternatively, `ctx.Entry(employer).State = EntityState.Deleted` – Simon Belanger Jul 18 '13 at 12:44
  • 18
    this will only work if the relationships are defined as delete cascade. otherwise the code above will fail on an FK exception. – baruchl Sep 29 '14 at 19:08
  • 6
    @mt_serg, I'm looking 3 steps ahead. when was the last time you really had to remove such a simple record from the DB? usually you are dealing with more complex records that include FK relations. hence my comment. – baruchl Sep 30 '14 at 18:46
  • @SimonBelanger Won't that still fetch the object? – MrFox Dec 03 '15 at 12:24
  • @MrFox The state tracker will only register the object itself and mark it as deleted. When SaveChanges is called, it will look in the tracker and see that the object is marked for deletion. Not fetching is actually done. You could actually new-up an instance and set the PK of the object (ID in this case) and attach it to the state tracker. – Simon Belanger Dec 03 '15 at 14:27
  • The point being made is that when do you ever create an object, attach it, then remove it (using the object reference you just created)... Basically you either construct a fake object that doesn't exist in the context then delete it or query the DB for it... a lame example that bares little resemblance with the real world.... You could construct the item easily / manually if you say had a load of records in the session / serialised... which begs the question of which is faster and by how much? Construct from memory or from DB call. – Paul Zahra Apr 11 '16 at 12:00
  • @SimonBelanger What does that line of code replace? – Ian Warburton May 24 '16 at 23:57
  • 2
    @IanWarburton The 2nd and 3rd line (Attach and Remove) – Simon Belanger May 25 '16 at 11:22
  • 4
    @PaulZahra: sometimes you have a list of IDs from some other query or source, and you need to delete one. Rather than loading up the objects just to delete them, this way you can delete by ID. You know, that's how the DELETE statement works in SQL normally. – siride Jul 11 '16 at 18:18
  • So you already have an entity in the context with ID of 1 that is being tracked... then you add another entity with an ID of 1... then delete ID of 1... seems a bit hacky to me. – Paul Zahra Jul 12 '16 at 08:04
  • @PaulZahra no that's not what he said. – Nick Coad Sep 27 '16 at 04:45
  • @PaulZahra the client sending a list of ids to delete; is but one example. No need to assume that new entities are being created. Also, I don't think baruchl was referring to new entities. – seebiscuit Mar 22 '17 at 15:22
  • Creating a stub in this fashion just seems illogical to me, and makes me wonder why MS hasn't done something about it... furthermore this solution is only really 'valid' if the entity you want to delete is not in memory, if it is in memory (context) then the answer by Mansfield seems the best fit. – Paul Zahra Mar 23 '17 at 10:12
  • First one worked for me. Second one, if your entity's tracking is disabled, may not work. I tried and it gave me an error that entity does not exists in current context – Atta H. Aug 25 '17 at 17:27
  • 1
    This is not a good solution if there's a chance that the entity won't exist as there is no null check. – brad Apr 21 '18 at 22:00
  • 1
    This throws an exception if id is not in database. how to handle this? – Nouman Bhatti Jul 19 '19 at 00:30
  • What if your `DbSet` has that item in `.GetLocal()` from a previous but recent load? Would it not have two identical Entities by primary key and throw an exception when you SaveChanges? – Zachary Scott Apr 22 '20 at 05:52
  • I sustain the usage of ctx.Entry(employer).State = EntityState.Deleted; in a transaction block and try/catch block. I don't share the feeling about FKs though... if you get blocked on a deletion from your solution because of FKs in place, that means whoever is the architect needs to review very thouroughly the work done. I've never been fond of FKs and less of delete cascade. – Emilio.NT Jun 19 '20 at 14:06
105

You can use SingleOrDefault to get a single object matching your criteria, and then pass that to the Remove method of your EF table.

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

if (itemToRemove != null) {
    Context.Employ.Remove(itemToRemove);
    Context.SaveChanges();
}
Mansfield
  • 14,445
  • 18
  • 76
  • 112
  • 6
    this is not good way, because you are select all field from database! – Ali Yousefi May 12 '16 at 05:31
  • 2
    This is the way I do it. – Jack Fairfield Aug 31 '16 at 20:22
  • @JackFairfield checkout the accepted answer. There is no need to hit the database and retrieve data. EF only looks at the Id of the object being deleted anyway. – Chazt3n Dec 27 '16 at 23:34
  • 6
    @Ali, Jack - But I think this is preferable because it first checks if the data you are trying to delete actually exists which can prevent any trouble. The accepted answer has no check as such. – Uzair Khan Mar 20 '17 at 07:31
  • 5
    This is the better way. Think about it. What if John Smith is trying to remove an item with an id = 1 that Susie Smith removed 30 seconds ago but John doesn't know? You need to hit the database in that case. – Yusha Jan 09 '18 at 17:47
  • 8
    @Yusha Why? In both scenarios the outcome is that the record is gone. Do we really care if that happened now or 30 seconds ago? Some race conditions just aren't all that interesting to keep track of. – 9Rune5 Mar 12 '18 at 11:53
  • 2
    @9Rune5 Yes, we absolutely **care** about what happened as developers in a database whether it be 30 seconds ago or .0003 miliseconds ago. The data could be very sensitive. We need to know who did what and why. Better safe than sorry imo. Note that I am **not** saying your point isn't valid. I'm just defending my case for why I would use the above as a solution – Yusha Mar 12 '18 at 13:44
  • @Yusha, but: **1.** John fetches record with Id=1 => **2.** Susie then deletes record with Id=1 => **3.** John finally performs a Context.SaveChanges() 10ms **after** Susie... I do not believe SaveChanges() is going to complain in this scenario. I.e. you still have a race condition? AFAICT, given your stated requirement, the only way would be to run the DELETE by hand and see how many records were affected (1 record affected: OK, 0 records: Not OK). – 9Rune5 Mar 12 '18 at 19:03
14
  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();
Brian Webster
  • 30,033
  • 48
  • 152
  • 225
Alex G
  • 595
  • 6
  • 21
  • 3
    `FirstOrDefault` is dangerous. Either you know there's only one (so use `SingleOrDefault`), or there is more than one, and it should be done in a loop. – Mark Sowul Feb 06 '18 at 19:36
8
Employer employer = context.Employers.First(x => x.EmployerId == 1);

context.Customers.DeleteObject(employer);
context.SaveChanges();
Sam Leach
  • 12,746
  • 9
  • 45
  • 73
8

I am using entity framework with LINQ. Following code was helpful for me;

1- For multiple records

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

2- For Single record

 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
  • 6,011
  • 3
  • 50
  • 68
  • For Single record why not use `SingleOrDefault` instead of `FirstOrDefault`? – Mark Sowul Feb 06 '18 at 19:35
  • Whenever you use SingleOrDefault, you clearly state that the query should result in at most a single result. On the other hand, when FirstOrDefault is used, the query can return any amount of results but you state that you only want the first one https://stackoverflow.com/a/1745716/3131402 – Baqer Naqvi Feb 07 '18 at 10:47
  • 1
    Yes, so why would it be correct to delete an arbitrary record, if there is more than one? Particularly in this case the id is the key, so there should be one: if there is more than one, it is a bug (which Single would detect) – Mark Sowul Feb 07 '18 at 14:56
  • @MarkSowul you are right. I have edited the answer to use FirstOrDefault. – Baqer Naqvi Feb 07 '18 at 15:39
  • @BaqerNaqvi RemoveRange is terrible way to remove entity from the performance perspective.. Especially when your entity is heavy with all the navigational properties by foreign keys. I would rather use var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD= @your_parameter"; this.your_context.Database.ExecuteSqlCommand(sql, new SqlParameter("@your_parameter", yourParameter)); – curiousBoy Apr 24 '18 at 00:43
4

More generic approuch

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);
}
valentasm
  • 2,137
  • 23
  • 24
3

Just wanted to contribute the three methods I've bounced back and forth with.

Method 1:

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

Method 2:

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

One of the reasons why I prefer to go with Method 2 is because in the case of setting EF or EFCore to QueryTrackingBehavior.NoTracking, it's safer to do.

Then there's Method 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;

This utilizes a soft delete approach by setting the record's DeletedOn property, and still being able to keep the record for future use, what ever that may be. Basically, putting it in the Recycle Bin.


Also, in regards to Method 3, instead of setting the entire record to being modified:

entry.State = EntityState.Modified;

You would also simply set only the column DeletedOn as modified:

entry.Property(x => x.DeletedOn).IsModified = true;
LatentDenis
  • 2,839
  • 12
  • 48
  • 99
2

With Entity Framework 6, you can use Remove. Also it 's a good tactic to use using for being sure that your connection is closed.

using (var context = new EmployDbContext())
{
    Employ emp = context.Employ.Where(x => x.Id == id).Single<Employ>();
    context.Employ.Remove(emp);
    context.SaveChanges();
}
Gizmo
  • 31
  • 4
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);
        }
    }

What do you think of this, simple or not, you could also try this:

        var productrow = cnn.Product.Find(id);
        cnn.Product.Remove(productrow);
        cnn.SaveChanges();
Namroy
  • 99
  • 1
  • 3
0

For a generic DAO this worked:

    public void Delete(T entity)
    {
        db.Entry(entity).State = EntityState.Deleted;
        db.SaveChanges();
    }
Josh Gallagher
  • 5,211
  • 2
  • 33
  • 60
Tom Trnka
  • 56
  • 4
0

Using EntityFramework.Plus could be an option:

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

More examples are available here

0

u can do it simply like this

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

} 

view from which u will call it

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

i hope this will be easy for u to understand

0

You can do something like this in your click or celldoubleclick event of your grid(if you used one)

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

Then do something like this in your Delete Button:

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
}

Alternatively, you can use a LINQ Query instead of using LINQ To Entities Query:

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

employ.Id is used as filtering parameter which was already passed from the CellDoubleClick Event of your DataGridView.

  • The Idea behind the code is you wire the id(employ.Id) of the record you want to delete to the model(Employee Class) and then attach it to the actual Table from the Context then execute in-memory Remove() Method then finally execute actual saving to the database using SaveChanges() Method. Though the LINQ Query also works fine but I don't like the idea of querying to the table just to get the id of the record. – arvin aquio Dec 21 '18 at 05:53
0

Here's a safe way:

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

Here you can pile up all the changes you want, so you can do a series of deletion before the SaveChanges and Commit, so they will be applied only if they are all successful.

Emilio.NT
  • 81
  • 2
  • 4
0

The best way is to check and then delete

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
Sracanis
  • 490
  • 5
  • 25