/// <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); }
/// <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); }
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); } } }
/// <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()); }
/// <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()); }
void ISaveChangesOptions.BeforeFetchEntities(SaveChangesContext context) { throw new NotSupportedException(); }
Task ISaveChangesOptions.BeforeFetchEntitiesAsync(SaveChangesContext context, CancellationToken cancellationToken) { return(BeforeFetchEntitiesAction?.Invoke(context, cancellationToken)); }
/// <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) { }
void ISaveChangesOptions.ValidateDependencyGraph(DependencyGraph dependencyGraph, SaveChangesContext context) { ValidateDependencyGraphAction?.Invoke(dependencyGraph, context); }
void ISaveChangesOptions.AfterFlushChanges(SaveChangesContext context, List <KeyMapping> keyMappings) { throw new NotSupportedException(); }
void ISaveChangesOptions.BeforeSaveEntityChanges(EntityInfo entityInfo, SaveChangesContext context) { throw new NotSupportedException(); }
Task ISaveChangesOptions.AfterSaveChangesAsync(List <EntityInfo> saveOrder, SaveChangesContext context, CancellationToken cancellationToken) { throw new NotSupportedException(); }
void ISaveChangesOptions.AfterSaveChanges(List <EntityInfo> saveOrder, SaveChangesContext context) { throw new NotSupportedException(); }
Task ISaveChangesOptions.BeforeApplyChangesAsync(SaveChangesContext context, CancellationToken cancellationToken) { throw new NotSupportedException(); }
void ISaveChangesOptions.AfterSaveChanges(List <EntityInfo> saveOrder, SaveChangesContext context) { AfterSaveChangesAction?.Invoke(saveOrder, context); }
void ISaveChangesOptions.BeforeApplyChanges(SaveChangesContext context) { BeforeApplyChangesAction?.Invoke(context); }
void ISaveChangesOptions.BeforeFetchEntities(SaveChangesContext context) { BeforeFetchEntitiesAction?.Invoke(context); }
/// <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) { }
void ISaveChangesOptions.BeforeApplyChanges(SaveChangesContext context) { throw new NotSupportedException(); }
void ISaveChangesOptions.AfterFlushChanges(SaveChangesContext context, List <KeyMapping> keyMappings) { AfterFlushChangesAction?.Invoke(context, keyMappings); }
Task ISaveChangesOptions.BeforeApplyChangesAsync(SaveChangesContext context, CancellationToken cancellationToken) { return(BeforeApplyChangesAction?.Invoke(context, cancellationToken) ?? Task.CompletedTask); }
Task ISaveChangesOptions.AfterFlushChangesAsync(SaveChangesContext context, List <KeyMapping> keyMappings, CancellationToken cancellationToken) { throw new NotSupportedException(); }
Task ISaveChangesOptions.AfterSaveChangesAsync(List <EntityInfo> saveOrder, SaveChangesContext context, CancellationToken cancellationToken) { return(AfterSaveChangesAction?.Invoke(saveOrder, context, cancellationToken) ?? Task.CompletedTask); }
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); }
Task ISaveChangesOptions.AfterFlushChangesAsync(SaveChangesContext context, List <KeyMapping> keyMappings, CancellationToken cancellationToken) { return(AfterFlushChangesAction?.Invoke(context, keyMappings, cancellationToken)); }
/// <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) { }
Task ISaveChangesOptions.BeforeSaveEntityChangesAsync(EntityInfo entityInfo, SaveChangesContext context, CancellationToken cancellationToken) { return(BeforeSaveEntityChangesAction?.Invoke(entityInfo, context, cancellationToken) ?? Task.CompletedTask); }
/// <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) { }
void ISaveChangesOptions.BeforeSaveEntityChanges(EntityInfo entityInfo, SaveChangesContext context) { BeforeSaveEntityChangesAction?.Invoke(entityInfo, context); }
Task ISaveChangesOptions.BeforeSaveEntityChangesAsync(EntityInfo entityInfo, SaveChangesContext context, CancellationToken cancellationToken) { throw new NotSupportedException(); }