Удалить одну запись из Entity Framework?


196

У меня есть таблица SQL Server в Entity Framework, названная employс одним ключевым столбцом ID.

Как удалить одну запись из таблицы, используя Entity Framework?


2
db.employ.Remove (db.employ.Find (ID1))
— Картер Медлин

2
@CarterMedlin - пока это будет работать, это два попадания в базу данных: один SELECT и один DELETE. Большинство людей считают это чрезвычайно расточительным, особенно потому, что выбор, вероятно, займет значительно больше времени, чем удаление.
— Давор

Я бы не предложил использовать каркас сущностей Remove или RemoveRange из-за проблем с производительностью. Я бы предпочел просто использовать что-то очень простое, например: var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, новый SqlParameter ("@ your_parameter", yourParameter));
— curiousBoy

2
@curiousBoy Я думаю, что когда вы выполняете операторы, как вы предлагали, кэш EF6 не отражает изменения.
— Ицхак

Ответы:


362

Нет необходимости сначала запрашивать объект, вы можете присоединить его к контексту по его идентификатору. Как это:

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

87
В качестве альтернативы,ctx.Entry(employer).State = EntityState.Deleted
— Симон Белангер

12
это будет работать, только если отношения определены как каскад удаления. в противном случае приведенный выше код завершится с ошибкой FK.
— Барухль

6
@mt_serg, я смотрю на 3 шага впереди. когда в последний раз вам действительно пришлось удалить такую ​​простую запись из БД? обычно вы имеете дело с более сложными записями, которые включают отношения FK. отсюда мой комментарий.
— Барухль

2
@IanWarburton 2-я и 3-я строки (присоединить и удалить)
— Саймон Белэнджер

4
@PaulZahra: иногда у вас есть список идентификаторов из какого-либо другого запроса или источника, и вам нужно удалить один. Вместо того, чтобы загружать объекты, просто чтобы удалить их, вы можете удалить их по идентификатору. Вы знаете, вот как оператор DELETE работает в SQL нормально.
— Сирида

83

Вы можете использовать, SingleOrDefaultчтобы получить один объект, соответствующий вашим критериям, а затем передать его в Removeметод вашей таблицы EF.

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
@ Али, Джек - Но я думаю, что это предпочтительнее, потому что сначала проверяется, существуют ли данные, которые вы пытаетесь удалить, на самом деле, что может предотвратить любые проблемы. Принятый ответ не имеет проверки как таковой.
— Майкл Филипс

4
Это лучший способ. Подумай об этом. Что если Джон Смит пытается удалить элемент с идентификатором = 1, который Сьюзи Смит удалила 30 секунд назад, но Джон не знает? Вы должны поразить базу данных в этом случае.
— Юша

5
@ Юша Почему? В обоих случаях результат заключается в том, что запись исчезла. Мы действительно заботимся, произошло ли это сейчас или 30 секунд назад? Некоторые гоночные условия не так интересны, чтобы их отслеживать.
— июня 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
FirstOrDefaultопасный. Либо вы знаете, что есть только один (так что используйте SingleOrDefault), либо их больше одного, и это должно быть сделано в цикле.
— Марк Совул

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

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

Защищает ли это, если нет объекта с Id 1? Разве это не исключение?
— Джек Фэйрфилд

@JackFairfield Я думаю, вы должны проверить нулевой объект. и в соответствии с этим выполнить удаление.
— Джаванд Сингх,

Firstопасный. Либо вы знаете, что есть только один (так что используйте Single), либо их больше одного, и это должно быть сделано в цикле.
— Марк Совул

5

Я использую Entity Framework с 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, запрос может вернуть любое количество результатов, но вы утверждаете, что вам нужен только первый stackoverflow.com/a/1745716/3131402
— Baqer Naqvi

1
Да, так почему было бы правильно удалить произвольную запись, если их больше одной? В частности, в этом случае ключ является идентификатором, поэтому он должен быть один: если их больше одного, это ошибка (которую может обнаружить Single)
— Марк Соул

@MarkSowul ты прав. Я отредактировал ответ, чтобы использовать FirstOrDefault.
— Бакер Накви

@BaqerNaqvi RemoveRange - это ужасный способ удалить объект с точки зрения производительности. Особенно, когда ваш объект имеет большой объем всех навигационных свойств с помощью внешних клавиш. Я бы лучше использовал var sql = "DELETE FROM YOUR_TABLE WHERE YOUR_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, новый 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

ты можешь сделать это просто так

   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 Query вместо LINQ To Entities Query:

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

employee.Id используется в качестве параметра фильтрации, который уже был передан из события CellDoubleClick вашего DataGridView.


Идея, лежащая в основе кода, заключается в том, что вы связываете id (employee.Id) записи, которую вы хотите удалить, с моделью (классом Employee), а затем присоединяете ее к фактической таблице из контекста, затем выполняете метод удаления () в памяти, а затем наконец, выполните фактическое сохранение в базу данных с помощью метода SaveChanges (). Хотя LINQ Query также работает нормально, но мне не нравится идея запроса к таблице только для получения идентификатора записи.
— Арвин Акио

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

Здесь вы можете накапливать все необходимые изменения, поэтому вы можете выполнить серию удалений перед сохранением изменений и фиксацией, поэтому они будут применены только в том случае, если все они будут успешными.


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

0

Для общего DAO это сработало:

    public void Delete(T entity)
    {
        db.Entry(entity).State = EntityState.Deleted;
        db.SaveChanges();
    }
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.