public SyncResponse Sync(SyncRequest request) { lock (this.changeSetLock) { if (this.sharedChangeSetN == 0) { using (var db = new BrennContext()) { this.sharedChangeSetN = new[] { db.Expenses.Max<Expense, int?>(e => e.ChangeSetN), db.Trips.Max<Trip, int?>(e => e.ChangeSetN), db.People.Max<Person, int?>(e => e.ChangeSetN) }.Max().GetValueOrDefault(1); } } } var anyUpdates = (request.ExpenseUpdates == null ? 0 : request.ExpenseUpdates.Count) + (request.TripUpdates == null ? 0 : request.TripUpdates.Count) + (request.PersonUpdates == null ? 0 : request.PersonUpdates.Count) > 0; var changeSetN = anyUpdates ? Interlocked.Increment(ref this.sharedChangeSetN) : this.sharedChangeSetN; var response = new SyncResponse { ExpenseUpdateResults = new List<UpdateResult>(), TripUpdateResults = new List<UpdateResult>(), PersonUpdateResults = new List<UpdateResult>(), ServerChangeSetN = changeSetN }; var updatedExpenseIds = new List<int>(); var updatedTripIds = new List<int>(); var updatedPersonIds = new List<int>(); PerformExpenseUpdates(request, response, updatedExpenseIds); PerformTripUpdates(request, response, updatedTripIds); PerformPersonUpdates(request, response, updatedPersonIds); using (var db = new BrennContext()) { ((IObjectContextAdapter)db).ObjectContext.ContextOptions.ProxyCreationEnabled = false; response.Expenses = new List<Expense>( db.Expenses.Include("Receivers").Where( e => e.ChangeSetN > request.ClientChangeSetN && !updatedExpenseIds.Contains(e.ExpenseId))); response.Trips = new List<Trip>( db.Trips .Where( e => e.ChangeSetN > request.ClientChangeSetN && !updatedTripIds.Contains(e.TripId))); response.Trips.ForEach(t => t.Expenses = null); response.People = new List<Person>( db.People .Where(e => e.ChangeSetN > request.ClientChangeSetN && !updatedPersonIds.Contains(e.PersonId))); } return response; }
private static void PerformTripUpdates( SyncRequest request, SyncResponse response, ICollection<int> updatedTripIds) { if (request.TripUpdates == null) { return; } foreach (var tripUpdate in request.TripUpdates) { if (tripUpdate.ClientRowId == default(Guid)) { throw new Exception("The client row id must be set."); } using (var db = new BrennContext()) { using (var scope = new TransactionScope()) { if (tripUpdate.Trip.TripId == default(int)) { db.Trips.Add(tripUpdate.Trip); } else { var trip = db.Trips.Find(tripUpdate.Trip.TripId); if (trip == null) { response.TripUpdateResults.Add( new UpdateResult { Error = UpdateError.DeletedOnServer, ClientRowId = tripUpdate.Trip.RowId }); continue; } if (trip.RowId != tripUpdate.ClientRowId) { response.TripUpdateResults.Add( new UpdateResult { Error = UpdateError.ModifiedOnServer, ClientRowId = tripUpdate.Trip.RowId }); continue; } var entry = db.Entry(trip); entry.CurrentValues.SetValues(tripUpdate.Trip); } db.SaveChanges(); scope.Complete(); } response.TripUpdateResults.Add( new UpdateResult { Error = null, ClientRowId = tripUpdate.Trip.RowId }); updatedTripIds.Add(tripUpdate.Trip.TripId); } } }
private static void PerformPersonUpdates( SyncRequest request, SyncResponse response, ICollection<int> updatedPersonIds) { if (request.PersonUpdates == null) { return; } foreach (var personUpdate in request.PersonUpdates) { using (var db = new BrennContext()) { using (var scope = new TransactionScope()) { var person = db.People.Find(personUpdate.Person.PersonId); if (person == null) { response.PersonUpdateResults.Add( new UpdateResult { Error = UpdateError.DeletedOnServer, ClientRowId = personUpdate.Person.RowId }); continue; } if (person.RowId != personUpdate.ClientRowId) { response.PersonUpdateResults.Add( new UpdateResult { Error = UpdateError.ModifiedOnServer, ClientRowId = personUpdate.Person.RowId }); continue; } var entry = db.Entry(person); entry.CurrentValues.SetValues(personUpdate.Person); db.SaveChanges(); scope.Complete(); } response.PersonUpdateResults.Add( new UpdateResult { Error = null, ClientRowId = personUpdate.Person.RowId }); updatedPersonIds.Add(personUpdate.Person.PersonId); } } }
private static void PerformExpenseUpdates( SyncRequest request, SyncResponse response, List<int> updatedExpenseIds) { if (request.ExpenseUpdates == null) { return; } foreach (ExpenseUpdate expenseUpdate in request.ExpenseUpdates) { using (var db = new BrennContext()) { using (var scope = new TransactionScope()) { var expense = db.Expenses.Find(expenseUpdate.Expense.ExpenseId); if (expense == null) { response.ExpenseUpdateResults.Add( new UpdateResult { Error = UpdateError.DeletedOnServer, ClientRowId = expenseUpdate.Expense.RowId }); continue; } if (expense.RowId != expenseUpdate.ClientRowId) { response.ExpenseUpdateResults.Add( new UpdateResult { Error = UpdateError.ModifiedOnServer, ClientRowId = expenseUpdate.Expense.RowId }); continue; } var entry = db.Entry(expense); entry.CurrentValues.SetValues(expenseUpdate.Expense); db.SaveChanges(); scope.Complete(); } response.ExpenseUpdateResults.Add( new UpdateResult { Error = null, ClientRowId = expenseUpdate.Expense.RowId }); updatedExpenseIds.Add(expenseUpdate.Expense.ExpenseId); } } }
/// <summary> /// The handle sync response without lock. /// </summary> /// <param name="response"> /// The response. /// </param> private void HandleSyncResponseWithoutLock(SyncResponse response) { Debug.WriteLine("Handling sync response with server change set {0}.", response.ServerChangeSetN); if (response.ServerChangeSetN <= this.clientChangeSet) { Debug.WriteLine( "Warning: The changeset number of the sync response is {0}, which is lower than or equal to the client version, {1}.", response.ServerChangeSetN, this.clientChangeSet); } else { this.clientChangeSet = response.ServerChangeSetN; } foreach (var update in response.ExpenseUpdateResults) { if (update.Error.HasValue) { Debug.WriteLine("Failed to update expense: {0}", update.Error); } else { Debug.WriteLine("Successful update of expense."); } } foreach (var update in response.TripUpdateResults) { if (update.Error.HasValue) { Debug.WriteLine("Failed to update trip: {0}", update.Error); } else { Debug.WriteLine("Successful update of trip."); } } foreach (var update in response.PersonUpdateResults) { if (update.Error.HasValue) { Debug.WriteLine("Failed to update person: {0}", update.Error); } else { Debug.WriteLine("Successful update of person."); } } if (response.People != null) { response.People.ForEach(p => Repository.Instance.AddOrUpdate(p)); } if (response.Trips != null) { foreach (var t in response.Trips) { Debug.Assert(t.Expenses == null, "The trip included its expenses."); Repository.Instance.AddOrUpdate(t); } } if (response.Expenses != null) { foreach (var expense in response.Expenses) { Debug.Assert(expense.Receivers != null, "Receivers was not included from the service."); Debug.Assert(expense.Trip == null, "The trip should not be defined by the expense."); Debug.Assert(expense.TripId > 0, "The trip id must be included."); Repository.Instance.AddOrUpdate(expense); } } }
/// <summary> /// The handle sync response. /// </summary> /// <param name="response"> /// The response. /// </param> private void HandleSyncResponse(SyncResponse response) { if (response == null) { throw new ArgumentNullException("response"); } lock (this.items) { this.HandleSyncResponseWithoutLock(response); } }