9

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();
danludwig
  • 46,965
  • 25
  • 159
  • 237
  • It will probably work when you detach the participants from the context. `Remove` is a nice method, why don't you want to use it? – Slauma Jul 20 '12 at 19:28
  • It's not that I didn't want to use it, it's that I wanted to get rid of the `Agreements` property on the DbContext. Ended up solving this by calling `dbContext.Set().Remove(agreement);` – danludwig Aug 03 '12 at 18:05

1 Answers1

15

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.

danludwig
  • 46,965
  • 25
  • 159
  • 237
  • 2
    I'd be intrested in knowing the difference between .Remove and setting the entityState. I have observed different behaviours and have found .Remove() to be much more reliable – nixon Mar 13 '13 at 04:46
  • did you figure it out? I am calling .Remove(o) but then when i loop through local entities on save, I don't see a bunch of them with "Deleted" state.. – Sonic Soul Oct 23 '14 at 17:57