Difference between DbSet.Remove and DbContext.Entry(entity).State = EntityState.Deleted

10,211

Ended up solving this by calling the following:

dbContext.Set<Agreement>().Remove(agreement);

I wanted to get rid of the Agreements property on the DbContext, which is why I was trying to do it with Entry(agreement).State = EntityState.Deleted.

Share:
10,211

Related videos on Youtube

danludwig
Author by

danludwig

System Fragmentation Advocate, Cloud Services Puppeteer, &amp; Network Parsimony Policeman AWS Certified Developer Associate 2021

Updated on August 16, 2022

Comments

  • danludwig
    danludwig over 1 year

    Consider the following entity model:

    public class Agreement : Entity
    {
        public int AgreementId { get; set; }
        public virtual ICollection<Participant> Participants { get; set; }
    }
    
    public class Establishment : Entity
    {
        public int EstablishmentId { get; set; }
    }
    
    public class Participant : Entity
    {
        public int AgreementId { get; set; }
        public virtual Agreement Agreement { get; set; }
    
        public int EstablishmentId { get; set; }
        public virtual Establishment { get; set; }
    
        public bool IsOwner { get; set; }
    }
    

    The reason there is not a direct ICollection<Establishment> on the Agreement entity is because of the IsOwner property, which further defines this many-to-many relationship.

    The relationship is mapped like so:

    internal ParticipantOrm()
    {
        ToTable(typeof(Participant).Name);
    
        HasKey(k => new { k.AgreementId, k.EstablishmentId });
    
        HasRequired(d => d.Agreement)
            .WithMany(p => p.Participants)
            .HasForeignKey(d => d.AgreementId)
            .WillCascadeOnDelete(true);
    
        HasRequired(d => d.Establishment)
            .WithMany()
            .HasForeignKey(d => d.EstablishmentId)
            .WillCascadeOnDelete(true);
    }
    

    The relationship is uni-directional, meaning you can only get to the Participants from within an Agreement -- you cannot access the agreements from the Establishment.

    Now, since the Agreement entity's primary key is part of the gerund Participant's primary key, and since cascade delete is specified, I would expect that putting the Agreement into the Deleted state would also cause each entity in its Participants collection to also be put into the deleted state.

    This appears to work when calling Remove on an Agreement DbSet:

    // this works
    dbContext.Agreements.Remove(agreement);
    dbContext.SaveChanges();
    

    However, it does not appear to work when simply setting the agreement entry's state to deleted:

    // this causes an exception when Participants is not empty
    dbContext.Entry(agreement).State = EntityState.Deleted;
    dbContext.SaveChanges();
    

    Is there a way I can define the relationship so that simply putting the Agreement entity into the deleted state will also cause the corresponding collection item entities to be put into the deleted state?

    Update

    I have been reading about this, and found out that eager loading the Participants collection does not help:

    // eager loading does not help, this still breaks
    var agreement = dbContext.Set<Agreement>()
        .Include(a => a.Participants)
        .FirstOrDefault();
    dbContext.Entry(agreement).State = EntityState.Deleted;
    dbContext.SaveChanges();