/// <summary> /// Detaches all entities matching the passed <paramref name="predicate"/> from the current object context /// </summary> /// <param name="unchangedEntitiesOnly">When <c>true</c>, only entities in unchanged state will be detached.</param> /// <param name="deep">Whether to scan all navigation properties and detach them recursively also.</param> /// <returns>The count of detached entities</returns> public static int DetachEntities(this HookingDbContext ctx, Func <BaseEntity, bool> predicate, bool unchangedEntitiesOnly = true, bool deep = false) { Guard.NotNull(predicate, nameof(predicate)); var numDetached = 0; using (new DbContextScope(ctx, autoDetectChanges: false, lazyLoading: false)) { var entries = ctx.ChangeTracker.Entries <BaseEntity>().Where(Match).ToList(); HashSet <BaseEntity> objSet = deep ? new HashSet <BaseEntity>() : null; foreach (var entry in entries) { numDetached += ctx.DetachInternal(entry, objSet, deep); } return(numDetached); } bool Match(EntityEntry <BaseEntity> entry) { if (entry.State > EfState.Detached && predicate(entry.Entity)) { return(unchangedEntitiesOnly ? entry.State == EfState.Unchanged : true); } return(false); } }
private static int DetachInternal(this HookingDbContext ctx, BaseEntity obj, ISet <BaseEntity> objSet, bool deep) { if (obj == null) { return(0); } return(ctx.DetachInternal(ctx.Entry(obj), objSet, deep)); }
private static int DetachInternal(this HookingDbContext ctx, EntityEntry <BaseEntity> entry, ISet <BaseEntity> objSet, bool deep) { var obj = entry.Entity; int numDetached = 0; if (deep) { // This is to prevent an infinite recursion when the child object has a navigation property // that points back to the parent if (objSet != null && !objSet.Add(obj)) { return(0); } // Recursively detach all navigation properties foreach (var prop in FastProperty.GetProperties(obj.GetType()).Values) { if (typeof(BaseEntity).IsAssignableFrom(prop.Property.PropertyType)) { numDetached += ctx.DetachInternal(prop.GetValue(obj) as BaseEntity, objSet, deep); } else if (typeof(IEnumerable <BaseEntity>).IsAssignableFrom(prop.Property.PropertyType)) { var val = prop.GetValue(obj); if (val is IEnumerable <BaseEntity> list) { foreach (var item in list.ToList()) { numDetached += ctx.DetachInternal(item, objSet, deep); } } } } } entry.State = EfState.Detached; numDetached++; return(numDetached); }
public static int DetachEntity <TEntity>(this HookingDbContext ctx, TEntity entity, bool deep = false) where TEntity : BaseEntity { return(ctx.DetachInternal(entity, deep ? new HashSet <BaseEntity>() : null, deep)); }