/// <summary>
        ///     Checks if the <see cref="DbContext" /> is tracking any new, deleted, or changed entities or
        ///     relationships that will be sent to the database if <see cref="DbContext.SaveChanges" /> is called.
        /// </summary>
        /// <remarks>
        ///     Functionally, calling this method is equivalent to checking if there are any entities or
        ///     relationships in the Added, Updated, or Deleted state.
        ///     Note that this method calls <see cref="DbChangeTracker.DetectChanges" /> unless
        ///     <see cref="DbContextConfiguration.AutoDetectChangesEnabled" /> has been set to false.
        /// </remarks>
        /// <returns>
        ///     True if underlying <see cref="DbContext" /> have changes, else false.
        /// </returns>
        public bool HasChanges()
        {
            _internalContext.DetectChanges();

            var objectStateManager = _internalContext.ObjectContext.ObjectStateManager;

            DebugCheck.NotNull(objectStateManager);

            return(objectStateManager.GetObjectStateEntriesCount(EntityState.Added | EntityState.Deleted | EntityState.Modified) > 0);
        }
示例#2
0
        /// <summary>
        ///     Finds an entity with the given primary key values.
        ///     If an entity with the given primary key values exists in the context, then it is
        ///     returned immediately without making a request to the store.  Otherwise, a request
        ///     is made to the store for an entity with the given primary key values and this entity,
        ///     if found, is attached to the context and returned.  If no entity is found in the
        ///     context or the store, then null is returned.
        /// </summary>
        /// <remarks>
        ///     The ordering of composite key values is as defined in the EDM, which is in turn as defined in
        ///     the designer, by the Code First fluent API, or by the DataMember attribute.
        /// </remarks>
        /// <param name="keyValues"> The values of the primary key for the entity to be found. </param>
        /// <returns> The entity found, or null. </returns>
        /// <exception cref="InvalidOperationException">Thrown if multiple entities exist in the context with the primary key values given.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the type of entity is not part of the data model for this context.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the types of the key values do not match the types of the key values for the entity type to be found.</exception>
        /// <exception cref="InvalidOperationException">Thrown if the context has been disposed.</exception>
        public TEntity Find(params object[] keyValues)
        {
            InternalContext.ObjectContext.AsyncMonitor.EnsureNotEntered();

            // This DetectChanges is useful in the case where objects are added to the graph and then the user
            // attempts to find one of those added objects.
            InternalContext.DetectChanges();

            var key = new WrappedEntityKey(EntitySet, EntitySetName, keyValues, "keyValues");

            // First, check for the entity in the state manager.  This includes first checking
            // for non-Added objects that match the key.  If the entity was not found, then
            // we check for Added objects.  We don't just use GetObjectByKey
            // because it would go to the store before checking for Added objects, and also
            // because if the object found was of the wrong type then it would still get into
            // the state manager.
            var entity = FindInStateManager(key) ?? FindInStore(key, "keyValues");

            if (entity != null &&
                !(entity is TEntity))
            {
                throw Error.DbSet_WrongEntityTypeFound(entity.GetType().Name, typeof(TEntity).Name);
            }
            return((TEntity)entity);
        }
示例#3
0
        public virtual void AddRange(IEnumerable entities)
        {
            DebugCheck.NotNull(entities);

            InternalContext.DetectChanges();

            ActOnSet(
                entity => InternalContext.ObjectContext.AddObject(EntitySetName, entity), EntityState.Added, entities, "AddRange");
        }
示例#4
0
        /// <summary>
        ///     Marks the given entity as Deleted such that it will be deleted from the database when SaveChanges
        ///     is called.  Note that the entity must exist in the context in some other state before this method
        ///     is called.
        /// </summary>
        /// <remarks>
        ///     Note that if the entity exists in the context in the Added state, then this method
        ///     will cause it to be detached from the context.  This is because an Added entity is assumed not to
        ///     exist in the database such that trying to delete it does not make sense.
        ///     This method is virtual so that it can be mocked.
        /// </remarks>
        /// <param name="entity"> The entity to remove. </param>
        public virtual void Remove(object entity)
        {
            DebugCheck.NotNull(entity);

            if (!(entity is TEntity))
            {
                throw Error.DbSet_BadTypeForAddAttachRemove("Remove", entity.GetType().Name, typeof(TEntity).Name);
            }

            InternalContext.DetectChanges();

            InternalContext.ObjectContext.DeleteObject(entity);
        }
示例#5
0
        public virtual void RemoveRange(IEnumerable entities)
        {
            DebugCheck.NotNull(entities);

            // prevent "enumerator was changed" exception
            // if entities is syncronized with other elements
            // (e.g: local view from DbSet.Local.)
            var copyOfEntities = entities.Cast <object>().ToList();

            InternalContext.DetectChanges();

            ActOnSet(
                entity => InternalContext.ObjectContext.DeleteObject(entity), EntityState.Deleted, copyOfEntities, "RemoveRange");
        }
