public void MigrateDownloads(SmartObjectContext ctx) { var sql = "SELECT * FROM [Download] WHERE [MediaFileId] IS NULL AND [UseDownloadUrl] = 0"; var downloadStubs = ctx.SqlQuery <DownloadStub>(sql).ToDictionary(x => x.Id); var downloadsFolderId = _albumRegistry.GetAlbumByName(SystemAlbumProvider.Downloads)?.Id; var messagesFolderId = _albumRegistry.GetAlbumByName(SystemAlbumProvider.Messages)?.Id; var newFiles = new List <MediaFile>(); using (var scope = new DbContextScope(ctx, validateOnSave: false, hooksEnabled: false, autoCommit: false, autoDetectChanges: false)) { var messageTemplates = ctx.Set <MessageTemplate>() .Where(x => x.Attachment1FileId.HasValue || x.Attachment2FileId.HasValue || x.Attachment3FileId.HasValue) .ToList(); // Key = Download.Id var messageTemplatesDict = new Dictionary <int, MessageTemplate>(); foreach (var mt in messageTemplates) { if (mt.Attachment1FileId.HasValue) { messageTemplatesDict[mt.Attachment1FileId.Value] = mt; } if (mt.Attachment2FileId.HasValue) { messageTemplatesDict[mt.Attachment2FileId.Value] = mt; } if (mt.Attachment3FileId.HasValue) { messageTemplatesDict[mt.Attachment3FileId.Value] = mt; } } var hasPostProcessor = _isFsProvider || messageTemplatesDict.Count > 0; var query = ctx.Set <Download>().Where(x => x.MediaFileId == null); var pager = new FastPager <Download>(query, 1000); while (pager.ReadNextPage(out var downloads)) { foreach (var d in downloads) { var stub = downloadStubs.Get(d.Id); if (stub == null) { continue; } if (stub.UseDownloadUrl || string.IsNullOrEmpty(stub.Extension)) { // Something weird has happened in the past continue; } if (stub.Filename == "undefined" || string.IsNullOrEmpty(stub.Filename)) { stub.Filename = stub.Id.ToString(CultureInfo.InvariantCulture); } var isMailAttachment = false; if (messageTemplatesDict.TryGetValue(stub.Id, out var mt)) { isMailAttachment = true; } // Create and insert new MediaFile entity for the download var file = new MediaFile { CreatedOnUtc = stub.UpdatedOnUtc, UpdatedOnUtc = stub.UpdatedOnUtc, Extension = stub.Extension.TrimStart('.'), Name = stub.Filename.Truncate(292), // Extension appended later in MigrateFiles() MimeType = stub.ContentType, MediaType = MediaType.Image, // Resolved later in MigrateFiles() FolderId = isMailAttachment ? messagesFolderId : downloadsFolderId, IsTransient = stub.IsTransient, MediaStorageId = stub.MediaStorageId, Version = 0 // Ensure that this record gets processed by MigrateFiles() }; // Assign new file to download d.MediaFile = file; // To be able to move files later if (hasPostProcessor) { newFiles.Add(file); } } // Save to DB int num = scope.Commit(); if (hasPostProcessor) { var downloadsDict = downloads.ToDictionary(x => x.Id); if (_isFsProvider) { // Copy files from "Media/Downloads" to "Media/Storage" folder MoveDownloadFiles(newFiles.ToDictionary(x => x.Id), downloadsDict, downloadStubs); } // MessageTemplate attachments (Download > MediaFile) if (messageTemplatesDict.Count > 0) { ReRefMessageTemplateAttachments(ctx, messageTemplatesDict, downloadsDict); } newFiles.Clear(); } // Breathe ctx.DetachEntities <MessageTemplate>(); ctx.DetachEntities <Download>(deep: true); } } }