Guid StoreSagaDocuments() { var sagaId = Guid.NewGuid(); var sagaDocId = $"CountingSagaDatas/{sagaId}"; var uniqueDocId = "Raven3Sagas-CountingSagaData/Name/5f293261-55cf-fb70-8b0a-944ef322a598"; // Guid is hash of "Alpha" var typeName = "Raven3Sagas+CountingSagaData, NServiceBus.RavenDB.Tests"; var oldData = new CountingSagaData { Name = "Alpha", Id = sagaId, Counter = 42, Originator = "DoesntMatter@MACHINE", OriginalMessageId = Guid.NewGuid().ToString() }; var uniqueDoc = new SagaUniqueIdentity { Id = uniqueDocId, SagaDocId = sagaDocId, SagaId = sagaId, UniqueValue = "Alpha" }; StoreSaga(store, sagaDocId, oldData, "CountingSagaDatas", typeName, uniqueDocId); StoreUniqueDoc(store, uniqueDocId, uniqueDoc); return(sagaId); }
public static void RenameUniqueIdentities <TOldSaga, TNewSaga>(DocumentStore store, string uniqueProperty) where TOldSaga : IContainSagaData where TNewSaga : IContainSagaData { List <string> keysToDelete = new List <string>(); string oldSagaPrefix = store.GetDocumentPrefix <TOldSaga>(); string newSagaPrefix = store.GetDocumentPrefix <TNewSaga>(); string oldIdentityPrefix = GetIdentityPrefix <TOldSaga>(uniqueProperty); string newIdentityPrefix = GetIdentityPrefix <TNewSaga>(uniqueProperty); using (BulkInsertOperation bulkInsert = store.BulkInsert()) { foreach (StreamResult <SagaUniqueIdentity> result in store.Stream <SagaUniqueIdentity>(oldIdentityPrefix)) { SagaUniqueIdentity oldIdentity = result.Document; keysToDelete.Add(result.Key); SagaUniqueIdentity newIdentity = new SagaUniqueIdentity { Id = oldIdentity.Id.Replace(oldIdentityPrefix, newIdentityPrefix), SagaDocId = oldIdentity.SagaDocId.Replace(oldSagaPrefix, newSagaPrefix), UniqueValue = oldIdentity.UniqueValue, SagaId = oldIdentity.SagaId }; bulkInsert.Store(newIdentity); } } store.BatchDelete(keysToDelete); }
static void CreateLegacySagaDocuments(IDocumentStore store, string unique) { var sagaId = Guid.NewGuid(); var saga = new SagaWithUniqueProperty { Id = sagaId, UniqueString = unique }; var sagaDocId = $"SagaWithUniqueProperty/{sagaId}"; var typeName = Regex.Replace(typeof(SagaWithUniqueProperty).AssemblyQualifiedName, ", Version=.*", ""); DirectStore(store, sagaDocId, saga, "SagaWithUniqueProperty", typeName, unique); var uniqueIdentity = new SagaUniqueIdentity { Id = SagaUniqueIdentity.FormatId(typeof(SagaWithUniqueProperty), "UniqueString", unique), SagaId = sagaId, SagaDocId = sagaDocId, UniqueValue = unique }; DirectStore(store, uniqueIdentity.Id, uniqueIdentity, "SagaUniqueIdentity", "NServiceBus.Persistence.Raven.SagaPersister.SagaUniqueIdentity, NServiceBus.Core"); }
public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue); //store it in the context to be able to optimize deletes for legacy sagas that don't have the id in metadata context.Set(UniqueDocIdKey, lookupId); var lookup = await documentSession .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip .LoadAsync <SagaUniqueIdentity>(lookupId) .ConfigureAwait(false); if (lookup != null) { documentSession.Advanced.Evict(lookup); return(lookup.SagaDocId != null ? await documentSession.LoadAsync <T>(lookup.SagaDocId).ConfigureAwait(false) //if we have a saga id we can just load it : await Get <T>(lookup.SagaId, session, context).ConfigureAwait(false)); //if not this is a saga that was created pre 3.0.4 so we fallback to a get instead } return(default(T)); }
public async Task <T> Get <T>(string propertyName, object propertyValue, SynchronizedStorageSession session, ContextBag context) where T : class, IContainSagaData { var documentSession = session.RavenSession(); var lookupId = SagaUniqueIdentity.FormatId(typeof(T), propertyName, propertyValue); var lookup = await documentSession .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip .LoadAsync <SagaUniqueIdentity>(lookupId) .ConfigureAwait(false); if (lookup != null) { documentSession.Advanced.Evict(lookup); // If we have a saga id we can just load it, should have been included in the round-trip already var container = await documentSession.LoadAsync <SagaDataContainer>(lookup.SagaDocId).ConfigureAwait(false); if (container != null) { if (container.IdentityDocId == null) { container.IdentityDocId = lookupId; } context.Set($"{SagaContainerContextKeyPrefix}{container.Data.Id}", container); return((T)container.Data); } } return(default(T)); }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context) { var documentSession = session.RavenSession(); if (sagaData == null) { return; } var container = new SagaDataContainer { Id = DocumentIdForSagaData(documentSession, sagaData), Data = sagaData }; if (correlationProperty == null) { return; } container.IdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value); await documentSession.StoreAsync(container, string.Empty, container.Id).ConfigureAwait(false); await documentSession.StoreAsync(new SagaUniqueIdentity { Id = container.IdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = container.Id }, changeVector : string.Empty, id : container.IdentityDocId).ConfigureAwait(false); }
void DeleteUniqueProperty(IContainSagaData saga, KeyValuePair <string, object> uniqueProperty) { var id = SagaUniqueIdentity.FormatId(saga.GetType(), uniqueProperty); sessionProvider.Session.Advanced.Defer(new DeleteCommandData { Key = id }); }
public async Task Improperly_converted_saga_can_be_fixed() { var sagaId = Guid.NewGuid(); var sagaDocId = $"SagaWithUniqueProperty/{sagaId}"; var uniqueString = "abcd"; var identityDocId = SagaUniqueIdentity.FormatId(typeof(SagaWithUniqueProperty), "UniqueString", uniqueString); var sagaData = new SagaWithUniqueProperty { Id = Guid.Empty, // Improperly converted UniqueString = uniqueString }; var sagaContainer = new SagaDataContainer { Id = sagaDocId, Data = sagaData, IdentityDocId = identityDocId }; var uniqueIdentity = new SagaUniqueIdentity { Id = SagaUniqueIdentity.FormatId(typeof(SagaWithUniqueProperty), "UniqueString", uniqueString), SagaId = sagaId, SagaDocId = sagaDocId, UniqueValue = uniqueString }; using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var _)) { await session.StoreAsync(sagaContainer); await session.StoreAsync(uniqueIdentity); await session.SaveChangesAsync(); } using (var session = store.OpenAsyncSession().UsingOptimisticConcurrency().InContext(out var options)) { var persister = new SagaPersister(new SagaPersistenceConfiguration()); var synchronizedSession = new RavenDBSynchronizedStorageSession(session, options); var loadedSaga = await persister.Get <SagaWithUniqueProperty>("UniqueString", uniqueString, synchronizedSession, options); Assert.IsNotNull(loadedSaga, "Saga is null"); Assert.AreNotEqual(Guid.Empty, loadedSaga.Id, "Id is Guid.Empty"); Assert.AreEqual(sagaId, loadedSaga.Id, "Saga Id is not the correct value."); } }
T GetByUniqueProperty <T>(string property, object value) where T : IContainSagaData { var lookupId = SagaUniqueIdentity.FormatId(typeof(T), new KeyValuePair <string, object>(property, value)); var lookup = sessionProvider.Session .Include("SagaDocId") //tell raven to pull the saga doc as well to save us a round-trip .Load <SagaUniqueIdentity>(lookupId); if (lookup != null) { return(lookup.SagaDocId != null ? sessionProvider.Session.Load <T>(lookup.SagaDocId) //if we have a saga id we can just load it : Get <T>(lookup.SagaId)); //if not this is a saga that was created pre 3.0.4 so we fallback to a get instead } return(default(T)); }
static async Task CreateSagaUniqueIdentity(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, IAsyncDocumentSession documentSession) { var sagaDocId = documentSession.Advanced.DocumentStore.Conventions.FindFullDocumentKeyFromNonStringIdentifier(sagaData.Id, sagaData.GetType(), false); var sagaUniqueIdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value); await documentSession.StoreAsync(new SagaUniqueIdentity { Id = sagaUniqueIdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = sagaDocId }, id : sagaUniqueIdentityDocId, etag : Etag.Empty).ConfigureAwait(false); var metadata = await documentSession.Advanced.GetMetadataForAsync(sagaData).ConfigureAwait(false); metadata[UniqueDocIdKey] = sagaUniqueIdentityDocId; }
static void StoreUniqueDoc(IDocumentStore store, string id, SagaUniqueIdentity document) { var documentInfo = new DocumentInfo { MetadataInstance = new MetadataAsDictionary() }; documentInfo.MetadataInstance[Constants.Documents.Metadata.RavenClrType] = "NServiceBus.RavenDB.Persistence.SagaPersister.SagaUniqueIdentity, NServiceBus.RavenDB"; documentInfo.MetadataInstance[Constants.Documents.Metadata.Collection] = "SagaUniqueIdentities"; Console.WriteLine($"Creating unique identity: {id}"); using (var session = store.OpenSession()) { var blittableDoc = session.Advanced.EntityToBlittable.ConvertEntityToBlittable(document, documentInfo); var command = new PutDocumentCommand(id, string.Empty, blittableDoc); session.Advanced.RequestExecutor.Execute(command, session.Advanced.Context); session.SaveChanges(); } }
public async Task Save(IContainSagaData sagaData, SagaCorrelationProperty correlationProperty, SynchronizedStorageSession session, ContextBag context, CancellationToken cancellationToken = default) { var documentSession = session.RavenSession(); if (sagaData == null) { return; } if (correlationProperty == null) { return; } var container = new SagaDataContainer { Id = DocumentIdForSagaData(documentSession, sagaData), Data = sagaData, IdentityDocId = SagaUniqueIdentity.FormatId(sagaData.GetType(), correlationProperty.Name, correlationProperty.Value), }; await documentSession.StoreAsync(container, string.Empty, container.Id, cancellationToken).ConfigureAwait(false); documentSession.StoreSchemaVersionInMetadata(container); var sagaUniqueIdentity = new SagaUniqueIdentity { Id = container.IdentityDocId, SagaId = sagaData.Id, UniqueValue = correlationProperty.Value, SagaDocId = container.Id }; await documentSession.StoreAsync(sagaUniqueIdentity, changeVector : string.Empty, id : container.IdentityDocId, token : cancellationToken).ConfigureAwait(false); documentSession.StoreSchemaVersionInMetadata(sagaUniqueIdentity); }
static void CreateLegacySagaDocuments(IDocumentStore store, string unique) { var sagaId = Guid.NewGuid(); var saga = new SagaWithUniqueProperty { Id = sagaId, UniqueString = unique }; var sagaDocId = $"SagaWithUniqueProperty/{sagaId}"; DirectStore(store, sagaDocId, saga, "SagaWithUniqueProperty", ReflectionUtil.GetFullNameWithoutVersionInformation(typeof(SagaWithUniqueProperty)), unique); var uniqueIdentity = new SagaUniqueIdentity { Id = SagaUniqueIdentity.FormatId(typeof(SagaWithUniqueProperty), "UniqueString", unique), SagaId = sagaId, SagaDocId = sagaDocId, UniqueValue = unique }; DirectStore(store, uniqueIdentity.Id, uniqueIdentity, "SagaUniqueIdentity", "NServiceBus.Persistence.Raven.SagaPersister.SagaUniqueIdentity, NServiceBus.Core"); }
void StoreUniqueProperty(IContainSagaData saga) { var uniqueProperty = UniqueAttribute.GetUniqueProperty(saga); if (!uniqueProperty.HasValue) { return; } var id = SagaUniqueIdentity.FormatId(saga.GetType(), uniqueProperty.Value); var sagaDocId = sessionProvider.Session.Advanced.DocumentStore.Conventions.FindFullDocumentKeyFromNonStringIdentifier(saga.Id, saga.GetType(), false); sessionProvider.Session.Store(new SagaUniqueIdentity { Id = id, SagaId = saga.Id, UniqueValue = uniqueProperty.Value.Value, SagaDocId = sagaDocId }); SetUniqueValueMetadata(saga, uniqueProperty.Value); }
public static void StoreSchemaVersionInMetadata(this IAsyncDocumentSession session, SagaUniqueIdentity entity) { var metadata = session.Advanced.GetMetadataFor(entity); metadata[SagaUniqueIdentitySchemaVersionMetadataKey] = SagaUniqueIdentity.SchemaVersion; }