Пример #1
0
 /// <summary>
 /// The method that is called after the entities are fetched from the database.
 /// </summary>
 /// <param name="context">The save changes context.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
 protected internal virtual Task BeforeApplyChangesAsync(SaveChangesContext context, CancellationToken cancellationToken = default(CancellationToken))
 {
     if (cancellationToken.IsCancellationRequested)
     {
         return(Task.FromCanceled <object>(cancellationToken));
     }
     return(Task.CompletedTask);
 }
Пример #2
0
 /// <summary>
 /// The method that is called after the entity changes where applied and flushed into the database.
 /// </summary>
 /// <param name="context">The save changes context.</param>
 /// <param name="keyMappings">The key mappings for auto-generated primary keys.</param>
 /// <param name="cancellationToken">A cancellation token that can be used to cancel the work</param>
 protected internal virtual Task AfterFlushChangesAsync(SaveChangesContext context, List <KeyMapping> keyMappings, CancellationToken cancellationToken = default(CancellationToken))
 {
     if (cancellationToken.IsCancellationRequested)
     {
         return(Task.FromCanceled <object>(cancellationToken));
     }
     return(Task.CompletedTask);
 }
Пример #3
0
        private static async Task ProcessSavesAsync(
            List <EntityInfo> saveOrder,
            PersistenceManager persistenceManager,
            SaveChangesContext context,
            ISaveChangesOptions saveChangesOptions,
            ConfiguredSessionProvider sessionProvider, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            foreach (var entityInfo in saveOrder)
            {
                await(persistenceManager.BeforeSaveEntityChangesAsync(entityInfo, context, cancellationToken)).ConfigureAwait(false);
                var beforeSaveEntityChangesTask = saveChangesOptions?.BeforeSaveEntityChangesAsync(entityInfo, context, cancellationToken);
                if (beforeSaveEntityChangesTask != null)
                {
                    await(beforeSaveEntityChangesTask).ConfigureAwait(false);
                }

                var session = sessionProvider.GetSession(entityInfo.EntityType);
                try
                {
                    switch (entityInfo.EntityState)
                    {
                    case EntityState.Modified:
                        await(session.UpdateAsync(entityInfo.Entity, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Added:
                        await(session.SaveAsync(entityInfo.Entity, cancellationToken)).ConfigureAwait(false);
                        break;

                    case EntityState.Deleted:
                        await(session.DeleteAsync(entityInfo.Entity, cancellationToken)).ConfigureAwait(false);
                        break;
                    }
                }
                catch (PropertyValueException e)
                {
                    // NH can throw this when a not null property is null or transient (e.g. not-null property references a null or transient value)
                    var errors = new[]
                    {
                        // KeyValues cannot be determined as the exception may reference another entity
                        new EntityError
                        {
                            EntityTypeName = e.EntityName,
                            ErrorMessage   = e.Message,
                            ErrorName      = "PropertyValueException",
                            PropertyName   = e.PropertyName
                        }
                    };

                    throw new EntityErrorsException(e.Message, errors);
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Saves the changes made by the client.
        /// </summary>
        /// <param name="saveBundle">The changes to save.</param>
        /// <param name="saveChangesOptions">The saving options.</param>
        /// <returns>The save result.</returns>
        protected SaveResult SaveChanges(SaveBundle saveBundle, SaveChangesOptions saveChangesOptions)
        {
            var saveWorkState = _saveWorkStateFactory.Create(saveBundle,
                                                             info => AfterCreateEntityInfo(info, saveBundle.SaveOptions) &&
                                                             (saveChangesOptions.AfterCreateEntityInfoAction?.Invoke(info, saveBundle.SaveOptions) ?? true));

            try
            {
                var context = new SaveChangesContext(saveWorkState.SaveMap, saveBundle.SaveOptions);
                return(SaveChangesCore(saveWorkState, context, saveChangesOptions));
            }
            catch (Exception e)
            {
                if (!HandleSaveException(e, saveWorkState))
                {
                    throw;
                }
            }

            return(saveWorkState.ToSaveResult());
        }
Пример #5
0
        /// <summary>
        /// Saves the changes made by the client.
        /// </summary>
        /// <param name="saveBundle">The changes to save.</param>
        /// <param name="saveChangesOptions">The saving options.</param>
        /// <param name="cancellationToken">The cancellation token</param>
        /// <returns>The save result.</returns>
        protected async Task <SaveResult> SaveChangesAsync(SaveBundle saveBundle, AsyncSaveChangesOptions saveChangesOptions, CancellationToken cancellationToken)
        {
            var saveWorkState = _saveWorkStateFactory.Create(saveBundle,
                                                             info => AfterCreateEntityInfo(info, saveBundle.SaveOptions) &&
                                                             (saveChangesOptions.AfterCreateEntityInfoAction?.Invoke(info, saveBundle.SaveOptions) ?? true));

            try
            {
                var context = new SaveChangesContext(saveWorkState.SaveMap, saveBundle.SaveOptions);
                return(await SaveChangesCoreAsync(saveWorkState, context, saveChangesOptions, cancellationToken).ConfigureAwait(false));
            }
            catch (Exception e)
            {
                if (!HandleSaveException(e, saveWorkState))
                {
                    throw;
                }
            }

            return(saveWorkState.ToSaveResult());
        }
Пример #6
0
 void ISaveChangesOptions.BeforeFetchEntities(SaveChangesContext context)
 {
     throw new NotSupportedException();
 }
Пример #7
0
 Task ISaveChangesOptions.BeforeFetchEntitiesAsync(SaveChangesContext context, CancellationToken cancellationToken)
 {
     return(BeforeFetchEntitiesAction?.Invoke(context, cancellationToken));
 }
Пример #8
0
 /// <summary>
 /// The method that is called after the entities are saved by NHibernate methods Save, Update and Delete from ISession.
 /// </summary>
 /// <param name="saveOrder">The order in which the entities were saved.</param>
 /// <param name="context">The save changes context.</param>
 protected internal virtual void AfterSaveChanges(List <EntityInfo> saveOrder, SaveChangesContext context)
 {
 }
Пример #9
0
 void ISaveChangesOptions.ValidateDependencyGraph(DependencyGraph dependencyGraph, SaveChangesContext context)
 {
     ValidateDependencyGraphAction?.Invoke(dependencyGraph, context);
 }
Пример #10
0
 void ISaveChangesOptions.AfterFlushChanges(SaveChangesContext context, List <KeyMapping> keyMappings)
 {
     throw new NotSupportedException();
 }
Пример #11
0
 void ISaveChangesOptions.BeforeSaveEntityChanges(EntityInfo entityInfo, SaveChangesContext context)
 {
     throw new NotSupportedException();
 }
Пример #12
0
 Task ISaveChangesOptions.AfterSaveChangesAsync(List <EntityInfo> saveOrder, SaveChangesContext context, CancellationToken cancellationToken)
 {
     throw new NotSupportedException();
 }
Пример #13
0
 void ISaveChangesOptions.AfterSaveChanges(List <EntityInfo> saveOrder, SaveChangesContext context)
 {
     throw new NotSupportedException();
 }
Пример #14
0
 Task ISaveChangesOptions.BeforeApplyChangesAsync(SaveChangesContext context, CancellationToken cancellationToken)
 {
     throw new NotSupportedException();
 }
Пример #15
0
 void ISaveChangesOptions.AfterSaveChanges(List <EntityInfo> saveOrder, SaveChangesContext context)
 {
     AfterSaveChangesAction?.Invoke(saveOrder, context);
 }
Пример #16
0
 void ISaveChangesOptions.BeforeApplyChanges(SaveChangesContext context)
 {
     BeforeApplyChangesAction?.Invoke(context);
 }
Пример #17
0
 void ISaveChangesOptions.BeforeFetchEntities(SaveChangesContext context)
 {
     BeforeFetchEntitiesAction?.Invoke(context);
 }
Пример #18
0
 /// <summary>
 /// The method that is called after the entity changes where applied and flushed into the database.
 /// </summary>
 /// <param name="context">The save changes context.</param>
 /// <param name="keyMappings">The key mappings for auto-generated primary keys.</param>
 protected internal virtual void AfterFlushChanges(SaveChangesContext context, List <KeyMapping> keyMappings)
 {
 }
Пример #19
0
 void ISaveChangesOptions.BeforeApplyChanges(SaveChangesContext context)
 {
     throw new NotSupportedException();
 }
Пример #20
0
 void ISaveChangesOptions.AfterFlushChanges(SaveChangesContext context, List <KeyMapping> keyMappings)
 {
     AfterFlushChangesAction?.Invoke(context, keyMappings);
 }
Пример #21
0
 Task ISaveChangesOptions.BeforeApplyChangesAsync(SaveChangesContext context, CancellationToken cancellationToken)
 {
     return(BeforeApplyChangesAction?.Invoke(context, cancellationToken) ?? Task.CompletedTask);
 }
Пример #22
0
 Task ISaveChangesOptions.AfterFlushChangesAsync(SaveChangesContext context, List <KeyMapping> keyMappings, CancellationToken cancellationToken)
 {
     throw new NotSupportedException();
 }
Пример #23
0
 Task ISaveChangesOptions.AfterSaveChangesAsync(List <EntityInfo> saveOrder, SaveChangesContext context, CancellationToken cancellationToken)
 {
     return(AfterSaveChangesAction?.Invoke(saveOrder, context, cancellationToken) ?? Task.CompletedTask);
 }
Пример #24
0
        internal async Task <List <KeyMapping> > FetchAndApplyChangesInternalAsync(
            PersistenceManager persistenceManager,
            SaveChangesContext context,
            ISaveChangesOptions saveChangesOptions, CancellationToken cancellationToken = default(CancellationToken))
        {
            cancellationToken.ThrowIfCancellationRequested();
            await(persistenceManager.BeforeFetchEntitiesAsync(context, cancellationToken)).ConfigureAwait(false);
            var beforeFetchEntitiesTask = saveChangesOptions?.BeforeFetchEntitiesAsync(context, cancellationToken);

            if (beforeFetchEntitiesTask != null)
            {
                await(beforeFetchEntitiesTask).ConfigureAwait(false);
            }

            var saveMap = context.SaveMap;

            using var sessionProvider = new ConfiguredSessionProvider(_sessionProvider);
            var entitiesIdMap = new EntityIdMap(saveMap.Count);
            var saveMapList   = saveMap.ToList();

            // Make sure that entity types that have all key-many-to-one are sorted so that the associated entities will be processed before them
            saveMapList.Sort(CompareSaveMapTypes);
            foreach (var pair in saveMapList)
            {
                await(SetupDatabaseEntitiesAsync(pair.Key, pair.Value, saveMap, entitiesIdMap, sessionProvider, cancellationToken)).ConfigureAwait(false);
            }

            await(persistenceManager.BeforeApplyChangesAsync(context, cancellationToken)).ConfigureAwait(false);
            var beforeApplyChangesTask = saveChangesOptions?.BeforeApplyChangesAsync(context, cancellationToken);

            if (beforeApplyChangesTask != null)
            {
                await(beforeApplyChangesTask).ConfigureAwait(false);
            }

            AddAdditionalEntities(context.AdditionalEntities, context.SaveMap);
            context.AdditionalEntities?.Clear();
            var dependencyGraph = new DependencyGraph(saveMap.Count);

            foreach (var pair in saveMap)
            {
                await(ApplyChangesAsync(pair.Key, pair.Value, dependencyGraph, saveMap, entitiesIdMap, sessionProvider, cancellationToken)).ConfigureAwait(false);
            }

            persistenceManager.ValidateDependencyGraph(dependencyGraph, context);
            saveChangesOptions?.ValidateDependencyGraph(dependencyGraph, context);

            var saveOrder = dependencyGraph.GetSaveOrder();

            await(persistenceManager.BeforeSaveChangesAsync(saveOrder, context, cancellationToken)).ConfigureAwait(false);
            var beforeSaveChangesTask = saveChangesOptions?.BeforeSaveChangesAsync(saveOrder, context, cancellationToken);

            if (beforeSaveChangesTask != null)
            {
                await(beforeSaveChangesTask).ConfigureAwait(false);
            }

            await(ProcessSavesAsync(saveOrder, persistenceManager, context, saveChangesOptions, sessionProvider, cancellationToken)).ConfigureAwait(false);

            await(persistenceManager.AfterSaveChangesAsync(saveOrder, context, cancellationToken)).ConfigureAwait(false);
            var afterSaveChangesTask = saveChangesOptions?.AfterSaveChangesAsync(saveOrder, context, cancellationToken);

            if (afterSaveChangesTask != null)
            {
                await(afterSaveChangesTask).ConfigureAwait(false);
            }

            await(FlushSessionsAsync(sessionProvider, cancellationToken)).ConfigureAwait(false);
            await(RefreshFromSessionAsync(saveMap, sessionProvider, cancellationToken)).ConfigureAwait(false);
            var keyMappings = GetKeyMappings(saveMap).ToList();

            await(persistenceManager.AfterFlushChangesAsync(context, keyMappings, cancellationToken)).ConfigureAwait(false);
            var afterFlushChangesTask = saveChangesOptions?.AfterFlushChangesAsync(context, keyMappings, cancellationToken);

            if (afterFlushChangesTask != null)
            {
                await(afterFlushChangesTask).ConfigureAwait(false);
            }

            UpdateClientEntities(context);

            return(keyMappings);
        }
Пример #25
0
 Task ISaveChangesOptions.AfterFlushChangesAsync(SaveChangesContext context, List <KeyMapping> keyMappings, CancellationToken cancellationToken)
 {
     return(AfterFlushChangesAction?.Invoke(context, keyMappings, cancellationToken));
 }
Пример #26
0
 /// <summary>
 /// The method that is called after the entity changes are applied and can be overriden to apply a general validation of the dependency graph.
 /// </summary>
 /// <param name="dependencyGraph">The dependency graph of the entities that are going to be saved.</param>
 /// <param name="context">The save changes context.</param>
 protected internal virtual void ValidateDependencyGraph(DependencyGraph dependencyGraph, SaveChangesContext context)
 {
 }
Пример #27
0
 Task ISaveChangesOptions.BeforeSaveEntityChangesAsync(EntityInfo entityInfo, SaveChangesContext context, CancellationToken cancellationToken)
 {
     return(BeforeSaveEntityChangesAction?.Invoke(entityInfo, context, cancellationToken) ?? Task.CompletedTask);
 }
Пример #28
0
 /// <summary>
 /// The method that is called before an entity is saved using NHibernate Save, Update or Delete methods from ISession.
 /// </summary>
 /// <param name="entityInfo">The entity info that is being saved.</param>
 /// <param name="context">The save changes context.</param>
 /// <returns>Whether the entity should be saved using the Save, Update or Delete methods from ISession.</returns>
 protected internal virtual void BeforeSaveEntityChanges(EntityInfo entityInfo, SaveChangesContext context)
 {
 }
Пример #29
0
 void ISaveChangesOptions.BeforeSaveEntityChanges(EntityInfo entityInfo, SaveChangesContext context)
 {
     BeforeSaveEntityChangesAction?.Invoke(entityInfo, context);
 }
Пример #30
0
 Task ISaveChangesOptions.BeforeSaveEntityChangesAsync(EntityInfo entityInfo, SaveChangesContext context, CancellationToken cancellationToken)
 {
     throw new NotSupportedException();
 }