Видалити один запис із Entity Framework?


195

У мене в Entity Framework є таблиця SQL Server з ім'ям employодного стовпчика ключів ID.

Як видалити один запис із таблиці за допомогою Entity Framework?


2
db.employ.Remove (db.employ.Find (ID1))
Carter Medlin

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

Я б не пропонував використовувати сутнісні рамки Remove або RemoveRange через проблеми з продуктивністю. Я б скоріше просто скористався чимось надзвичайно простим: var sql = "ВИДАЛИТИ З ВАШОГО ТАБЛИЦІ, КОГО ВАШ_FIELD = @your_parameter"; this.your_context.Database.ExecuteSqlCommand (sql, новий SqlParameter ("@ ваш_параметр", вашParameter));
цікавоБой

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

6
@mt_serg, я дивлюсь на 3 кроки вперед. коли останній раз вам справді довелося видалити такий простий запис із БД? зазвичай ви маєте справу зі складнішими записами, що включають відносини FK. звідси мій коментар.
baruchl

2
@IanWarburton 2-й та 3-й рядки (Вкласти та видалити)
Саймон Белангер

4
@PaulZahra: іноді у вас є список ідентифікаторів з якогось іншого запиту чи джерела, і його потрібно видалити. Замість того, щоб завантажувати об'єкти просто для їх видалення, таким чином ви можете видалити за ідентифікатором. Ви знаєте, так нормально працює оператор DELETE в SQL.
siride

82

Ви можете використовувати 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
@Ali, Джек - Але я вважаю, що це є кращим, оскільки він спочатку перевіряє, чи існують дані, які ви намагаєтесь видалити, що може запобігти будь-які проблеми. У прийнятій відповіді немає перевірки як такої.
Майкл Філіпс

4
Це кращий спосіб. Подумай над цим. Що робити, якщо Джон Сміт намагається видалити предмет з id = 1, який Сьюзі Сміт видалила 30 секунд тому, але Джон не знає? У цьому випадку вам потрібно натиснути на базу даних.
Юша

4
@Yusha Чому? В обох сценаріях підсумок полягає в тому, що запис уже немає. Чи нас справді хвилює, чи це сталося зараз або 30 секунд тому? Деякі умови гонки просто не так цікаво відстежувати.
9Rune5

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 Я думаю, ви повинні перевірити нульовий об'єкт. і відповідно до нього виконайте видалення.
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?
Марк Совул

Щоразу, коли ви використовуєте SingleOrDefault, ви чітко заявляєте, що запит повинен мати максимум один результат. З іншого боку, коли FirstOrDefault використовується, запит може повертати будь-яку кількість результатів , але ви заявляєте , що ви хочете тільки перший stackoverflow.com/a/1745716/3131402
Бакер Naqvi

1
Так, то чому б було правильним видаляти довільний запис, якщо їх більше? Особливо в цьому випадку ідентифікатор є ключовим, тому має бути такий: якщо їх більше, це помилка (яку виявить Single)
Марк Совул

@MarkSowul ви праві. Я відредагував відповідь, щоб використовувати FirstOrDefault.
Baqer Naqvi

@BaqerNaqvi RemoveRange - це жахливий спосіб видалення об'єкта з точки зору продуктивності. Особливо, коли ваша сутність є важкою з усіма навігаційними властивостями за допомогою іноземних ключів. Я б скоріше скористався var sql = "ВІДКЛЮЧИТИ З ВАШОГО ТАБЛИЦІ, ЩО ВАШ_FIELD = @ ваш_параметр"; this.your_context.Database.ExecuteSqlCommand (sql, новий SqlParameter ("@ ваш_параметр", вашParameter));
цікавоБой

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>

Я сподіваюся, що це буде легко зрозуміти і u


0

Ви можете зробити щось подібне в події клацання або натискання клітинки вашої сітки (якщо ви використовували таке)

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 для Entity Query:

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

zapos.Id використовується як параметр фільтрації, який вже переданий з події CellDoubleClick вашого DataGridView.


Ідея коду полягає в тому, щоб ви вказали ідентифікатор (zapos.Id) запису, який ви хочете видалити, до моделі (Class Employee Class), а потім приєднаєте її до фактичної таблиці з контексту, а потім виконайте методом Remove () в пам'яті нарешті виконати фактичне збереження в базі даних методом SaveChanges (). Хоча LINQ Query також працює чудово, але мені не подобається ідея запиту до таблиці, щоб отримати ідентифікатор запису.
arvin aquio

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 and 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();
        }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.