5

У меня есть сценарий по умолчанию, где у вас есть Category себя, RootCategory и ChildCategories. Как я могу указать, что мой свободный модель-строитель каскадирует все дочерние категории при удалении?Как установить каскад на отношения со ссылками?

Модель
public class Category 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 

    public virtual Category RootCategory { get; set; } 
    public virtual ICollection<Category> ChildCategories { get; set; } 
    public virtual ICollection<Item> Items { get; set; } 
} 

То, что я пытался

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

Представляя ограничение внешнего ключа «» FK_dbo.Categories_dbo.Categories_RootCategory_Id на столе «Категории» может вызвать циклов или несколько путей каскада. Укажите ON УДАЛИТЬ НЕТ ДЕЙСТВИЙ или НЕ ОБНОВИТЬ НЕТ ДЕЙСТВИЙ, или изменить другие ограничения FOREIGN KEY .

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Category>().HasOptional(x => x.RootCategory).WithMany(x => x.ChildCategories).WillCascadeOnDelete(true); 
} 

ответ

0

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

Я думаю, вам нужно parentCategoryID Недвижимость в вашей модели. В этом случае у вас будут сильные отношения, и каскадное удаление должно работать.

EDITED: Я имею в виду, что если у вас есть parentCategoryID вы можете попытаться изменить код следующим образом:

modelBuilder.Entity<Category>().HasOptional(x => x.RootCategory).WithMany(x => x.ChildCategories).HasForeignKey(x => x.parentCategoryID).WillCascadeOnDelete(true); 
+0

Каким образом Parent_Id выставлен, решит проблему? Он уже имеет Parent_Id в базе данных, которую использует EF. – sed

+0

@Steve Я отредактировал свой ответ. –

0

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

У меня был объект комментария, который мог бы иметь ответы (другие комментарии), создавая «неограниченное дерево» комментариев.

Каждый комментарий имеет свой собственный идентификатор CommentID (первичный ключ), а также ParentID (внешний ключ, без CASCADE). Тогда я был триггер БД на моем замечании таблице:

CREATE TRIGGER [dbo].[Trigger_DeleteChildComments] 
ON [dbo].[Comment] 
FOR DELETE 
AS 
BEGIN 
    SET NoCount ON 
    DELETE FROM Comment WHERE ParentID IN (SELECT CommentID FROM DELETED) 
END 

(Или: «После удаления комментарий с, удалить все другие комментарии, которые имеют с как родитель.)

Обратите внимание, что это работает только потому, что моя бизнес-логика не позволяет «циклы» на этом графике комментариев, следя за тем, чтобы график оставался как дерево. Таким образом, я считаю, что мой триггер не вызывает бесконечных циклов.

4

У меня была такая же проблема. API configuraion, я не знаю, можете ли вы сделать это там. Что вы можете сделать, это установить для WillCascadeOnDelete значение false и просто удалить ChildCategories самостоятельно.

private void DeleteChildCategories(Category category) 
{ 
    foreach (Category subCategory in category.ChildCategories.ToList()) 
     { 
      if (subCategory.SubCategories.Count() > 0) 
      { 
       DeleteChildCategories(subCategory); 
      } 
      else 
      { 
       _db.Category.Remove(subCategory); 
      } 
     } 
    _db.Category.Remove(category); 
} 

Вы можете вызвать DeleteChildCategories при удалении Категории внутри действия вашего контроллера.

DeleteChildCategories(Category); 
_db.SaveChanges(); 

Надеюсь, это поможет.

Mark

+0

У меня такая же проблема, как и у OP, и это, скорее всего, решение, которое я в конечном итоге использую. –

+1

Согласно [this] (http://stackoverflow.com/questions/528529/self-referencing-constraint-in-ms-sql) вы не можете использовать каскадное удаление в собственной справочной таблице, ни с EF, ни с чисто T -SQL. У меня была та же проблема, и я также получил неэффективное рекурсивное удаление кода. – marce