示例#1
0
        private void PageEntities <TEntity>(
            SmartObjectContext context,
            DbSet <MediaStorage> mediaStorages,
            IOrderedQueryable <TEntity> query,
            Action <TEntity> moveEntity) where TEntity : BaseEntity, IHasMedia
        {
            var pageIndex = 0;
            IPagedList <TEntity> entities = null;

            do
            {
                if (entities != null)
                {
                    // detach all entities from previous page to save memory
                    context.DetachAll(false);
                    entities.Clear();
                    entities = null;
                }

                // load max 1000 entities at once
                entities = new PagedList <TEntity>(query, pageIndex++, PAGE_SIZE);

                entities.Each(x => moveEntity(x));

                // save the current batch to database
                context.SaveChanges();
            }while (entities.HasNextPage);
        }
示例#2
0
        protected virtual void PageEntities <TEntity>(IOrderedQueryable <TEntity> query, Action <TEntity> moveEntity) where TEntity : BaseEntity, IHasMedia
        {
            var pageIndex = 0;
            IPagedList <TEntity> entities = null;

            do
            {
                if (entities != null)
                {
                    // detach all entities from previous page to save memory
                    _services.DbContext.DetachEntities(entities);
                    entities.Clear();
                    entities = null;
                }

                // load max 100 entities at once
                entities = new PagedList <TEntity>(query, pageIndex++, PAGE_SIZE);

                entities.Each(x => moveEntity(x));

                // save the current batch to database
                _services.DbContext.SaveChanges();
            }while (entities.HasNextPage);
        }
示例#3
0
        protected int MovePictures(bool toDb)
        {
            // long running operation, therefore some code chunks are redundant here in order to boost performance

            // a list of ALL file paths that were either deleted or created
            var affectedFiles = new List <string>(1000);

            var ctx    = _pictureRepository.Context;
            var failed = false;
            int i      = 0;

            using (var scope = new DbContextScope(ctx: ctx, autoDetectChanges: false, proxyCreation: false, validateOnSave: false, autoCommit: false))
            {
                using (var tx = ctx.BeginTransaction())
                {
                    // we are about to process data in chunks but want to commit ALL at once when ALL chunks have been processed successfully.
                    try
                    {
                        int pageIndex = 0;
                        IPagedList <Picture> pictures = null;

                        do
                        {
                            if (pictures != null)
                            {
                                // detach all entities from previous page to save memory
                                ctx.DetachEntities(pictures);

                                // breathe
                                pictures.Clear();
                                pictures = null;
                            }

                            // load max 500 picture entities at once
                            pictures = this.GetPictures(pageIndex, 500);
                            pageIndex++;

                            foreach (var picture in pictures)
                            {
                                string filePath = null;

                                if (!toDb)
                                {
                                    if (picture.PictureBinary != null && picture.PictureBinary.Length > 0)
                                    {
                                        // save picture as file
                                        SavePictureInFile(picture.Id, picture.PictureBinary, picture.MimeType, out filePath);
                                    }
                                    // remove picture binary from DB
                                    picture.PictureBinary = new byte[0];
                                }
                                else
                                {
                                    // load picture binary from file and set in DB
                                    var picBinary = LoadPictureFromFile(picture.Id, picture.MimeType, out filePath);
                                    if (picBinary.Length > 0)
                                    {
                                        picture.PictureBinary = picBinary;
                                    }
                                }

                                // remember file path: we must be able to rollback IO operations on transaction failure
                                if (filePath.HasValue())
                                {
                                    affectedFiles.Add(filePath);
                                    //picture.IsNew = true;
                                }

                                // explicitly attach modified entity to context, because we disabled AutoCommit
                                picture.UpdatedOnUtc = DateTime.UtcNow;
                                _pictureRepository.Update(picture);

                                i++;
                            }

                            // save the current batch to DB
                            ctx.SaveChanges();
                        } while (pictures.HasNextPage);

                        // FIRE!
                        tx.Commit();
                    }
                    catch (Exception ex)
                    {
                        failed = true;
                        tx.Rollback();
                        _settingService.SetSetting <bool>("Media.Images.StoreInDB", !toDb);
                        _notifier.Error(ex.Message);
                        _logger.Error(ex);
                    }
                }
            }

            if (affectedFiles.Count > 0)
            {
                if ((toDb && !failed) || (!toDb && failed))
                {
                    // FS > DB sucessful OR DB > FS failed: delete all physical files
                    // run a background task for the deletion of files (fire & forget)
                    Task.Factory.StartNew(state =>
                    {
                        var files = state as string[];
                        foreach (var path in files)
                        {
                            if (File.Exists(path))
                            {
                                File.Delete(path);
                            }
                        }
                    }, affectedFiles.ToArray()).ConfigureAwait(false);
                }

                // shrink database (only when DB > FS and success)
                if (!toDb && !failed)
                {
                    ctx.ShrinkDatabase();
                }
            }

            return(i);
        }