从实体框架中删除一条记录?


195

我在实体框架中有一个SQL Server表,该表命名employ为一个名为ID

如何使用Entity Framework从表中删除一条记录?


2
db.employ.Remove(db.employ.Find(ID1))
卡特·

2
@CarterMedlin-虽然可以使用,但是有两个数据库命中:一个SELECT和一个DELETE。大多数人发现这非常浪费,特别是因为select可能比删除花费更多的时间。
Davor

由于性能问题,我不建议使用实体框架Remove或RemoveRange。我宁愿使用以下超级简单的方法:var sql =“从YOUR_TABLE删除,而YOUR_FIELD = @your_parameter”; this.your_context.Database.ExecuteSqlCommand(sql,new SqlParameter(“ @ your_parameter”,yourParameter));
curiousBoy '18

2
@curiousBoy我认为执行建议的语句时,EF6缓存不会反映出更改。
Yitzchak

Answers:


362

不必先查询对象,您可以通过其ID将其附加到上下文。像这样:

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

另外,您可以将附加条目的状态设置为Deleted:

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

87
或者,ctx.Entry(employer).State = EntityState.Deleted
西蒙贝朗格

12
仅当关系定义为删除级联时,这才起作用。否则,上面的代码将因FK异常而失败。
baruchl 2014年

6
@mt_serg,我正在寻找3个步骤。您上一次真正必须从数据库中删除这样一个简单记录的时间是什么时候?通常,您正在处理包含FK关系的更复杂的记录。因此,我的评论。
baruchl 2014年

2
@IanWarburton第二和第三行(附加和删除)
Simon Belanger

4
@PaulZahra:有时您有一些来自其他查询或来源的ID列表,您需要删除一个ID。这样就可以按ID删除,而不是仅加载对象来删除它们。您知道,这就是DELETE语句在SQL中正常工作的方式。
siride '16

82

您可以SingleOrDefault用来获取与您的条件匹配的单个对象,然后将其传递给RemoveEF表的方法。

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

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

5
这不是一个好方法,因为您要从数据库中选择所有字段!
阿里·尤塞菲

2
这就是我的方法。
杰克·费尔菲尔德

4
@Ali,Jack-但我认为这是可取的,因为它首先检查您要删除的数据是否确实存在,这可以防止任何麻烦。接受的答案本身没有检查。
迈克尔·菲利普

4
这是更好的方法。想一想。如果John Smith试图删除id为1的商品,而Susie Smith则在30秒前删除了该商品,但John不知道该怎么办?在这种情况下,您需要访问数据库。
Yusha

4
@Yusha为什么?在这两种情况下,结果都是记录消失了。我们真的在乎是现在还是30秒钟前发生这种情况?某些比赛条件并不是很有趣。
9Rune5,11

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
FirstOrDefault是危险的。您要么知道只有一个(所以请使用SingleOrDefault),要么不止一个,应该循环执行。
Mark Sowul '18

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

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

如果没有带有ID 1的对象,这是否可以保护?它不会抛出异常吗?
杰克·费尔菲尔德

@JackFairfield我认为您应该检查空对象。并根据它执行删除。
Jawand Singh

First是危险的。您要么知道只有一个(所以请使用Single),要么知道不止一个,应该循环执行。
马克索沃

5

我在LINQ中使用实体框架。以下代码对我有帮助;

1-对于多个记录

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

2-对于单记录

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

对于单记录,为什么不使用SingleOrDefault代替FirstOrDefault
Mark Sowul '18

每当您使用SingleOrDefault时,您都明确声明该查询最多只能产生一个结果。另一方面,使用FirstOrDefault时,查询可以返回任意数量的结果,但您声明只希望第一个stackoverflow.com/a/1745716/3131402
Baqer Naqvi

1
是的,因此,如果有多个记录,那么删除任意记录为什么正确呢?特别是在这种情况下,id是密钥,因此应该有一个:如果有多个,则是bug(Single会检测到)
Mark Sowul

@MarkSowul你是对的。我已编辑答案以使用FirstOrDefault。
Baqer Naqvi

@BaqerNaqvi RemoveRange是从性能角度删除实体的糟糕方法。尤其是当您的实体因外键具有所有导航属性而变得笨重时。我宁愿使用var sql =“从YOUR_TABLE中删除,而YOUR_FIELD = @your_parameter”; this.your_context.Database.ExecuteSqlCommand(sql,new SqlParameter(“ @ your_parameter”,yourParameter));
curiousBoy

2

更通用的方法

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

在Entity Framework 6中,您可以使用Remove。同样,使用一种很好的策略来using确保您的连接已关闭。

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

1

只是想贡献我来回弹跳的三种方法。

方法1:

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

方法2:

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

我更喜欢使用方法2的原因之一是因为在将EF或EFCore设置为的情况下QueryTrackingBehavior.NoTracking,这样做更安全。

然后是方法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;

这可以通过设置记录的DeletedOn属性来使用软删除方法,并且仍然可以保留记录以备将来使用,无论如何。基本上,将其放入回收站


另外,关于方法3,不是将整个记录设置为要修改:

entry.State = EntityState.Modified;

您还可以仅将列设置DeletedOn为已修改:

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

您如何看待这个问题(无论是否简单),也可以尝试以下操作:

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

0

对于通用DAO,我的工作最终是这样的:

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


0

你可以像这样简单地做

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

模型

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

} 

查看您会从中调用的视图

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

我希望这对您来说很容易理解


0

您可以在网格的click或celldoubleclick事件中执行类似的操作(如果使用过)

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

然后在“删除”按钮中执行以下操作:

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
}

或者,您可以使用LINQ查询而不是LINQ到实体查询:

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

employee.Id用作已从DataGridView的CellDoubleClick事件传递的过滤参数。


代码背后的想法是,您将要删除的记录的id(employ.Id)连接到模型(Employee Class),然后将其从Context附加到实际的Table,然后执行内存中的Remove()方法,然后最后使用SaveChanges()方法执行实际保存到数据库的操作。尽管LINQ查询也可以正常工作,但是我不喜欢仅查询表的ID以获取记录ID的想法。
arvin aquio '18

0

这是一种安全的方法:

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

在这里,您可以堆积所需的所有更改,因此可以在SaveChanges和Commit之前进行一系列删除,因此只有在所有更改成功后才应用它们。


0

最好的方法是先检查然后删除

        if (ctx.Employ.Any(r=>r.Id == entity.Id))
        {
            Employ rec = new Employ() { Id = entity.Id };
            ctx.Entry(rec).State = EntityState.Deleted;
            ctx.SaveChanges();
        }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.