public void Equals_SameBanDifferentID_ReturnTrue() { var source = new BanSource() { Display = "test source", Name = "test", RoleplayLevel = RoleplayLevel.Medium, Id = 3 }; var banA = new Ban() { Id = 12, CKey = "test", BannedOn = DateTime.MinValue, BannedBy = "tester", BanType = BanType.Server, Reason = "what a great test", Source = source.Id, SourceNavigation = source }; var banB = new Ban() { Id = 0, CKey = "test", BannedOn = DateTime.MinValue, BannedBy = "tester", BanType = BanType.Server, Reason = "what a great test", Source = source.Id, SourceNavigation = source }; var comparer = BanEqualityComparer.Instance; Assert.True(comparer.Equals(banA, banB), "Two bans equal by internal values should be equal"); Assert.True(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans equal by internal values should have equal hashcodes"); }
public void Equals_SameBanIDDifferentSource_ReturnFalse() { var sourceA = new BanSource() { Display = "test source A", Name = "testA", RoleplayLevel = RoleplayLevel.Medium, Id = 3 }; var sourceB = new BanSource() { Display = "test source B", Name = "testB", RoleplayLevel = RoleplayLevel.Medium, Id = 4 }; var banA = new Ban() { BanID = "epic", CKey = "doesn't matter", Source = sourceA.Id, SourceNavigation = sourceA }; var banB = new Ban() { BanID = "epic", CKey = "different", Source = sourceB.Id, SourceNavigation = sourceB }; var comparer = BanEqualityComparer.Instance; Assert.False(comparer.Equals(banA, banB), "Two bans from different sources should not be equal by BanID"); Assert.False(comparer.GetHashCode(banA) == comparer.GetHashCode(banB), "Two bans from different sources should not have equal hashcodes"); }
public async Task RunImports() { foreach (var file in Directory.GetFiles("FlatData/JSON/")) { var fileData = File.ReadAllText(file); FlatDataFile deserializedData = null; try { deserializedData = JsonSerializer.Deserialize <FlatDataFile>(fileData, new JsonSerializerOptions() { PropertyNameCaseInsensitive = true }); } catch (Exception ex) { _logger.LogError($"Failed to deserialize flat data file: '{file}'"); continue; } var lastVersion = await _dbContext.FlatBansVersion .Where(x => x.Name == deserializedData.Name) .OrderByDescending(x => x.Version) .FirstOrDefaultAsync(); // We need to update the data if (lastVersion == null || lastVersion.Version < deserializedData.Version) { _logger.LogInformation(lastVersion == null ? $"Data from '{deserializedData.Name}' missing from database, adding..." : $"Out-of-date data found from '{deserializedData.Name} (v{lastVersion.Version}, updating to v{deserializedData.Version}), updating...'"); try { // Make this an atomic operation to ensure failed imports don't leave holes in the data using var transaction = await _dbContext.Database.BeginTransactionAsync(); // Update any ban sources if necessary var toUpdate = await _dbContext.BanSources .Where(x => deserializedData.Sources.Select(x => x.Name).Contains(x.Name)) .Include(x => x.Bans) .ToListAsync(); foreach (var source in toUpdate) { var match = deserializedData.Sources.First(x => x.Name == source.Name); if (match.RoleplayLevel != source.RoleplayLevel || match.Display != source.Display) { _logger.LogInformation($"Updating ban source '{source.Name}', found mis-matching metadata with new version of flat dataset"); source.Display = match.Display; source.RoleplayLevel = match.RoleplayLevel; } } await _dbContext.SaveChangesAsync(); // Remove any existing bans for each updated source foreach (var source in toUpdate) { _dbContext.Bans.RemoveRange(source.Bans); } await _dbContext.SaveChangesAsync(); // Add any new ban sources that were not present in old file version foreach (var source in deserializedData.Sources.Where(x => !toUpdate.Select(y => y.Name).Contains(x.Name))) { var copy = new BanSource() { Display = source.Display, Name = source.Name, RoleplayLevel = source.RoleplayLevel }; _dbContext.BanSources.Add(copy); toUpdate.Add(copy); } await _dbContext.SaveChangesAsync(); // Map bans to ban sources foreach (var group in deserializedData.ServerBans.Concat(deserializedData.JobBans).GroupBy(x => x.Source)) { var matchingSource = deserializedData.Sources.First(x => x.Id == group.Key); var matchingDbSource = toUpdate.First(x => x.Name == matchingSource.Name); foreach (var b in group) { b.Source = matchingDbSource.Id; b.SourceNavigation = matchingDbSource; } _dbContext.Bans.AddRange(group); } await _dbContext.SaveChangesAsync(); // Add update record reflecting the changes var thisUpdate = new FlatBansVersion() { Name = deserializedData.Name, Version = deserializedData.Version, PerformedAt = DateTime.UtcNow }; _dbContext.FlatBansVersion.Add(thisUpdate); await _dbContext.SaveChangesAsync(); // Commit changes when everything else has gone correctly await transaction.CommitAsync(); _logger.LogInformation("Import/update complete"); } catch (Exception ex) { _logger.LogError(ex, $"Failed to import flat ban data from {deserializedData.Name}, see below for details"); } } } }