protected override void BeforeSave() { DateTime timestamp = DateTime.UtcNow; //find all changed enities var modifiedEntities = Context.ChangeTracker.Entries<CurveDetail>() .Where(p => p.State == EntityState.Modified) .Select(p => p.Entity); foreach (CurveDetail detail in modifiedEntities) { //main entity, for which we keep versioning var mainEntity = detail.Curve; ICollection<CurveDetail> mainEntityDetails = mainEntity.CurveDetails; if (detail.Status == EntityStatus.ExpiredInSession) { foreach (CurveDetail item in mainEntityDetails) { if (detail.CurveDetailID != item.CurveDetailID) { item.EndTime = detail.EndTime; item.ModifiedBy = detail.ModifiedBy; item.ModifiedAt = detail.ModifiedAt; } } mainEntity.EndTime = detail.EndTime; mainEntity.ModifiedBy = detail.ModifiedBy; mainEntity.ModifiedAt = detail.ModifiedAt; } if (detail.Status == EntityStatus.ApprovedInSession) { //entity has been approved //mark existing details as expired foreach (CurveDetail item in mainEntityDetails) { if (detail.CurveDetailID != item.CurveDetailID) { item.Latest = false; item.EndTime = (DateTime)detail.ApprovedAt; detail.StartTime = (DateTime)detail.ApprovedAt; } } //check if main entity is approved - if not copy details if (mainEntity.Status != EntityStatus.Approved) { mainEntity.ApprovedAt = detail.ApprovedAt; mainEntity.ApprovedBy = detail.ApprovedBy; mainEntity.StartTime = detail.StartTime; } // approve all consituents foreach (var dim in mainEntity.CurveDimensions) { foreach (var item in dim.CurveConstituents) { if (item.Status != EntityStatus.Unapproved || item.Status != EntityStatus.UnapprovedInSession) { item.ApprovedAt = detail.ApprovedAt; item.ApprovedBy = detail.ApprovedBy; item.StartTime = detail.StartTime; } } } } else if (detail.Status == EntityStatus.UnapprovedInSession) { //new version of the entity //we are creating a copy of currently edited entity //and add it back to context var copy = new CurveDetail(); mainEntity.CurveDetails.Add(copy); //copy values from original Context.Entry(copy).CurrentValues.SetValues(detail); //reset auditing copy.ResetCopy(); //revert the changes - done implicitly Context.Entry(detail).State = EntityState.Unchanged; //remove latest flag detail.Latest = false; } } }