Using the SchedulerCustomEditor as a sample project I've created a project where the user can manage Events, both individual and recurring. I'm using EF6 to manage read/write to the database. My database has an Events table which has a many-to-many relationship with Categories and a many to many relationship with Locations (see attached).
Add and Edit events (and their related categories) seems to work fine, recurring events and recurrence exceptions are getting created, updated properly, delete works fine until a recurring event has a recurrence exception. An exception is thrown by Entity Framework: "Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded." Stepping through my delete function the calls to delete the recurrence exception event and it's parent occur almost simultaneously, I've notice similar in the Delete function in the SchedulerCustomEditor sample project:
public virtual void Delete(MeetingViewModel meeting, ModelStateDictionary modelState)
{
if (meeting.Attendees == null)
{
meeting.Attendees = new int[0];
}
var entity = meeting.ToEntity();
db.Meetings.Attach(entity);
var attendees = meeting.Attendees.Select(attendee => new MeetingAttendee
{
AttendeeID = attendee,
MeetingID = entity.MeetingID
});
foreach (var attendee in attendees)
{
db.MeetingAttendees.Attach(attendee);
}
entity.MeetingAttendees.Clear();
var recurrenceExceptions = db.Meetings.Where(m => m.RecurrenceID == entity.MeetingID);
foreach (var recurrenceException in recurrenceExceptions)
{
db.Meetings.Remove(recurrenceException);
}
db.Meetings.Remove(entity);
db.SaveChanges();
}
Can't say I really understand what is going on in the above function with the Attach calls. In the above function you are manually removing the records MeetingAttendees join table somehow, but in my scenario I have no access to these join tables.
My Delete function is:
public virtual void Delete(EventScheduleViewModel evt, ModelStateDictionary modelState)
{
if (evt.Categories == null)
{
evt.Categories = new int[0];
}
if (evt.Locations == null)
{
evt.Locations = new int[0];
}
var entity = db.Events.Include("Categories").Include("Locations").FirstOrDefault(m => m.EventID == evt.EventID);
foreach (var category in entity.Categories.ToList())
{
entity.Categories.Remove(category);
}
foreach (var location in entity.Locations.ToList())
{
entity.Locations.Remove(location);
}
var recurrenceExceptions = db.Events.Where(m => m.RecurrenceID == entity.EventID);
foreach (var recurrenceException in recurrenceExceptions)
{
db.Events.Remove(recurrenceException);
}
db.Events.Remove(entity);
try
{
db.SaveChanges();
}
catch (Exception e)
{
throw;
}
}
here's my Insert and Update functions which seem to be working ok:
public virtual void Insert(EventScheduleViewModel evt, ModelStateDictionary modelState)
{
if (ValidateModel(evt, modelState))
{
if (evt.Categories == null)
{
evt.Categories = new int[0];
}
if (evt.Locations == null)
{
evt.Locations = new int[0];
}
var entity = evt.ToEntity();
foreach (var categoryId in evt.Categories)
{
var category = db.Categories.FirstOrDefault(s => s.CategoryID == categoryId);
if (category != null)
{
entity.Categories.Add(category);
}
}
foreach (var locationId in evt.Locations)
{
var location = db.Locations.FirstOrDefault(s => s.LocationID == locationId);
if (location != null)
{
entity.Locations.Add(location);
}
}
try
{
db.Events.Add(entity);
db.SaveChanges();
}
catch (Exception)
{
throw;
}
evt.EventID = entity.EventID;
}
}
public virtual void Update(EventScheduleViewModel evt, ModelStateDictionary modelState)
{
if (ValidateModel(evt, modelState))
{
var entity = db.Events.Include("Categories").Include("Locations").FirstOrDefault(m => m.EventID == evt.EventID);
entity.Title = evt.Title;
entity.Start = evt.Start;
entity.End = evt.End;
entity.Description = evt.Description;
entity.IsAllDay = evt.IsAllDay;
entity.RecurrenceID = evt.RecurrenceID;
entity.RecurrenceRule = evt.RecurrenceRule;
entity.RecurrenceException = evt.RecurrenceException;
entity.StartTimezone = evt.StartTimezone;
entity.EndTimezone = evt.EndTimezone;
entity.Fee = evt.Fee;
entity.ContactName = evt.ContactName;
entity.ContactPhone = evt.ContactPhone;
entity.ContactEmail = evt.ContactEmail;
entity.Summary = evt.Summary;
entity.OffsiteLocation = evt.OffsiteLocation;
entity.SubmitterName = evt.SubmitterName;
entity.SubmitterPhone = evt.SubmitterPhone;
entity.SubmitterEmail = evt.SubmitterEmail;
entity.SubmitterComments = evt.SubmitterComments;
entity.ImagePath = evt.ImagePath;
entity.ImageAltText = evt.ImageAltText;
entity.LastModified = evt.LastModified;
entity.LastModifiedBy = evt.LastModifiedBy;
entity.IsOffCampus = evt.IsOffCampus;
entity.IsPublished = evt.IsPublished;
entity.IsDisplayedOnNSCC = evt.IsDisplayedOnNSCC;
entity.IsDisplayedOnConnectStudent = evt.IsDisplayedOnConnectStudent;
entity.IsDisplayedOnConnectEmployee = evt.IsDisplayedOnConnectEmployee;
entity.IsCollegeWide = evt.IsCollegeWide;
foreach (var category in entity.Categories.ToList())
{
entity.Categories.Remove(category);
}
foreach (var location in entity.Locations.ToList())
{
entity.Locations.Remove(location);
}
if (evt.Categories != null)
{
foreach (var categoryId in evt.Categories)
{
var category = db.Categories.FirstOrDefault(s => s.CategoryID == categoryId);
if (category != null)
{
entity.Categories.Add(category);
}
}
}
if (evt.Locations != null)
{
foreach (var locationId in evt.Locations)
{
var location = db.Locations.FirstOrDefault(s => s.LocationID == locationId);
if (location != null)
{
entity.Locations.Add(location);
}
}
}
try
{
db.SaveChanges();
}
catch (Exception)
{
throw;
}
}
}
How can I write my Delete function to remove recurring events that have recurrence exceptions?
Thanks.