/// <summary> /// Constructs a grouper based on the contents of the given entity state manager. /// </summary> /// <param name="stateManager">Entity state manager containing changes to be processed.</param> /// <param name="metadataWorkspace">Metadata workspace.</param> /// <param name="connection">Map connection</param> /// <param name="commandTimeout">Timeout for update commands; null means 'use provider default'</param> private UpdateTranslator(IEntityStateManager stateManager, MetadataWorkspace metadataWorkspace, EntityConnection connection, int? commandTimeout) { EntityUtil.CheckArgumentNull(stateManager, "stateManager"); EntityUtil.CheckArgumentNull(metadataWorkspace, "metadataWorkspace"); EntityUtil.CheckArgumentNull(connection, "connection"); // propagation state m_changes = new Dictionary<EntitySetBase, ChangeNode>(); m_functionChanges = new Dictionary<EntitySetBase, List<ExtractedStateEntry>>(); m_stateEntries = new List<IEntityStateEntry>(); m_knownEntityKeys = new Set<EntityKey>(); m_requiredEntities = new Dictionary<EntityKey, AssociationSet>(); m_optionalEntities = new Set<EntityKey>(); m_includedValueEntities = new Set<EntityKey>(); // workspace state m_metadataWorkspace = metadataWorkspace; m_viewLoader = metadataWorkspace.GetUpdateViewLoader(); m_stateManager = stateManager; // ancillary propagation services m_recordConverter = new RecordConverter(this); m_constraintValidator = new RelationshipConstraintValidator(this); m_providerServices = DbProviderServices.GetProviderServices(connection.StoreProviderFactory); m_connection = connection; m_commandTimeout = commandTimeout; // metadata cache m_extractorMetadata = new Dictionary<Tuple<EntitySetBase, StructuralType>, ExtractorMetadata>(); ; // key management KeyManager = new KeyManager(this); KeyComparer = CompositeKey.CreateComparer(KeyManager); }
/// <summary> /// Persist modifications described in the given cache. /// </summary> /// <param name="entityCache">Entity cache containing changes to persist to the store.</param> /// <returns>Number of cache entries affected by the udpate.</returns> public Int32 Update(IEntityStateManager entityCache) { EntityUtil.CheckArgumentNull(entityCache, "entityCache"); if (!IsStateManagerDirty(entityCache)) { return(0); } // Check that we have a connection before we proceed if (_connection == null) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_NoConnectionForAdapter); } // Check that the store connection is available if (_connection.StoreProviderFactory == null || this._connection.StoreConnection == null) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_NoStoreConnectionForUpdate); } // Check that the connection is open before we proceed if (ConnectionState.Open != _connection.State) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ClosedConnectionForUpdate); } return(UpdateTranslator.Update(entityCache, this)); }
public void ProviderShouldTrackPropertyChanges() { IEntityStateManager manager = GetStateManager(); var stateModel = GetModel(); var snapshot = manager.CreateSnapshot(stateModel); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Guid)).ShouldBeFalse(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.String)).ShouldBeFalse(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Int)).ShouldBeFalse(); stateModel.Int = int.MaxValue; stateModel.String = null; stateModel.Guid = Guid.Empty; snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Guid)).ShouldBeTrue(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.String)).ShouldBeTrue(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Int)).ShouldBeTrue(); stateModel.Int = IntValue; stateModel.String = StringValue; stateModel.Guid = GuidValue; snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Guid)).ShouldBeFalse(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.String)).ShouldBeFalse(); snapshot.HasChanges(stateModel, ToolkitExtensions.GetMemberName <EntityStateModel>(() => model => model.Int)).ShouldBeFalse(); }
/// <summary> /// Determine whether the cache has changes to apply. /// </summary> /// <param name="entityCache"> ObjectStateManager to check. Must not be null. </param> /// <returns> true if cache contains changes entries; false otherwise </returns> private static bool IsStateManagerDirty(IEntityStateManager entityCache) { DebugCheck.NotNull(entityCache); // this call to GetCacheEntries is constant time (the ObjectStateManager implementation // maintains an explicit list of entries in each state) return(entityCache.GetEntityStateEntries(EntityState.Added | EntityState.Deleted | EntityState.Modified).Any()); }
internal override void OnInitializedInternal() { if (StateManager == null) { StateManager = IocContainer.Get <IEntityStateManager>(); } if (ValidatorProvider == null) { ValidatorProvider = IocContainer.Get <IValidatorProvider>(); } }
/// <summary> /// Determine whether the cache has changes to apply. /// </summary> /// <param name="entityCache">ObjectStateManager to check. Must not be null.</param> /// <returns>true if cache contains changes entries; false otherwise</returns> private static bool IsStateManagerDirty(IEntityStateManager entityCache) { Debug.Assert(null != entityCache); bool hasChanges = false; // this call to GetCacheEntries is constant time (the ObjectStateManager implementation // maintains an explicit list of entries in each state) foreach (ObjectStateEntry entry in entityCache.GetEntityStateEntries( EntityState.Added | EntityState.Deleted | EntityState.Modified)) { hasChanges = true; break; } return(hasChanges); }
public void ProviderShouldSaveAndApplyState() { IEntityStateManager manager = GetStateManager(); var stateModel = GetModel(); manager.CreateSnapshot(stateModel); stateModel.Int = int.MaxValue; stateModel.String = null; stateModel.Guid = Guid.Empty; stateModel.Guid.ShouldEqual(Guid.Empty); stateModel.String.ShouldBeNull(); stateModel.Int.ShouldEqual(int.MaxValue); }
public void ProviderShouldTrackObjectChanges() { IEntityStateManager manager = GetStateManager(); var stateModel = GetModel(); var snapshot = manager.CreateSnapshot(stateModel); snapshot.HasChanges(stateModel).ShouldBeFalse(); stateModel.Int = int.MaxValue; snapshot.HasChanges(stateModel).ShouldBeTrue(); stateModel.Int = IntValue; snapshot.HasChanges(stateModel).ShouldBeFalse(); stateModel.String = null; snapshot.HasChanges(stateModel).ShouldBeTrue(); stateModel.String = StringValue; snapshot.HasChanges(stateModel).ShouldBeFalse(); stateModel.Guid = Guid.Empty; snapshot.HasChanges(stateModel).ShouldBeTrue(); stateModel.Guid = GuidValue; snapshot.HasChanges(stateModel).ShouldBeFalse(); }
private T Update <T>( IEntityStateManager entityCache, T noChangesResult, Func <UpdateTranslator, T> updateFunction, bool throwOnClosedConnection) { if (!IsStateManagerDirty(entityCache)) { return(noChangesResult); } // Check that we have a connection before we proceed if (_connection == null) { throw Error.EntityClient_NoConnectionForAdapter(); } // Check that the store connection is available if (_connection.StoreProviderFactory == null || _connection.StoreConnection == null) { throw Error.EntityClient_NoStoreConnectionForUpdate(); } // Check that the connection is open before we proceed if (throwOnClosedConnection && (ConnectionState.Open != _connection.State)) { throw Error.EntityClient_ClosedConnectionForUpdate(); } var updateTranslator = _updateTranslatorFactory(entityCache, this); return(updateFunction(updateTranslator)); }
/// <summary> /// Persist modifications described in the given cache. /// </summary> /// <param name="entityCache">Entity cache containing changes to persist to the store.</param> /// <returns>Number of cache entries affected by the udpate.</returns> public Int32 Update(IEntityStateManager entityCache) { EntityUtil.CheckArgumentNull(entityCache, "entityCache"); if (!IsStateManagerDirty(entityCache)) { return 0; } // Check that we have a connection before we proceed if (_connection == null) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_NoConnectionForAdapter); } // Check that the store connection is available if (_connection.StoreProviderFactory == null || this._connection.StoreConnection == null) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_NoStoreConnectionForUpdate); } // Check that the connection is open before we proceed if (ConnectionState.Open != _connection.State) { throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ClosedConnectionForUpdate); } return UpdateTranslator.Update(entityCache, this); }
/// <summary> /// Determine whether the cache has changes to apply. /// </summary> /// <param name="entityCache">ObjectStateManager to check. Must not be null.</param> /// <returns>true if cache contains changes entries; false otherwise</returns> private static bool IsStateManagerDirty(IEntityStateManager entityCache) { Debug.Assert(null != entityCache); bool hasChanges = false; // this call to GetCacheEntries is constant time (the ObjectStateManager implementation // maintains an explicit list of entries in each state) foreach (ObjectStateEntry entry in entityCache.GetEntityStateEntries( EntityState.Added | EntityState.Deleted | EntityState.Modified)) { hasChanges = true; break; } return hasChanges; }
/// <summary> /// Persists stateManager changes to the store. /// </summary> /// <param name="stateManager">StateManager containing changes to persist.</param> /// <param name="adapter">Map adapter requesting the changes.</param> /// <returns>Total number of state entries affected</returns> internal static Int32 Update(IEntityStateManager stateManager, IEntityAdapter adapter) { // provider/connection details EntityConnection connection = (EntityConnection)adapter.Connection; MetadataWorkspace metadataWorkspace = connection.GetMetadataWorkspace(); int? commandTimeout = adapter.CommandTimeout; UpdateTranslator translator = new UpdateTranslator(stateManager, metadataWorkspace, connection, commandTimeout); // tracks values for identifiers in this session Dictionary<int, object> identifierValues = new Dictionary<int, object>(); // tracks values for generated values in this session List<KeyValuePair<PropagatorResult, object>> generatedValues = new List<KeyValuePair<PropagatorResult, object>>(); IEnumerable<UpdateCommand> orderedCommands = translator.ProduceCommands(); // used to track the source of commands being processed in case an exception is thrown UpdateCommand source = null; try { foreach (UpdateCommand command in orderedCommands) { // Remember the data sources so that we can throw meaningful exception source = command; long rowsAffected = command.Execute(translator, connection, identifierValues, generatedValues); translator.ValidateRowsAffected(rowsAffected, source); } } catch (Exception e) { // we should not be wrapping all exceptions if (UpdateTranslator.RequiresContext(e)) { throw EntityUtil.Update(System.Data.Entity.Strings.Update_GeneralExecutionException, e, translator.DetermineStateEntriesFromSource(source)); } throw; } translator.BackPropagateServerGen(generatedValues); int totalStateEntries = translator.AcceptChanges(adapter); return totalStateEntries; }
/// <summary> /// An asynchronous version of Update, which /// persists modifications described in the given cache. /// </summary> /// <param name="entityCache"> Entity cache containing changes to persist to the store. </param> /// <param name="cancellationToken"> The token to monitor for cancellation requests. </param> /// <returns> A Task containing the number of cache entries affected by the update. </returns> public Task <int> UpdateAsync(IEntityStateManager entityCache, CancellationToken cancellationToken) { return(Update(entityCache, Task.FromResult(0), ut => ut.UpdateAsync(cancellationToken), true)); }
/// <summary> /// Persist modifications described in the given cache. /// </summary> /// <param name="entityCache"> Entity cache containing changes to persist to the store. </param> /// <returns> Number of cache entries affected by the udpate. </returns> public int Update(IEntityStateManager entityCache, bool throwOnClosedConnection = true) { return(Update(entityCache, 0, ut => ut.Update(), throwOnClosedConnection)); }