/// <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); }
/// <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); }
public virtual void AddRange(IEnumerable entities) { DebugCheck.NotNull(entities); InternalContext.DetectChanges(); ActOnSet( entity => InternalContext.ObjectContext.AddObject(EntitySetName, entity), EntityState.Added, entities, "AddRange"); }
/// <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); }
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"); }
// <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(); } }
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); } }
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); }
/// <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()); }
/// <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); }