private async Task InternalCopyFileData(MediaFile file, MediaFile copy) { await _storageProvider.SaveAsync(copy, MediaStorageItem.FromStream(await _storageProvider.OpenReadAsync(file))); await _imageCache.DeleteAsync(copy); // Tags. await _db.LoadCollectionAsync(file, (MediaFile x) => x.Tags); var existingTagsIds = copy.Tags.Select(x => x.Id).ToList(); foreach (var tag in file.Tags) { if (!existingTagsIds.Contains(tag.Id)) { copy.Tags.Add(tag); existingTagsIds.Add(tag.Id); } } // Localized values. var languages = _languageService.GetAllLanguages(true); foreach (var language in languages) { var title = file.GetLocalized(x => x.Title, language.Id, false, false).Value; if (title.HasValue()) { await _localizedEntityService.ApplyLocalizedValueAsync(copy, x => x.Title, title, language.Id); } var alt = file.GetLocalized(x => x.Alt, language.Id, false, false).Value; if (alt.HasValue()) { await _localizedEntityService.ApplyLocalizedValueAsync(copy, x => x.Alt, alt, language.Id); } } await _db.SaveChangesAsync(); _db.DetachEntities <MediaTag>(); }
protected virtual async Task TrackManyCoreAsync(IEnumerable <MediaTrack> tracks, string albumName) { Guard.NotNull(tracks, nameof(tracks)); if (!tracks.Any()) { return; } using (var scope = new DbContextScope(_db, minHookImportance: HookImportance.Important, autoDetectChanges: false)) { // Get the album (necessary later to set FolderId)... MediaFolderNode albumNode = albumName.HasValue() ? _folderService.GetNodeByPath(albumName)?.Value : null; // Get distinct ids of all detected files... var mediaFileIds = tracks.Select(x => x.MediaFileId).Distinct().ToArray(); // fetch these files from database... var query = _db.MediaFiles .Include(x => x.Tracks) .Where(x => mediaFileIds.Contains(x.Id)); var isInstallation = !EngineContext.Current.Application.IsInstalled; if (isInstallation) { query = query.Where(x => x.Version == 1); } var files = await query.ToDictionaryAsync(x => x.Id); // for each media file relation to an entity... foreach (var track in tracks) { // fetch the file from local dictionary by its id... if (files.TryGetValue(track.MediaFileId, out var file)) { if (isInstallation) { // set album id as folder id (during installation there are no sub-folders) file.FolderId = albumNode?.Id; // remember that we processed tracks for this file already file.Version = 2; } if (track.Album.IsEmpty()) { if (albumNode != null) { // Overwrite track album if scope album was passed. track.Album = albumNode.Name; } else if (file.FolderId.HasValue) { // Determine album from file albumNode = _folderService.FindAlbum(file)?.Value; track.Album = albumNode?.Name; } } if (track.Album.IsEmpty()) { continue; // cannot track without album } if ((albumNode ?? _folderService.FindAlbum(file)?.Value)?.CanDetectTracks == false) { continue; // should not track in albums that do not support track detection } // add or remove the track from file if (track.Operation == MediaTrackOperation.Track) { file.Tracks.Add(track); } else { var dbTrack = file.Tracks.FirstOrDefault(x => x == track); if (dbTrack != null) { file.Tracks.Remove(track); _db.TryChangeState(dbTrack, EfState.Deleted); } } if (file.Tracks.Count > 0) { // A file with tracks can NEVER be transient file.IsTransient = false; } else if (_makeFilesTransientWhenOrphaned) { // But an untracked file can OPTIONALLY be transient file.IsTransient = true; } } } // Save whole batch to database int num = await _db.SaveChangesAsync(); if (num > 0) { // Breathe _db.DetachEntities <MediaFile>(deep: true); } } }
public async Task MigrateAsync(IEnumerable <LocaleResourceEntry> entries, bool updateTouchedResources = false) { Guard.NotNull(entries, nameof(entries)); if (!entries.Any() || !_languages.Any()) { return; } using (var scope = new DbContextScope(_db, autoDetectChanges: false, minHookImportance: HookImportance.Essential)) { var langMap = (await _languages .ToListAsync()) .ToDictionarySafe(x => x.LanguageCulture.EmptyNull().ToLower()); var toDelete = new List <LocaleStringResource>(); var toUpdate = new List <LocaleStringResource>(); var toAdd = new List <LocaleStringResource>(); bool IsEntryValid(LocaleResourceEntry entry, Language targetLang) { if (entry.Lang == null) { return(true); } var sourceLangCode = entry.Lang.ToLower(); if (targetLang != null) { var culture = targetLang.LanguageCulture; if (culture == sourceLangCode || culture.StartsWith(sourceLangCode + "-")) { return(true); } } else { if (langMap.ContainsKey(sourceLangCode)) { return(true); } if (langMap.Keys.Any(k => k.StartsWith(sourceLangCode + "-", StringComparison.OrdinalIgnoreCase))) { return(true); } } return(false); } // Remove all entries with invalid lang identifier var invalidEntries = entries.Where(x => !IsEntryValid(x, null)); if (invalidEntries.Any()) { entries = entries.Except(invalidEntries).ToArray(); } foreach (var lang in langMap) { var validEntries = entries.Where(x => IsEntryValid(x, lang.Value)).ToArray(); foreach (var entry in validEntries) { var dbRes = GetResource(entry.Key, lang.Value.Id, toAdd, out bool isLocal); if (dbRes == null && entry.Value.HasValue() && !entry.UpdateOnly) { // ADD action toAdd.Add(new LocaleStringResource { LanguageId = lang.Value.Id, ResourceName = entry.Key, ResourceValue = entry.Value }); } if (dbRes == null) { continue; } if (entry.Value == null) { // DELETE action if (isLocal) { toAdd.Remove(dbRes); } else { toDelete.Add(dbRes); } } else { if (isLocal) { dbRes.ResourceValue = entry.Value; continue; } // UPDATE action if (updateTouchedResources || !dbRes.IsTouched.GetValueOrDefault()) { dbRes.ResourceValue = entry.Value; toUpdate.Add(dbRes); if (toDelete.Contains(dbRes)) { toDelete.Remove(dbRes); } } } } } if (toAdd.Any() || toDelete.Any()) { // add new resources to context _resources.AddRange(toAdd); // remove deleted resources _resources.RemoveRange(toDelete); // save now int affectedRows = await _db.SaveChangesAsync(); _db.DetachEntities <Language>(); _db.DetachEntities <LocaleStringResource>(); } } }