Удаление нескольких записей для связанной таблицы - PullRequest
1 голос
/ 11 апреля 2011

В моей базе данных есть две таблицы с именами Vendors и VendorPriceBreaks:

Vendors
-----------------
VendorID (PK)
Name

VendorPriceBreaks
-----------------
VendorPriceBreakID (PK)
VendorID (FK)
Price

Когда я удаляю Vendor, я хотел бы также удалить все связанные с ним VendorPriceBreaks. Я использую Entity Framework.

Сначала я попробовал:

public RedirectToRouteResult Delete(int id)
{
    MyEntities entities = new MyEntities();

    var vendor = entities.Vendors.FirstOrDefault(v => v.VendorID == id);
    entities.Vendors.Context.DeleteObject(vendor);
    entities.Vendors.Context.SaveChanges();

    return RedirectToAction("Index");
}

, который дал мне сообщение об ошибке: Оператор DELETE конфликтовал с ограничением REFERENCE "FK_VendorPriceBreaks_Vendors"

Итак, я добавил эту строку перед удалением моего объекта: vendor.VendorPriceBreaks.Clear();

Но затем я получил это сообщение об ошибке: Операция завершилась неудачно: отношение не может быть изменено, так как одно или несколько свойств внешнего ключа не могут иметь значение null. Когда в отношение вносится изменение, для соответствующего свойства внешнего ключа устанавливается нулевое значение. Если внешний ключ не поддерживает нулевые значения, необходимо определить новое отношение, свойству внешнего ключа должно быть присвоено другое ненулевое значение или несвязанный объект должен быть удален.

Какой лучший способ сделать это?

Ответы [ 4 ]

2 голосов
/ 11 апреля 2011

Вы можете «включить» ваши дочерние сущности.

var vendor = entities.Vendors
                     .Include("VendorPriceBreaks")
                     .FirstOrDefault(v => v.VendorID == id);

Кроме того, вы можете изменить свойство отношений между двумя сущностями в конструкторе .edmx.

enter image description here

1 голос
/ 11 апреля 2011

Другие ребята уже предоставили ценные ответы, поэтому вы должны выбрать один из них в качестве принятых ответов.

Я просто добавляю это как ответ, потому что это слишком долго для комментария.Обычно этого можно достичь четырьмя способами:

Casade delete, как описано в @ p.campbell.Важно определить ON CASCADE DELETE для отношения в базе данных, а также Cascade для отношения в конструкторе EF. Здесь является причиной, по которой опция должна быть установлена ​​с обеих сторон.

Хранимая процедура, как описано @Bilgehan.На всякий случай хранимой процедуры удалите потомки перед родителем.Вы можете фактически выполнить SQL напрямую с помощью ExecuteStoreCommand.

Идентифицирующее отношение - это одно из самых странных решений для архитекторов в EF.Это требует, чтобы дочерняя сущность имела составной ключ от своего уникального идентификатора и FK до родительского.Если это произойдет, вы можете просто позвонить vendor.VendorPriceBreaks.Clear(), и он не только удалит отношения, но и удалит дочерние элементы.Недостатком является то, что связанные объекты должны быть загружены из базы данных.

Ручное удаление связанных объектов, как описано @Slauma.Если у вас нет каскадного удаления, хранимой процедуры или идентифицирующего отношения, другого способа нет, чем загрузить связанные объекты и удалить их один за другим.

1 голос
/ 11 апреля 2011

Я думаю, вам следует создать процедуру:

Create proc DeleteRecords
@VendorID int       
As
BEGIN TRY
    BEGIN TRAN
           DELETE FROM VendorPriceBreaks
        WHERE VendorID =@VendorID
        DELETE FROM Vendors
        WHERE VendorID =@VendorID        
    COMMIT TRAN
END TRY
BEGIN CATCH
  ROLLBACK TRAN
END CATCH

И после того, как вы сможете добавить этот процесс в вашу entityFramwork как функцию.

счастливое кодирование

1 голос
/ 11 апреля 2011

Если вы не включили каскадное удаление в базе данных (я думаю, это было бы лучшим вариантом в вашей модели; см. Ответ p.campbell), вы должны явно удалить элементы в коллекции:

public RedirectToRouteResult Delete(int id)
{
    MyEntities entities = new MyEntities();

    var vendor = entities.Vendors.FirstOrDefault(v => v.VendorID == id);
    foreach (var item in vendor.VendorPriceBreaks.ToList())
        entities.VendorPriceBreaks.Context.DeleteObject(item);
    entities.Vendors.Context.DeleteObject(vendor);
    entities.Vendors.Context.SaveChanges();

    return RedirectToAction("Index");
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...