/// <summary> /// This can be used to add / update / remove slots. /// </summary> public async Task <List <Duty> > UpdateDuties(List <Duty> duties, bool overrideValidation) { if (!duties.Any()) { throw new BusinessLayerException("Didn't provide any duties."); } await CheckForDutySlotOverlap(duties, overrideValidation); var dutyIds = duties.SelectToList(duty => duty.Id); var savedDuties = Db.Duty.AsSingleQuery() .Include(d => d.DutySlots) .Where(s => dutyIds.Contains(s.Id) && s.ExpiryDate == null); var shiftIds = duties.SelectMany(d => d.DutySlots).SelectDistinctToList(ds => ds.ShiftId); var shifts = Db.Shift.Where(s => shiftIds.Contains(s.Id)); foreach (var duty in duties) { var savedDuty = await savedDuties.FirstOrDefaultAsync(s => s.Id == duty.Id); savedDuty.ThrowBusinessExceptionIfNull($"{nameof(Duty)} with the id: {duty.Id} could not be found. "); duty.Timezone.GetTimezone().ThrowBusinessExceptionIfNull($"A valid {nameof(duty.Timezone)} must be provided."); Db.Entry(savedDuty !).CurrentValues.SetValues(duty); Db.Entry(savedDuty).Property(x => x.LocationId).IsModified = false; Db.Entry(savedDuty).Property(x => x.ExpiryDate).IsModified = false; foreach (var dutySlot in duty.DutySlots) { var savedDutySlot = await Db.DutySlot .FirstOrDefaultAsync(ds => ds.Id == dutySlot.Id && ds.ExpiryDate == null); dutySlot.LocationId = duty.LocationId; dutySlot.DutyId = duty.Id; dutySlot.Timezone = duty.Timezone; dutySlot.Duty = null; dutySlot.Sheriff = null; dutySlot.Shift = null; dutySlot.Location = null; dutySlot.IsOvertime = false; var shift = shifts.FirstOrDefault(s => s.Id == dutySlot.ShiftId && s.ExpiryDate == null); if (shift != null) { if (shift.StartDate > dutySlot.StartDate) { shift.StartDate = dutySlot.StartDate; shift.IsOvertime = ShiftService.IsShiftOvertime(shift.StartDate, shift.EndDate, shift.Timezone, OvertimeHours); dutySlot.IsOvertime = shift.IsOvertime; } if (shift.EndDate < dutySlot.EndDate) { shift.EndDate = dutySlot.EndDate; shift.IsOvertime = ShiftService.IsShiftOvertime(shift.StartDate, shift.EndDate, shift.Timezone, OvertimeHours); dutySlot.IsOvertime = shift.IsOvertime; } } if (savedDutySlot == null) { await Db.DutySlot.AddAsync(dutySlot); } else { Db.Entry(savedDutySlot).CurrentValues.SetValues(dutySlot); } } Db.RemoveRange(savedDuty.DutySlots.Where(ds => duty.DutySlots.All(d => d.Id != ds.Id))); } await Db.SaveChangesAsync(); return(await savedDuties.ToListAsync()); }