S
S
Sergey Konovalov2015-09-18 18:35:29
ASP.NET
Sergey Konovalov, 2015-09-18 18:35:29

How to setup cascade delete in Entity Framework?

Actually the question is in the title. There is a class

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; }
    }
and related classes
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; }
    }

I am just starting to get acquainted with EF, as far as I understand, in order to use cascade deletion, you need to use fluent api. I tried to implement this in my context:
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);

        }
    }

but when i try to delete the batch
BirdKeepingDBContext context = new BirdKeepingDBContext();
            if (ModelState.IsValid)
            {
                
                context.Partiya.Remove(context.Partiya.Single(p => p.NomerPartii == partiya.NomerPartii));
                context.SaveChanges();
            }
the child record found error still occurs when trying to save the changes.
Either I connected something incorrectly in the context, or something is wrong with the attributes, where did I read that if you bind in the context, then the attributes are not used? In general, I ask you to throw in ideas what could be the reason and somehow explain on your fingers when and why the fluent api is used?

Answer the question

In order to leave comments, you need to log in

2 answer(s)
S
Sergey Konovalov, 2015-09-19
@zakar1ya

After a long reading of the fluent api manuals, it turned out that the matter was completely different.
Fluent api supports cascade delete by default, the problem was that by clicking "delete", the view passed to the controller the entity in which the fields

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; }
, meaning the navigation properties were null.
Accordingly, EF could not remove related records because it did not know which ones, until I manually included them in the selection
[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);
        }

There was a small question left, Include requires a string with the name of the associated object, but it’s somehow not good to write directly, as I have. How is it better to write it down and in general can there be better designs than this one?
context.Partiya
                    .Include("Zakupki")
                    .Include("Zakladki")
                    .Include("Vivod")
                    .Include("Prodagi")

A
Andrey Evdokimov, 2015-09-23
@Uncle_Stranger

Use labs instead of strings

context.Partiya
                    .Include(x => x.Zakupki)
                    .Include(x => x.Zakladki)
                    .Include(x => x.Vivod)
                    .Include(x => x.Prodagi)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question