Как автоматически удалить дочерний элемент на основе удаления родителя для первого подхода к базе данных (.edmx)?

Ниже приведены мои 2 класса, разделяющие отношения от 1 до многих:

public partial class Employee
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual ICollection<Skills> Skills { get; set; }
}

public partial class Skills
{
    public int Id { get; set; }
    public Nullable<int> EmployeeId { get; set; }
    public string Skills { get; set; }
    public virtual Employee Employee { get; set; }
}

Теперь я пытаюсь удалить сотрудников с соответствующими навыками следующим образом:

1) Удаление как сотрудника, так и навыков одним методом с сохранением только изменений. Я предполагаю, что в этом случае у меня будет преимущество в производительности, так как мне нужно вызвать сохранение изменений только один раз, но есть также 1 проблема: если навыки были удалены, но если при удалении сотрудника возникает ошибка, в этом случае я буду потерять Навыки соответствующего Сотрудника.

public void Delete(int[] ids)
{
    using (var context = new MyEntities())
    {
        context.Skills.RemoveRange(context.Skills.Where(cd => ids.Contains(cd.EmployeeId)));
        context.Employee.RemoveRange(context.Employee.Where(t => ids.Contains(t.Id)));
        context.SaveChanges();
    }
}

2) Другой вариант — использовать транзакцию, чтобы убедиться, что оба и дочерние элементы успешно удалены, как показано ниже:

public HttpResponseMessage Delete(int[] ids)
{ 
    using (var context = new MyEntities())
    {
        using (var transaction = context.Database.BeginTransaction())
        {
            try
            { 
                DeleteSkills(ids,context);
                DeleteEmployees(ids,context);
                transaction.Commit();
            }
            catch (Exception ex)
            {
                transaction.Rollback();
                // throw exception.
            }
        }
    }
}

public void DeleteEmployees(int[] ids,MyEntities _context)
{
    _context.Employee.RemoveRange(_context.Employee.Where(t => ids.Contains(t.Id)));
    _context.SaveChanges();
}

public void DeleteSkills(int[] ids, MyEntities _context)
{
    _context.Skills.RemoveRange(_context.Skills.Where(cd => ids.Contains(cd.EmployeeId)));
    _context.SaveChanges();
}

3) Я ищу вариант, при котором мне не нужно явно удалять дочерний элемент (навыки), а дочерний элемент удаляется автоматически на основе удаления родительского (сотрудника) объекта, как это происходит в случае первого каскадного кода при удалении, чтобы Мне не нужно запускать 2 запроса для удаления родительского и дочернего элементов (мой первый вариант) или мне не нужно поддерживать транзакцию (мой второй вариант).

Я провел некоторое исследование, но не смог найти никакой помощи по автоматическому удалению дочерних элементов на основе удаления родителя в случае первого подхода к базе данных (.edmx).

Каков эффективный способ справиться с этим сценарием?


person Learning-Overthinker-Confused    schedule 27.09.2017    source источник
comment
Я считаю, что DbContext.SaveChanges сам использует транзакцию, поэтому вам не нужно беспокоиться о частичном удалении в случае 1   -  person Sam I am says Reinstate Monica    schedule 27.09.2017
comment
Почему бы не использовать поведение SQL Cascade для удаления, подобное этому stackoverflow.com/a/37459049/2946329   -  person Salah Akbari    schedule 27.09.2017
comment
Привет Обучение. Я заметил ряд проблем с вашими сообщениями, которых можно было бы избежать с помощью небольших изменений. Не могли бы вы ответить на эти пункты, пожалуйста? (1) говоря о себе, пожалуйста, всегда используйте заглавную I. Читатели-носители английского языка, как правило, находят довольно раздражающим чтение i, и эта реакция на легкое разочарование может помешать им помочь. (2) Слова не, не мог, не, не имеет и т. д. все имеют апостроф перед последней буквой. Сможете ли вы добавить это при вводе или включить автокоррекцию на своем компьютере?   -  person halfer    schedule 27.09.2017
comment
(3) К каждому из ваших вопросов неукоснительно добавляется вопрос: кто-нибудь может мне помочь? Ответ на это, как правило, просто да, конечно, но это не тот ответ, который вы ищете. Статья Почему "Кто-нибудь может мне помочь? ” не актуальный вопрос? поможет здесь. Если вы можете заменить эту фразу более конкретным вопросом, это здорово, в противном случае, пожалуйста, просто оставьте это. Спасибо!   -  person halfer    schedule 27.09.2017
comment
Почему этот вопрос был вновь открыт? Я думаю, что предложенный дубликат был точным. Если нет, как насчет этого? Важнейшей частью является то, что для FK в базе данных должно быть указано каскадное удаление.   -  person Gert Arnold    schedule 28.09.2017
comment
@halfer Я действительно очень прошу прощения за неудобства, но на самом деле я всегда спешу задать вопрос и решить свою проблему как можно быстрее из-за крайнего срока, поэтому, публикуя вопрос, я не проверяю эти мелкие вещи должным образом.   -  person Learning-Overthinker-Confused    schedule 28.09.2017
comment
@halferПричина, по которой я всегда говорю, может кто-нибудь, пожалуйста, помогите мне в моем вопросе, это просто просьба к пользователям SO помочь мне.   -  person Learning-Overthinker-Confused    schedule 28.09.2017
comment
@Learning: пожалуйста, попробуйте хотя бы частично принять мой совет, хотя бы для того, чтобы уменьшить объем работы, которую вы на постоянной основе даете редакторам-добровольцам. Спасибо.   -  person halfer    schedule 28.09.2017
comment
@S.Akbari: На самом деле я еще не пробовал, но при поиске каскадного удаления я узнал о проблеме с круговыми каскадными путями, связанной с этой опцией.   -  person Learning-Overthinker-Confused    schedule 28.09.2017


Ответы (2)


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

Таким образом, EF по умолчанию включает эффект каскадного удаления для всех сущностей.

Если вы хотите вручную обрабатывать, вы можете использовать:

 .WillCascadeOnDelete(false);


 protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<parent>()
            .HasOptional<child>(c => c.child)
            .WithMany()
            .WillCascadeOnDelete(false);
    }
person Community    schedule 30.06.2020

Прочтите о поведении при удалении в Entity Framework.

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

В вашем случае вам нужно поведение каскадного удаления, которое автоматически удаляет дочерние элементы/зависимые объекты, которые вы удаляете.

Сделайте это так в своем методе OnModelCreating:

 protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PARENT>()
             .........
            .OnDelete(DeleteBehavior.Cascade);
    }

Посмотрите здесь, как использовать и что это такое:

https://entityframeworkcore.com/saving-data-cascade-delete#:%7E:text=Entity%20Framework%20Core%20Cascade%20Delete&text=Cascade%20delete%20позволяет%20%20удаление,удаление%20поведений%20of%20individual%20relationships.

person Flori Bruci    schedule 30.06.2020