Search code examples
c#ef-code-firstmany-to-many

Update Many-to-Many only Delete Not Insert


I have the following 3 entities:

public class Event
{
    #region Fields

    private float cost;
    private DateTime dateEnd;
    private DateTime dateIni;
    private string description;
    private int disciplineId;
    private int id;
    private float latitude;
    private int limit;
    private string locationDescription;
    private string locationTitle;
    private float longitude;
    private int organizationId;
    private string presentationImg;
    private bool status;

    #endregion Fields

    #region Constructors

    public Event()
    {
        this.Sponsors =  new HashSet<EventOrganizations>();
        this.EventModes = new HashSet<EventModes>();
        this.Status = true;
    }

    #endregion Constructors

    #region Properties

    public float Cost
    {
        get { return cost; }
        set { cost = value; }
    }

    public DateTime DateEnd
    {
        get { return dateEnd; }
        set { dateEnd = value; }
    }

    public DateTime DateIni
    {
        get { return dateIni; }
        set { dateIni = value; }
    }

    public string Description
    {
        get { return description; }
        set { description = value; }
    }

    public virtual Discipline Discipline
    {
        get; set;
    }

    public int DisciplineId
    {
        get { return disciplineId; }
        set { disciplineId = value; }
    }

    public virtual ICollection<EventModes> EventModes
    {
        get;
        set;
    }

    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    public float Latitude
    {
        get { return latitude; }
        set { latitude = value; }
    }

    public int Limit
    {
        get { return limit; }
        set { limit = value; }
    }

    public string LocationDescription
    {
        get { return locationDescription; }
        set { locationDescription = value; }
    }

    public string LocationTitle
    {
        get { return locationTitle; }
        set { locationTitle = value; }
    }

    public float Longitude
    {
        get { return longitude; }
        set { longitude = value; }
    }

    public virtual Organization Organization
    {
        get; set;
    }

    public int OrganizationId
    {
        get { return organizationId; }
        set { organizationId = value; }
    }

    public virtual Page Page
    {
        get; set;
    }

    public string PresentationImg
    {
        get { return presentationImg; }
        set { presentationImg = value; }
    }

    public virtual ICollection<EventOrganizations> Sponsors
    {
        get; set;
    }

    public bool Status
    {
        get { return status; }
        set { status = value; }
    }

    #endregion Properties
}

public class EventOrganizations
{
    #region Fields

    private int eventId;
    private int organizationId;

    #endregion Fields

    #region Properties

    public virtual Event Event
    {
        get; set;
    }

    public int EventId
    {
        get { return eventId; }
        set { eventId = value; }
    }

    public virtual Organization Organization
    {
        get; set;
    }

    public int OrganizationId
    {
        get { return organizationId; }
        set { organizationId = value; }
    }

    #endregion Properties
}

public class Organization
{
    #region Fields

    private string description;
    private int id;
    private string logo;
    private bool status;
    private string url;

    #endregion Fields

    #region Constructors

    public Organization()
    {
        this.Status = true;
        this.Events = new HashSet<Event>();
        this.EventSponsored = new HashSet<EventOrganizations>();
    }

    #endregion Constructors

    #region Properties

    [Required]
    [MaxLength(150)]
    public string Description
    {
        get { return description; }
        set { description = value; }
    }

    public virtual ICollection<Event> Events
    {
        get; set;
    }

    public virtual ICollection<EventOrganizations> EventSponsored
    {
        get; set;
    }

    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int Id
    {
        get { return id; }
        set { id = value; }
    }

    [Required]
    public string Logo
    {
        get { return logo; }
        set { logo = value; }
    }

    public bool Status
    {
        get { return status; }
        set { status = value; }
    }

    [MaxLength(150)]
    public string Url
    {
        get { return url; }
        set { url = value; }
    }

    #endregion Properties
}

Context:

    modelBuilder.Entity<EventOrganizations>()
    .HasKey(i => new { i.EventId, i.OrganizationId });

    modelBuilder.Entity<EventOrganizations>()
            .HasRequired(i => i.Event)
            .WithMany(i => i.Sponsors)
            .HasForeignKey(i => i.EventId)
            .WillCascadeOnDelete(false);

    modelBuilder.Entity<EventOrganizations>()
            .HasRequired(i => i.Organization)
            .WithMany(i=>i.EventSponsored)
            .HasForeignKey(i => i.OrganizationId)
            .WillCascadeOnDelete(false);

Now in EventOrganizations table I have:

    EventId OrganizationId
    7       6
    8       6
    9       6

let's say I want to perform an update action over row (9,6), for this I'm sending:

    {
      "Id": 9,
      "Sponsors": [{
          "EventId":9,
          "OrganizationId":8
        }]
      }

My update method:

      public void Update(Event entity)
      {
      var existingEvent = context.Events
                                    .Include(x => x.EventModes)
                                    .Include(x => x.Sponsors)
                                    .Where(x => x.Id ==           entity.Id).FirstOrDefault<Event>();

      var addedSponsors = entity.Sponsors.Except(existingEvent.Sponsors, x => x.OrganizationId).ToList<EventOrganizations>();
      var deletedSponsors = existingEvent.Sponsors.Except(entity.Sponsors, x => x.OrganizationId).ToList<EventOrganizations>();
      deletedSponsors.ForEach(c => existingEvent.Sponsors.Remove(c));    
      foreach (EventOrganizations c in addedSponsors)
      {
        if (context.Entry(c).State == EntityState.Detached)
        {
            context.EventOrganizations.Attach(c);
        }
        existingEvent.Sponsors.Add(c);
      }

    context.SaveChanges();
   }

I don't get why is performing just delete and not insert the new attached entity over the EventOrganizations table


Solution

  • Since "EventOrganizations" object contains both Id on post, you should use

         foreach (EventOrganizations c in addedSponsors)
         {
             existingEvent.EventOrganizations.Add(c);
         }
    

    The issue is that when adding a children to an Entity in an ICollection, the parent Id should not be mapped. So you can add Sponsors to the table directly, or you can remove the "EventId" value from the posted data and add it to the "Sponsors" collection.