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

Posted

技术标签:

【中文标题】从实体框架中删除一条记录?【英文标题】:Delete a single record from Entity Framework? 【发布时间】:2013-07-17 09:25:15 【问题描述】:

我在实体框架中有一个名为 employ 的 SQL Server 表,其中有一个名为 ID 的键列。

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

【问题讨论】:

db.employ.Remove(db.employ.Find(ID1)) @CarterMedlin - 虽然这会起作用,但这是两个数据库命中:一个 SELECT 和一个 DELETE。大多数人认为这非常浪费,特别是因为选择可能比删除花费更多的时间。 由于性能问题,我不建议使用实体框架 Remove 或 RemoveRange。我宁愿只使用以下超级简单的东西: var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD= @your_parameter"; this.your_context.Database.ExecuteSqlCommand(sql, new SqlParameter("@your_parameter", yourParameter)); @curiousBoy 我认为当您执行您建议的语句时,EF6 缓存不会反映更改。 【参考方案1】:

不需要先查询对象,你可以通过它的 id 将它附加到上下文中。 像这样:

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

或者,您可以将附加条目的状态设置为已删除:

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

【讨论】:

或者,ctx.Entry(employer).State = EntityState.Deleted 这仅在关系被定义为删除级联时才有效。否则上面的代码将因 FK 异常而失败。 @mt_serg,我正在向前看 3 步。您最后一次真正不得不从数据库中删除如此简单的记录是什么时候?通常您正在处理包含 FK 关系的更复杂的记录。因此我的评论。 @IanWarburton 第二行和第三行(附加和删除) @PaulZahra:有时你有一个来自其他查询或来源的 ID 列表,你需要删除一个。而不是加载对象只是为了删除它们,这样您可以按 ID 删除。你知道,SQL 中的 DELETE 语句通常是这样工作的。【参考方案2】:

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

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

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

【讨论】:

这不是好办法,因为你是从数据库中选择所有字段! 我就是这样做的。 @Ali, Jack - 但我认为这更可取,因为它首先检查您尝试删除的数据是否确实存在,这可以防止任何麻烦。接受的答案本身没有检查。 这是更好的方法。想想看。如果 John Smith 试图删除 id = 1 的项目,Susie Smith 在 30 秒前删除了但 John 不知道怎么办?在这种情况下,您需要访问数据库。 @Yusha 为什么?在这两种情况下,结果都是记录消失了。我们真的关心这是现在还是 30 秒前发生的?跟踪某些比赛条件并不是那么有趣。【参考方案3】:
  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();

【讨论】:

FirstOrDefault 很危险。要么你知道只有一个(所以使用SingleOrDefault),或者有多个,应该循环完成。【参考方案4】:
Employer employer = context.Employers.First(x => x.EmployerId == 1);

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

【讨论】:

如果没有 ID 为 1 的对象,这会保护吗?不会抛出异常吗? @JackFairfield 我认为你应该检查空对象。并根据它执行删除。 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 无论何时使用 SingleOrDefault,您都清楚地表明查询最多只能产生一个结果。另一方面,当使用 FirstOrDefault 时,查询可以返回任意数量的结果,但您声明您只想要第一个 ***.com/a/1745716/3131402 是的,如果有多个记录,为什么删除任意记录是正确的?特别是在这种情况下,id 是关键,所以应该有一个:如果有多个,那就是一个错误(Single 会检测到) @MarkSowul 你是对的。我已经编辑了使用 FirstOrDefault 的答案。 @BaqerNaqvi RemoveRange 是从性能角度删除实体的糟糕方法。尤其是当您的实体因外键的所有导航属性而沉重时。我宁愿使用 var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD= @your_parameter"; this.your_context.Database.ExecuteSqlCommand(sql, new SqlParameter("@your_parameter", yourParameter));【参考方案6】:

更通用的方法

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

【讨论】:

【参考方案7】:

使用 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();

【讨论】:

【参考方案8】:

只是想贡献我反复使用的三种方法。

方法一:

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

方法二:

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;

【讨论】:

【参考方案9】:
    [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();

【讨论】:

【参考方案10】:

使用EntityFramework.Plus 可能是一种选择:

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

更多示例可here

【讨论】:

【参考方案11】:

你可以像这样简单地做到这一点

   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>

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

【讨论】:

【参考方案12】:

您可以在网格的 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 To Entities 查询:

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

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

【讨论】:

代码背后的想法是将要删除的记录的 id(employ.Id) 连接到模型(Employee Class),然后将其附加到上下文中的实际表,然后执行内存中的 Remove() 方法最后使用 SaveChanges() 方法执行实际保存到数据库。虽然 LINQ 查询也可以正常工作,但我不喜欢查询表只是为了获取记录的 id 的想法。【参考方案13】:

这是一个安全的方法:

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之前做一系列的删除,所以只有全部成功才会应用。

【讨论】:

【参考方案14】:

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

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

【讨论】:

【参考方案15】:

对于一个通用的 DAO,这是可行的:

    public void Delete(T entity)
    
        db.Entry(entity).State = EntityState.Deleted;
        db.SaveChanges();
    

【讨论】:

以上是关于从实体框架中删除一条记录?的主要内容,如果未能解决你的问题,请参考以下文章

试图从父实体java类中删除记录

如何在实体框架中循环创建和删除记录

当我删除核心数据实体的最后一条记录时,为啥我的应用程序崩溃了?

使用实体框架中的可选记录级联删除

如何使用 LINQ 仅从实体加载最后一条记录?

实体框架分离实体和相关实体消失