|
@@ -8,6 +8,7 @@ using System.Runtime.Serialization.Formatters.Binary;
|
|
|
using System.Text;
|
|
|
using InABox.Core;
|
|
|
using Microsoft.CodeAnalysis;
|
|
|
+using NPOI.POIFS.FileSystem;
|
|
|
|
|
|
namespace InABox.Database.SQLite
|
|
|
{
|
|
@@ -2706,6 +2707,9 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
private Dictionary<Type, List<Tuple<Type, string>>> _cascades = new();
|
|
|
private Dictionary<Type, List<Tuple<Type, List<string>>>> _setNulls = new();
|
|
|
+
|
|
|
+ private const int deleteBatchSize = 100;
|
|
|
+
|
|
|
private void LoadDeletions(Type type)
|
|
|
{
|
|
|
// Get the EntityLink that is associated with this class
|
|
@@ -2762,55 +2766,74 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
private MethodInfo _deleteEntitiesMethod = typeof(SQLiteProvider).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
.Single(x => x.Name == nameof(DeleteEntity) && x.IsGenericMethod);
|
|
|
- private void DeleteEntity<T>(Guid parentID, string parentField, DeletionData deletionData) where T : Entity, new()
|
|
|
+ private void DeleteEntity<T>(Guid[] parentIDs, string parentField, DeletionData deletionData) where T : Entity, new()
|
|
|
{
|
|
|
var columns = DeletionData.DeletionColumns<T>();
|
|
|
- var entities = Query(new Filter<T>(parentField).IsEqualTo(parentID), columns);
|
|
|
- foreach(var row in entities.Rows)
|
|
|
+
|
|
|
+ var entityIDs = new List<Guid>();
|
|
|
+
|
|
|
+ for (int i = 0; i < parentIDs.Length; i += deleteBatchSize)
|
|
|
{
|
|
|
- deletionData.DeleteEntity<T>(row);
|
|
|
- CascadeDelete(typeof(T), row.Get<T, Guid>(x => x.ID), deletionData);
|
|
|
+ var items = new ArraySegment<Guid>(parentIDs, i, Math.Min(deleteBatchSize, parentIDs.Length - i));
|
|
|
+ var entities = Query(new Filter<T>(parentField).InList(items.ToArray()), columns);
|
|
|
+ foreach (var row in entities.Rows)
|
|
|
+ {
|
|
|
+ deletionData.DeleteEntity<T>(row);
|
|
|
+ entityIDs.Add(row.Get<T, Guid>(x => x.ID));
|
|
|
+ }
|
|
|
}
|
|
|
+ CascadeDelete(typeof(T), entityIDs.ToArray(), deletionData);
|
|
|
}
|
|
|
|
|
|
- private void DeleteEntity(Type T, Guid parentID, string parentField, DeletionData deletionData)
|
|
|
+ private void DeleteEntity(Type T, Guid[] parentIDs, string parentField, DeletionData deletionData)
|
|
|
{
|
|
|
- _deleteEntitiesMethod.MakeGenericMethod(T).Invoke(this, new object?[] { parentID, parentField, deletionData });
|
|
|
+ _deleteEntitiesMethod.MakeGenericMethod(T).Invoke(this, new object?[] { parentIDs, parentField, deletionData });
|
|
|
}
|
|
|
|
|
|
private MethodInfo _setNullEntityMethod = typeof(SQLiteProvider).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
.Single(x => x.Name == nameof(SetNullEntity) && x.IsGenericMethod);
|
|
|
- private void SetNullEntity<T>(List<string> properties, Guid parentID, DeletionData deletionData) where T : Entity, new()
|
|
|
+ private void SetNullEntity<T>(List<string> properties, Guid[] parentIDs, DeletionData deletionData) where T : Entity, new()
|
|
|
{
|
|
|
foreach(var property in properties)
|
|
|
{
|
|
|
- var entities = Query(new Filter<T>(property).IsEqualTo(parentID), new Columns<T>(x => x.ID));
|
|
|
- foreach (var row in entities.Rows)
|
|
|
+ var columns = new Columns<T>(x => x.ID);
|
|
|
+ columns.Add(property);
|
|
|
+
|
|
|
+ for(int i = 0; i < parentIDs.Length; i += deleteBatchSize)
|
|
|
{
|
|
|
- deletionData.SetNullEntity<T>(row.Get<T, Guid>(x => x.ID), property, parentID);
|
|
|
+ var items = new ArraySegment<Guid>(parentIDs, i, Math.Min(deleteBatchSize, parentIDs.Length - i));
|
|
|
+ var entities = Query(new Filter<T>(property).InList(items.ToArray()), columns);
|
|
|
+ foreach (var row in entities.Rows)
|
|
|
+ {
|
|
|
+ deletionData.SetNullEntity<T>(row.Get<T, Guid>(x => x.ID), property, row.Get<Guid>(property));
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- private void SetNullEntity(Type T, List<string> properties, Guid parentID, DeletionData deletionData)
|
|
|
+ private void SetNullEntity(Type T, List<string> properties, Guid[] parentIDs, DeletionData deletionData)
|
|
|
{
|
|
|
- _setNullEntityMethod.MakeGenericMethod(T).Invoke(this, new object?[] { properties, parentID, deletionData });
|
|
|
+ _setNullEntityMethod.MakeGenericMethod(T).Invoke(this, new object?[] { properties, parentIDs, deletionData });
|
|
|
}
|
|
|
|
|
|
- private void CascadeDelete(Type type, Guid parentID, DeletionData deletionData)
|
|
|
+ private void CascadeDelete(Type type, Guid[] parentIDs, DeletionData deletionData)
|
|
|
{
|
|
|
+ if(parentIDs.Length == 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
if (_cascades.TryGetValue(type, out var cascades))
|
|
|
{
|
|
|
foreach (var cascade in cascades)
|
|
|
{
|
|
|
- DeleteEntity(cascade.Item1, parentID, cascade.Item2, deletionData);
|
|
|
+ DeleteEntity(cascade.Item1, parentIDs, cascade.Item2, deletionData);
|
|
|
}
|
|
|
}
|
|
|
if(_setNulls.TryGetValue(type, out var setNulls))
|
|
|
{
|
|
|
foreach(var setNull in setNulls)
|
|
|
{
|
|
|
- SetNullEntity(setNull.Item1, setNull.Item2, parentID, deletionData);
|
|
|
+ SetNullEntity(setNull.Item1, setNull.Item2, parentIDs, deletionData);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -2832,7 +2855,7 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
var deletionData = new DeletionData();
|
|
|
deletionData.DeleteEntity(entity);
|
|
|
- CascadeDelete(typeof(T), entity.ID, deletionData);
|
|
|
+ CascadeDelete(typeof(T), new Guid[] { entity.ID }, deletionData);
|
|
|
|
|
|
var tableName = typeof(T).Name;
|
|
|
var deletion = new Deletion()
|
|
@@ -2866,8 +2889,8 @@ namespace InABox.Database.SQLite
|
|
|
foreach (var entity in entityList)
|
|
|
{
|
|
|
deletionData.DeleteEntity(entity);
|
|
|
- CascadeDelete(typeof(T), entity.ID, deletionData);
|
|
|
}
|
|
|
+ CascadeDelete(typeof(T), ids, deletionData);
|
|
|
|
|
|
var tableName = typeof(T).Name;
|
|
|
var deletion = new Deletion()
|