/// <summary> /// Updates the database with new or changed transformations. /// </summary> /// <returns>An update result which may or may not have succeeded.</returns> public async Task <UpdateTransformationsResult> UpdateTransformationDatabaseAsync() { uint addedSpecies = 0; uint updatedSpecies = 0; var bundledSpeciesResult = await _content.DiscoverBundledSpeciesAsync(); if (!bundledSpeciesResult.IsSuccess) { return(UpdateTransformationsResult.FromError(bundledSpeciesResult)); } foreach (var species in bundledSpeciesResult.Entity.OrderBy(s => s.GetSpeciesDepth())) { if (await IsSpeciesNameUniqueAsync(species.Name)) { // Add a new species await _database.Species.AddAsync(species); ++addedSpecies; } else { // There's an existing species with this name var existingSpecies = (await GetSpeciesByNameAsync(species.Name)).Entity; species.ID = existingSpecies.ID; var existingEntry = _database.Entry(existingSpecies); existingEntry.CurrentValues.SetValues(species); if (existingEntry.State == EntityState.Modified) { ++updatedSpecies; } } await _database.SaveChangesAsync(); } uint addedTransformations = 0; uint updatedTransformations = 0; var availableSpecies = await GetAvailableSpeciesAsync(); foreach (var species in availableSpecies) { var bundledTransformationsResult = await _content.DiscoverBundledTransformationsAsync(this, species); if (!bundledTransformationsResult.IsSuccess) { return(UpdateTransformationsResult.FromError(bundledTransformationsResult)); } foreach (var transformation in bundledTransformationsResult.Entity) { if (await IsPartAndSpeciesCombinationUniqueAsync(transformation.Part, transformation.Species)) { // Add a new transformation await _database.Transformations.AddAsync(transformation); ++addedTransformations; } else { // We just take the first one, since species can't define composite parts individually var existingTransformation = ( await GetTransformationsByPartAndSpeciesAsync ( transformation.Part, transformation.Species ) ).Entity.First(); // Override the new data's ID to match the existing one transformation.ID = existingTransformation.ID; var existingEntry = _database.Entry(existingTransformation); existingEntry.CurrentValues.SetValues(transformation); // Workarounds for some broken EF core behaviour var baseColourNeedsUpdate = !existingTransformation.DefaultBaseColour .IsSameColourAs(transformation.DefaultBaseColour); if (baseColourNeedsUpdate) { // This catches null-to-null changes if (existingTransformation.DefaultBaseColour != transformation.DefaultBaseColour) { existingEntry.State = EntityState.Modified; } existingTransformation.DefaultBaseColour = transformation.DefaultBaseColour.Clone(); } var patternColourNeedsUpdate = existingTransformation.DefaultPatternColour is null || !existingTransformation.DefaultPatternColour .IsSameColourAs(transformation.DefaultPatternColour); if (patternColourNeedsUpdate) { // This catches null-to-null changes if (existingTransformation.DefaultPatternColour != transformation.DefaultPatternColour) { existingEntry.State = EntityState.Modified; } existingTransformation.DefaultPatternColour = transformation.DefaultPatternColour?.Clone(); } if (existingEntry.State == EntityState.Modified) { ++updatedTransformations; } } await _database.SaveChangesAsync(); } } return(UpdateTransformationsResult.FromSuccess ( addedSpecies, addedTransformations, updatedSpecies, updatedTransformations )); }