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

196

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

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

user2497476
источник
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();
mt_serg
источник
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();
}
Mansfield
источник
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);
}
valentasm
источник
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();
}
Gizmo
источник
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;
LatentDenis
источник
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();
Namroy
источник
0

Использование EntityFramework.Plus может быть вариантом:

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

Больше примеров доступно здесь

Мухаммед Реза Садреддини
источник
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...
  }
}

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

Emilio.NT
источник
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();
    }
Том Трнка
источник