示例#6
0
        // <summary>
        // This method checks whether an entity is already in the context.  If it is, then the state
        // is changed to the new state given.  If it isn't, then the action delegate is executed to
        // either Add or Attach the entity.
        // </summary>
        // <param name="action"> A delegate to Add or Attach the entity. </param>
        // <param name="newState"> The new state to give the entity if it is already in the context. </param>
        // <param name="entity"> The entity. </param>
        // <param name="methodName"> Name of the method. </param>
        private void ActOnSet(Action action, EntityState newState, object entity, string methodName)
        {
            DebugCheck.NotNull(entity);

            if (!(entity is TEntity))
            {
                throw Error.DbSet_BadTypeForAddAttachRemove(methodName, entity.GetType().Name, typeof(TEntity).Name);
            }

            InternalContext.DetectChanges();

            ObjectStateEntry stateEntry;
            if (InternalContext.ObjectContext.ObjectStateManager.TryGetObjectStateEntry(entity, out stateEntry))
            {
                // Will be no-op if state is already newState.
                stateEntry.ChangeState(newState);
            }
            else
            {
                action();
            }
        }
示例#7
0
        public virtual void RemoveRange(IEnumerable entities)
        {
            DebugCheck.NotNull(entities);

            // prevent "enumerator was changed" exception
            // if entities is syncronized with other elements
            // (e.g: local view from DbSet.Local.)
            var copyOfEntities = entities.Cast <object>().ToList();

            InternalContext.DetectChanges();

            foreach (var entity in copyOfEntities)
            {
                Check.NotNull(entity, "entity");

                if (!(entity is TEntity))
                {
                    throw Error.DbSet_BadTypeForAddAttachRemove("RemoveRange", entity.GetType().Name, typeof(TEntity).Name);
                }

                InternalContext.ObjectContext.DeleteObject(entity);
            }
        }
示例#8
0
        private async Task <TEntity> FindInternalAsync(CancellationToken cancellationToken, params object[] keyValues)
        {
            // This DetectChanges is useful in the case where objects are added to the graph and then the user
            // attempts to find one of those added objects.
            InternalContext.DetectChanges();

            var key = new WrappedEntityKey(EntitySet, EntitySetName, keyValues, "keyValues");

            // First, check for the entity in the state manager.  This includes first checking
            // for non-Added objects that match the key.  If the entity was not found, then
            // we check for Added objects.  We don't just use GetObjectByKey
            // because it would go to the store before checking for Added objects, and also
            // because if the object found was of the wrong type then it would still get into
            // the state manager.
            var entity = FindInStateManager(key)
                         ?? await FindInStoreAsync(key, "keyValues", cancellationToken).ConfigureAwait(continueOnCapturedContext: false);

            if (entity != null &&
                !(entity is TEntity))
            {
                throw Error.DbSet_WrongEntityTypeFound(entity.GetType().Name, typeof(TEntity).Name);
            }
            return((TEntity)entity);
        }
示例#9
0
        /// <summary>
        /// Checks if the <see cref="DbContext" /> is tracking any new, deleted, or changed entities or
        /// relationships that will be sent to the database if <see cref="DbContext.SaveChanges" /> is called.
        /// </summary>
        /// <remarks>
        /// Functionally, calling this method is equivalent to checking if there are any entities or
        /// relationships in the Added, Updated, or Deleted state.
        /// Note that this method calls <see cref="DbChangeTracker.DetectChanges" /> unless
        /// <see cref="DbContextConfiguration.AutoDetectChangesEnabled" /> has been set to false.
        /// </remarks>
        /// <returns>
        /// True if underlying <see cref="DbContext" /> have changes, else false.
        /// </returns>
        public bool HasChanges()
        {
            _internalContext.DetectChanges();

            return(_internalContext.ObjectContext.ObjectStateManager.HasChanges());
        }
示例#10
0
 /// <summary>
 ///     Detects changes made to the properties and relationships of POCO entities.  Note that some types of
 ///     entity (such as change tracking proxies and entities that derive from
 ///     <see
 ///         cref="System.Data.Entity.Core.Objects.DataClasses.EntityObject" />
 ///     )
 ///     report changes automatically and a call to DetectChanges is not normally needed for these types of entities.
 ///     Also note that normally DetectChanges is called automatically by many of the methods of <see cref="DbContext" />
 ///     and its related classes such that it is rare that this method will need to be called explicitly.
 ///     However, it may be desirable, usually for performance reasons, to turn off this automatic calling of
 ///     DetectChanges using the AutoDetectChangesEnabled flag from <see cref="DbContext.Configuration" />.
 /// </summary>
 public void DetectChanges()
 {
     _internalContext.DetectChanges(force: true);
 }