Как настроить cascade delete в Entity Framework?

Собственно вопрос в заголовке. Есть класс
public class Partiya
    {
        [Key]
        [Column("NOMERPARTII")]
        public int NomerPartii { get; set; }

        [Column("KOLICHESTVO")]
        public int? Kolichestvo { get; set; }

        public virtual List<Zakupki> Zakupki { get; set; }
        public virtual List<Zakladki> Zakladki { get; set; }
        public virtual List<Vivod> Vivod { get; set; }
        public virtual List<Prodagi> Prodagi { get; set; }
    }
и связанные с ними классы
public class Zakladki
    {
        [Key]
        [Column("INDEXZAKLADKI")]
        public int IndexZakladki { get; set; }

        [Column("DATEZAKLADKI")]
        public DateTime DateZakladki { get; set; }

        [Column("PARTIYA")]
        public int PartiyaID { get; set; }

        [ForeignKey("PartiyaID")]
        public virtual Partiya Partiya { get; set; }

    }
 [Table("ZAKUPKI")]
    public class Zakupki
    {
        [Key]
        [Column("INDEXZAKUPKI")]
        public int IndexZakupki { get; set; }

        [Column("OTKUDA")]
        public int AdressesID { get; set; }

        [Column("KOLICHESTVO")]
        public int Kolichestvo { get; set; }

        [Column("PARTIYA")]
        public int PartiyaID { get; set; }

        [ForeignKey("PartiyaID")]
        public Partiya Partiya { get; set; }

        [ForeignKey("AdressesID")]
        public virtual Adresses Adresses { get; set; }
    }
public class Vivod
    {
        [Key]
        [Column("INDEXVIVODA")]
        public int IndexVivoda { get; set; }

        [Column("DATEVIVODA")]
        public DateTime DateVivoda { get; set; }

        [Column("PARTIYA")]
        public int PartiyaID { get; set; }

        [ForeignKey("PartiyaID")]
        public virtual Partiya Partiya { get; set; }
    }
    public class Prodagi
    {
        [Key]
        [Column("INDEXPRODAGI")]
        public int IndexProdagi { get; set; }

        [Column("DATEPRODAGI")]
        [DataType(DataType.Date)]
        public DateTime DateProdagi { get; set; }

        [Column("PARTIYA")]
        public int PartiyaID { get; set; }

        [ForeignKey("PartiyaID")]
        public virtual Partiya Partiya { get; set; }
    }

С EF знакомство только начинаю, насколько понял для того чтобы воспользоваться каскадным удалением, нужно использовать fluent api. У себя в контексте попытался это реализовать:
public class BirdKeepingDBContext : DbContext
    {
        public DbSet<Adresses> Adresses { get; set; }
        public DbSet<Partiya> Partiya { get; set; }
        public DbSet<Zakupki> Zakupki { get; set; }
        public DbSet<Zakladki> Zakladki { get; set; }
        public DbSet<Vivod> Vivod { get; set; }
        public DbSet<Prodagi> Prodagi { get; set; }
        public DbSet<Itogi> Itogi { get; set; }

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Adresses>()
                .ToTable("ADRESSES", "PTICA");
            modelBuilder.Entity<Zakupki>()
                .ToTable("ZAKUPKI", "PTICA");

            modelBuilder.Entity<Zakladki>()
                .ToTable("ZAKLADKI", "PTICA");
            modelBuilder.Entity<Vivod>()
                .ToTable("VIVOD", "PTICA");
            modelBuilder.Entity<Prodagi>()
                .ToTable("PRODAGI", "PTICA");
            modelBuilder.Entity<Itogi>()
                .ToTable("ITOGI", "PTICA");
            modelBuilder.Entity<Partiya>()
                .ToTable("PARTIYA", "PTICA");
            modelBuilder.Entity<Partiya>()
                .HasMany(p => p.Vivod)
                .WithRequired(v => v.Partiya)
                .WillCascadeOnDelete(true);
            modelBuilder.Entity<Partiya>()
                .HasMany(p => p.Prodagi)
                .WithRequired(p => p.Partiya)
                .WillCascadeOnDelete(true);
            modelBuilder.Entity<Partiya>()
                .HasMany(p => p.Zakladki)
                .WithRequired(z => z.Partiya)
                .WillCascadeOnDelete(true);
            modelBuilder.Entity<Partiya>()
                .HasMany(p => p.Zakupki)
                .WithRequired(z => z.Partiya)
                .WillCascadeOnDelete(true);

        }
    }

но когда пытаюсь удалить партию
BirdKeepingDBContext context = new BirdKeepingDBContext();
            if (ModelState.IsValid)
            {
                
                context.Partiya.Remove(context.Partiya.Single(p => p.NomerPartii == partiya.NomerPartii));
                context.SaveChanges();
            }
все равно вылетает ошибка child record found, при попытке сохранить изменения.
Либо я неправильно в контексте что-то связал, или с атрибутами что-то не то, где то читал что если связывать в контексте, то атрибуты не используются? В общем прошу подкинуть идей в чем может быть причина и как-нибудь на пальцах объяснить, когда и для чего fluent api используется?
  • Вопрос задан
  • 1496 просмотров
Решения вопроса 1
@zakar1ya Автор вопроса
Junior
После долгого чтения мануалов по fluent api, оказалось что дело совсем в другом.
Fluent api поддерживает cascade delete по умолчанию, проблема была в том, что нажимая "удалить", представление передавало контроллеру сущность в которой поля
public virtual List<Zakupki> Zakupki { get; set; }
        public virtual List<Zakladki> Zakladki { get; set; }
        public virtual List<Vivod> Vivod { get; set; }
        public virtual List<Prodagi> Prodagi { get; set; }
, то есть навигационные свойства были null.
Соответственно EF не мог удалить связанные записи потому что не знал какие, до тех пор пока я вручную не включил их в выборку
[HttpPost]
        public ActionResult Delete(Partiya partiya)
        {
            BirdKeepingDBContext context = new BirdKeepingDBContext();
            if (ModelState.IsValid)
            {
                Partiya part = context.Partiya
                    .Include("Zakupki")
                    .Include("Zakladki")
                    .Include("Vivod")
                    .Include("Prodagi")
                    .Single(p => p.NomerPartii == partiya.NomerPartii);
                context.Partiya.Remove(part);
                context.SaveChanges();
            }

            return View(partiya);
        }

Остался небольшой вопрос, Include требует строку с именем связанного объекта, но напрямую прописывать, как у меня, как-то не хорошо. Как это лучше записать и вообще может есть конструкции получше чем эта?
context.Partiya
                    .Include("Zakupki")
                    .Include("Zakladki")
                    .Include("Vivod")
                    .Include("Prodagi")
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
Используйте лябды вместо строк
context.Partiya
                    .Include(x => x.Zakupki)
                    .Include(x => x.Zakladki)
                    .Include(x => x.Vivod)
                    .Include(x => x.Prodagi)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы