Fixed AutoSavedStore's deletion of data when table was using composite keys.
This commit is contained in:
106
Store/Internal/ComplexAutoSavedStore.cs
Normal file
106
Store/Internal/ComplexAutoSavedStore.cs
Normal file
@@ -0,0 +1,106 @@
|
||||
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using HermesSocketLibrary.db;
|
||||
|
||||
namespace HermesSocketServer.Store.Internal
|
||||
{
|
||||
public abstract class ComplexAutoSavedStore<K, V> : GroupSaveStore<K, V> where K : class where V : class
|
||||
{
|
||||
private readonly IList<V> _removedValues;
|
||||
private readonly GroupSaveSqlGenerator<V> _generator;
|
||||
private readonly DatabaseTable _table;
|
||||
private readonly Database _database;
|
||||
private readonly Serilog.ILogger _logger;
|
||||
|
||||
|
||||
public ComplexAutoSavedStore(DatabaseTable table, Database database, Serilog.ILogger logger)
|
||||
: base()
|
||||
{
|
||||
if (table.KeyColumns.Length <= 1)
|
||||
throw new InvalidOperationException($"Use AutoSavedStore instead due to a single key column [table name: {table.TableName}]");
|
||||
|
||||
_removedValues = new List<V>();
|
||||
if (table.TypeMapping == null)
|
||||
_generator = new GroupSaveSqlGenerator<V>(table.PropertyMapping, logger);
|
||||
else
|
||||
_generator = new GroupSaveSqlGenerator<V>(table.PropertyMapping, table.TypeMapping, logger);
|
||||
_table = table;
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public override async Task Save()
|
||||
{
|
||||
var allColumns = _table.KeyColumns.Union(_table.DataColumns).ToArray();
|
||||
var typeMapping = _table.TypeMapping ?? new Dictionary<string, string>();
|
||||
|
||||
await GenerateQuery(_added,
|
||||
(size) => _generator.GeneratePreparedInsertSql(_table.TableName, size, allColumns, typeMapping),
|
||||
async (query, _, values) => await _generator.DoPreparedStatement(_database, query, values, allColumns));
|
||||
|
||||
await GenerateQuery(_modified,
|
||||
(size) => _generator.GeneratePreparedUpdateSql(_table.TableName, size, _table.KeyColumns, _table.DataColumns, typeMapping),
|
||||
async (query, _, values) => await _generator.DoPreparedStatement(_database, query, values, allColumns));
|
||||
|
||||
await GenerateDeleteQuery(_deleted, _removedValues,
|
||||
(size) => _generator.GeneratePreparedDeleteSql(_table.TableName, size, _table.KeyColumns, typeMapping),
|
||||
async (query, list) => await _generator.DoPreparedStatement(_database, query, list, _table.KeyColumns));
|
||||
}
|
||||
|
||||
private async Task GenerateQuery(IList<K> keys, Func<int, string> generate, Func<string, IEnumerable<K>, IEnumerable<V>, Task<int>> execute)
|
||||
{
|
||||
ImmutableList<K>? list = null;
|
||||
lock (_lock)
|
||||
{
|
||||
if (!keys.Any())
|
||||
return;
|
||||
|
||||
list = keys.ToImmutableList();
|
||||
keys.Clear();
|
||||
}
|
||||
|
||||
var query = generate(list.Count);
|
||||
var values = list.Select(id => _store[id]).Where(v => v != null);
|
||||
int rowsAffected = await execute(query, list, values);
|
||||
|
||||
if (rowsAffected != list.Count)
|
||||
{
|
||||
_logger.Error($"Rows affected in database ({rowsAffected}) and the number of items that should be modified ({list.Count}) do not match: {query}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Information($"{rowsAffected} rows were affected by this query: {query}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task GenerateDeleteQuery(IList<K> keys, IList<V> values, Func<int, string> generate, Func<string, IEnumerable<V>, Task<int>> execute)
|
||||
{
|
||||
ImmutableList<V>? list = null;
|
||||
lock (_lock)
|
||||
{
|
||||
if (!keys.Any() || !values.Any()) {
|
||||
return;
|
||||
}
|
||||
|
||||
list = values.ToImmutableList();
|
||||
values.Clear();
|
||||
keys.Clear();
|
||||
}
|
||||
|
||||
var query = generate(list.Count);
|
||||
int rowsAffected = await execute(query, list);
|
||||
|
||||
if (rowsAffected != list.Count)
|
||||
{
|
||||
_logger.Error($"Rows affected in database ({rowsAffected}) and the number of items that should be modified ({list.Count}) do not match: {query}");
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Information($"{rowsAffected} rows were affected by this query: {query}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPostRemove(K key, V value) => _removedValues.Add(value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user