/// <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);
        }
Beispiel #2
0
        /// <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));
        }
Beispiel #3
0
        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();
        }
Beispiel #4
0
        /// <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>();
     }
 }
Beispiel #6
0
        /// <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);
        }
Beispiel #7
0
        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);
        }
Beispiel #8
0
        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();
        }
Beispiel #9
0
        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;
        }
Beispiel #13
0
 /// <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));
 }
Beispiel #14
0
 /// <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));
 }