public async Task PersistAsync(T model) { var persistedObject = await RetrieveInternalAsync(model.Key); if (persistedObject == null) { await _db.CreateDocumentAsync(new PersistedModel <T>(model)); } else { persistedObject.Current = model; await _db.UpdateDocumentAsync(persistedObject); } }
public async Task PersistAsync(TModel model) { //waits untill the previous task has been finished (sort of like a lock but no 100% the same) await _persistMutex.WaitAsync().ConfigureAwait(false); try { var persistedObject = RetrieveInternal(model.Key); if (persistedObject == null) { SetETag(model); await _db.CreateDocumentAsync(new PersistedModel <TModel>(model)); //Try catch to handle transaction logic try { await EventSourcingCreateRecordAsync(null, model); } catch { //Revert the creation of the documentDb doc await DeleteAsync(model.Key, false); throw; } } else { //When doing a patch, the last one wins since we are only updating a part of the object and probably do not have access to the etag. //To detect a patch operation, check the e-tag for a null value if (persistedObject.Current.ETag != null && persistedObject.Current.ETag != model.ETag) { throw new Exception("The object has changed between your read action and this update request. We cannot continue with the save."); } SetETag(model); //It's important that this happens before the persistedObject.Current is set to the updated model to get the diff... var newEventSourcingRecord = await EventSourcingCreateRecordAsync(persistedObject.Current, model); try { persistedObject.Current = model; await _db.UpdateDocumentAsync(persistedObject); } catch { //Revert the creation of the event sourcing record //var entityToDelete = await TableStorage.GetSingleEntity<ITableEntity>(newEventSourcingRecord.PartitionKey, newEventSourcingRecord.RowKey); await _tableStorage.DeleteAsync(newEventSourcingRecord); throw; } } } finally { _persistMutex.Release(); } }