|
@@ -7,7 +7,7 @@ using System.Reflection;
|
|
|
using System.Runtime.Serialization.Formatters.Binary;
|
|
|
using System.Text;
|
|
|
using InABox.Core;
|
|
|
-
|
|
|
+using Microsoft.CodeAnalysis;
|
|
|
|
|
|
namespace InABox.Database.SQLite
|
|
|
{
|
|
@@ -628,7 +628,7 @@ namespace InABox.Database.SQLite
|
|
|
return result;
|
|
|
|
|
|
var actions = new List<string>();
|
|
|
- var childtypes = Types.Where(x => /* (x != type) && */ x.IsSubclassOf(typeof(Entity)));
|
|
|
+ var childtypes = Types.Where(x => /* (x != type) && */ x.IsSubclassOf(typeof(Entity)) && x.GetCustomAttribute<AutoEntity>() == null);
|
|
|
foreach (var childtype in childtypes)
|
|
|
{
|
|
|
// Get all registererd types for this entitylink
|
|
@@ -1092,10 +1092,11 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
private void CheckTriggers(SQLiteWriteAccessor access, Type type, Dictionary<string, string> db_triggers)
|
|
|
{
|
|
|
+ /*
|
|
|
#if PURGE
|
|
|
foreach (var trigger in db_triggers.Keys)
|
|
|
ExecuteSQL(access, string.Format("DROP TRIGGER {0}", trigger));
|
|
|
-#else
|
|
|
+#else*/
|
|
|
var type_triggers = LoadTriggers(type);
|
|
|
|
|
|
foreach (var trigger in db_triggers.Keys)
|
|
@@ -1104,7 +1105,7 @@ namespace InABox.Database.SQLite
|
|
|
foreach (var trigger in type_triggers)
|
|
|
if (!db_triggers.ContainsValue(trigger))
|
|
|
ExecuteSQL(access, trigger);
|
|
|
-#endif
|
|
|
+//#endif
|
|
|
}
|
|
|
|
|
|
// private void CheckViews(SQLiteWriteAccessor access, Type type, Dictionary<String, String> db_views)
|
|
@@ -2148,7 +2149,7 @@ namespace InABox.Database.SQLite
|
|
|
Dictionary<string, string>? aggregates, Dictionary<string, object?>? constants, int top, bool distinct, bool useparams) where T : Entity
|
|
|
=> PrepareSelectNonGeneric(typeof(T), command, prefix, filter, columns, sort, aggregates, constants, top, distinct, useparams);
|
|
|
|
|
|
- private void PrepareUpsert<T>(SQLiteCommand command, T item, bool addDelete = false) where T : Entity
|
|
|
+ private static void PrepareUpsertNonGeneric(Type T, SQLiteCommand command, Entity item, bool addDelete = false)
|
|
|
{
|
|
|
command.CommandText = "";
|
|
|
command.Parameters.Clear();
|
|
@@ -2199,7 +2200,7 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
var particles = new List<string>();
|
|
|
particles.Add("INSERT INTO");
|
|
|
- particles.Add(typeof(T).EntityName().Split('.').Last());
|
|
|
+ particles.Add(T.EntityName().Split('.').Last());
|
|
|
particles.Add("(");
|
|
|
particles.Add(string.Join(",", insertfields));
|
|
|
particles.Add(")");
|
|
@@ -2214,6 +2215,9 @@ namespace InABox.Database.SQLite
|
|
|
command.CommandText = string.Join(" ", particles);
|
|
|
}
|
|
|
|
|
|
+ private void PrepareUpsert<T>(SQLiteCommand command, T item, bool addDelete = false) where T : Entity
|
|
|
+ => PrepareUpsertNonGeneric(typeof(T), command, item, addDelete);
|
|
|
+
|
|
|
public void PrepareDelete<T>(SQLiteCommand command, T item) where T : Entity
|
|
|
{
|
|
|
command.CommandText = string.Format("DELETE FROM {0} WHERE [ID] = @p0", typeof(T).EntityName().Split('.').Last());
|
|
@@ -2223,7 +2227,6 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
-
|
|
|
#region Schema Handling
|
|
|
|
|
|
public Dictionary<string, Type> GetSchema()
|
|
@@ -2256,6 +2259,8 @@ namespace InABox.Database.SQLite
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ #region Query
|
|
|
+
|
|
|
public IEnumerable<object[]> List<T>(Filter<T>? filter = null, Columns<T>? columns = null, SortOrder<T>? sort = null) where T : Entity, new()
|
|
|
{
|
|
|
var newFilter = new Filter<T>(x => x.Deleted).IsEqualTo(Guid.Empty);
|
|
@@ -2300,34 +2305,33 @@ namespace InABox.Database.SQLite
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
- private CoreTable DoQuery<T>(Filter<T>? filter, Columns<T>? columns, SortOrder<T>? sort, int top, bool log, bool distinct)
|
|
|
- where T : Entity, new()
|
|
|
+ private CoreTable DoQueryNonGeneric(Type T, IFilter? filter = null, IColumns? columns = null, ISortOrder? sort = null, int top = int.MaxValue, bool log = true, bool distinct = false)
|
|
|
{
|
|
|
var start = DateTime.Now;
|
|
|
//LogReset();
|
|
|
|
|
|
//LogStart();
|
|
|
- var cols = CoreUtils.GetColumns(columns);
|
|
|
+ var cols = CoreUtils.GetColumns(T, columns);
|
|
|
//LogStop("GetColumns");
|
|
|
|
|
|
var result = new CoreTable();
|
|
|
- result.TableName = typeof(T).EntityName();
|
|
|
- foreach (var col in cols.Items)
|
|
|
- result.Columns.Add(new CoreColumn { ColumnName = col.Property, DataType = col.ExpressionType() });
|
|
|
+ result.TableName = T.EntityName();
|
|
|
+ foreach (var col in cols.GetColumns())
|
|
|
+ result.Columns.Add(new CoreColumn { ColumnName = col.Property, DataType = col.Type });
|
|
|
//LogStop("MakeTable");
|
|
|
|
|
|
using (var access = GetReadAccess())
|
|
|
{
|
|
|
using (var command = access.CreateCommand())
|
|
|
{
|
|
|
- var sortorder = sort == null ? LookupFactory.DefineSort<T>() : sort;
|
|
|
+ var sortorder = sort ?? LookupFactory.DefineSort(T);
|
|
|
|
|
|
command.CommandText = "";
|
|
|
command.Parameters.Clear();
|
|
|
|
|
|
//LogStart();
|
|
|
- String sql = PrepareSelect(command, 'A', filter, cols, sortorder, null, null, top, distinct, true) + ";";
|
|
|
-
|
|
|
+ var sql = PrepareSelectNonGeneric(T, command, 'A', filter, cols, sortorder, null, null, top, distinct, true) + ";";
|
|
|
+
|
|
|
command.CommandText = sql;
|
|
|
|
|
|
try
|
|
@@ -2437,12 +2441,15 @@ namespace InABox.Database.SQLite
|
|
|
{
|
|
|
var duration = DateTime.Now - start;
|
|
|
Logger.Send(LogType.Information, "",
|
|
|
- string.Format("SQLite::Query<{0}>({1} cols) returns {2} rows in {3}ms", typeof(T).Name, cols.Items.Length, result.Rows.Count,
|
|
|
+ string.Format("SQLite::Query<{0}>({1} cols) returns {2} rows in {3}ms", T.Name, cols.Count, result.Rows.Count,
|
|
|
duration.TotalMilliseconds));
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+ private CoreTable DoQuery<T>(Filter<T>? filter, Columns<T>? columns, SortOrder<T>? sort, int top, bool log, bool distinct)
|
|
|
+ where T : Entity, new() => DoQueryNonGeneric(typeof(T), filter, columns, sort, top, log, distinct);
|
|
|
+
|
|
|
public CoreTable Query<T>(Filter<T>? filter = null, Columns<T>? columns = null, SortOrder<T>? sort = null, int top = int.MaxValue, bool log = true, bool distinct = false)
|
|
|
where T : Entity, new()
|
|
|
{
|
|
@@ -2532,7 +2539,11 @@ namespace InABox.Database.SQLite
|
|
|
return result.ToArray();
|
|
|
}
|
|
|
|
|
|
- private void OnSave<T>(IEnumerable<T> entities, bool addDelete = false) where T : Entity
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Save
|
|
|
+
|
|
|
+ private void OnSaveNonGeneric(Type T, IEnumerable<Entity> entities, bool addDelete = false)
|
|
|
{
|
|
|
if (!entities.Any())
|
|
|
return;
|
|
@@ -2548,7 +2559,7 @@ namespace InABox.Database.SQLite
|
|
|
{
|
|
|
foreach (var entity in entities)
|
|
|
{
|
|
|
- PrepareUpsert(command, entity, addDelete);
|
|
|
+ PrepareUpsertNonGeneric(T, command, entity, addDelete);
|
|
|
command.ExecuteNonQuery();
|
|
|
}
|
|
|
|
|
@@ -2566,7 +2577,9 @@ namespace InABox.Database.SQLite
|
|
|
throw error;
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
+ private void OnSave<T>(IEnumerable<T> entities, bool addDelete = false) where T : Entity
|
|
|
+ => OnSaveNonGeneric(typeof(T), entities, addDelete);
|
|
|
+
|
|
|
public static bool CanSave<T>()
|
|
|
{
|
|
|
if (DbFactory.IsReadOnly)
|
|
@@ -2589,8 +2602,7 @@ namespace InABox.Database.SQLite
|
|
|
}
|
|
|
OnSave(entities, false);
|
|
|
}
|
|
|
-
|
|
|
- private void OnSave<T>(T entity, bool addDelete = false) where T : Entity
|
|
|
+ private void OnSaveNonGeneric(Type T, Entity entity, bool addDelete = false)
|
|
|
{
|
|
|
Exception? error = null;
|
|
|
using (var access = GetWriteAccess())
|
|
@@ -2599,7 +2611,7 @@ namespace InABox.Database.SQLite
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- PrepareUpsert(command, entity, addDelete);
|
|
|
+ PrepareUpsertNonGeneric(T, command, entity, addDelete);
|
|
|
command.ExecuteNonQuery();
|
|
|
}
|
|
|
catch (Exception e)
|
|
@@ -2613,6 +2625,9 @@ namespace InABox.Database.SQLite
|
|
|
throw error;
|
|
|
}
|
|
|
|
|
|
+ private void OnSave<T>(T entity, bool addDelete = false) where T : Entity
|
|
|
+ => OnSaveNonGeneric(typeof(T), entity, addDelete);
|
|
|
+
|
|
|
public void Save<T>(T entity) where T : Entity
|
|
|
{
|
|
|
if (!CanSave<T>())
|
|
@@ -2621,7 +2636,11 @@ namespace InABox.Database.SQLite
|
|
|
}
|
|
|
OnSave(entity, false);
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Delete
|
|
|
+
|
|
|
public void Purge<T>(T entity) where T : Entity
|
|
|
{
|
|
|
using (var access = GetWriteAccess())
|
|
@@ -2686,7 +2705,7 @@ namespace InABox.Database.SQLite
|
|
|
var cascades = new List<Tuple<Type, string>>();
|
|
|
var setNulls = new List<Tuple<Type, List<string>>>();
|
|
|
|
|
|
- var childtypes = Types.Where(x => x.IsSubclassOf(typeof(Entity)));
|
|
|
+ var childtypes = Types.Where(x => x.IsSubclassOf(typeof(Entity)) && x.GetCustomAttribute<AutoEntity>() == null);
|
|
|
foreach (var childtype in childtypes)
|
|
|
{
|
|
|
// Get all registered types for this entitylink
|
|
@@ -2727,72 +2746,97 @@ 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, Deletion deletion) where T : Entity, new()
|
|
|
+ private void DeleteEntity<T>(Guid parentID, string parentField, DeletionData deletionData) where T : Entity, new()
|
|
|
{
|
|
|
- var entities = Query(new Filter<T>(parentField).IsEqualTo(parentID), new Columns<T>(x => x.ID))
|
|
|
- .Rows.Select(x => x.ToObject<T>()).ToList();
|
|
|
- foreach(var entity in entities)
|
|
|
+ var columns = DeletionData.DeletionColumns<T>();
|
|
|
+ var entities = Query(new Filter<T>(parentField).IsEqualTo(parentID), columns);
|
|
|
+ foreach(var row in entities.Rows)
|
|
|
{
|
|
|
- entity.Deleted = deletion.ID;
|
|
|
+ deletionData.DeleteEntity<T>(row);
|
|
|
+ CascadeDelete(typeof(T), row.Get<T, Guid>(x => x.ID), deletionData);
|
|
|
}
|
|
|
- OnSave(entities, true);
|
|
|
- foreach (var entity in entities)
|
|
|
+ }
|
|
|
+
|
|
|
+ private void DeleteEntity(Type T, Guid parentID, string parentField, DeletionData deletionData)
|
|
|
+ {
|
|
|
+ _deleteEntitiesMethod.MakeGenericMethod(T).Invoke(this, new object?[] { parentID, 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()
|
|
|
+ {
|
|
|
+ foreach(var property in properties)
|
|
|
{
|
|
|
- CascadeDelete(typeof(T), entity.ID, deletion);
|
|
|
+ var entities = Query(new Filter<T>(property).IsEqualTo(parentID), new Columns<T>(x => x.ID));
|
|
|
+ foreach (var row in entities.Rows)
|
|
|
+ {
|
|
|
+ deletionData.SetNullEntity<T>(row.Get<T, Guid>(x => x.ID), property, parentID);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- private void DeleteEntity(Type T, Guid parentID, string parentField, Deletion deletion)
|
|
|
+
|
|
|
+ private void SetNullEntity(Type T, List<string> properties, Guid parentID, DeletionData deletionData)
|
|
|
{
|
|
|
- _deleteEntitiesMethod.MakeGenericMethod(T).Invoke(this, new object?[] { parentID, parentField, deletion });
|
|
|
+ _setNullEntityMethod.MakeGenericMethod(T).Invoke(this, new object?[] { properties, parentID, deletionData });
|
|
|
}
|
|
|
|
|
|
- private void CascadeDelete(Type type, Guid parentID, Deletion deletion)
|
|
|
+ private void CascadeDelete(Type type, Guid parentID, DeletionData deletionData)
|
|
|
{
|
|
|
- if (!_cascades.TryGetValue(type, out var cascades))
|
|
|
- return;
|
|
|
- foreach(var cascade in cascades)
|
|
|
+ if (_cascades.TryGetValue(type, out var cascades))
|
|
|
+ {
|
|
|
+ foreach (var cascade in cascades)
|
|
|
+ {
|
|
|
+ DeleteEntity(cascade.Item1, parentID, cascade.Item2, deletionData);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(_setNulls.TryGetValue(type, out var setNulls))
|
|
|
{
|
|
|
- DeleteEntity(cascade.Item1, parentID, cascade.Item2, deletion);
|
|
|
+ foreach(var setNull in setNulls)
|
|
|
+ {
|
|
|
+ SetNullEntity(setNull.Item1, setNull.Item2, parentID, deletionData);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
public void Delete<T>(T entity, string userID) where T : Entity, new()
|
|
|
{
|
|
|
-#if PURGE
|
|
|
+//#if PURGE
|
|
|
if (!CanSave<T>())
|
|
|
{
|
|
|
return;
|
|
|
}
|
|
|
entity = DoQuery(
|
|
|
new Filter<T>(x => x.ID).IsEqualTo(entity.ID),
|
|
|
- null,
|
|
|
+ DeletionData.DeletionColumns<T>(),
|
|
|
null,
|
|
|
int.MaxValue,
|
|
|
true,
|
|
|
false
|
|
|
).Rows.First().ToObject<T>();
|
|
|
|
|
|
+ var deletionData = new DeletionData();
|
|
|
+ deletionData.DeleteEntity(entity);
|
|
|
+ CascadeDelete(typeof(T), entity.ID, deletionData);
|
|
|
+
|
|
|
var tableName = typeof(T).Name;
|
|
|
- var deletion = new Deletion() {
|
|
|
- DeletionDate = DateTime.Now,
|
|
|
- HeadTable = tableName,
|
|
|
+ var deletion = new Deletion()
|
|
|
+ {
|
|
|
+ DeletionDate = DateTime.Now,
|
|
|
+ HeadTable = tableName,
|
|
|
Description = entity.ToString() ?? "",
|
|
|
- DeletedBy = userID
|
|
|
+ DeletedBy = userID,
|
|
|
+ Data = Serialization.Serialize(deletionData)
|
|
|
};
|
|
|
OnSave(deletion);
|
|
|
-
|
|
|
- entity.Deleted = deletion.ID;
|
|
|
- OnSave(entity, true);
|
|
|
- CascadeDelete(typeof(T), entity.ID, deletion);
|
|
|
-#else
|
|
|
+ //#else
|
|
|
Purge(entity);
|
|
|
-#endif
|
|
|
+//#endif
|
|
|
}
|
|
|
|
|
|
public void Delete<T>(IEnumerable<T> entities, string userID) where T : Entity, new()
|
|
|
{
|
|
|
-#if PURGE
|
|
|
+//#if PURGE
|
|
|
if (!CanSave<T>())
|
|
|
{
|
|
|
return;
|
|
@@ -2800,28 +2844,32 @@ namespace InABox.Database.SQLite
|
|
|
if (!entities.Any())
|
|
|
return;
|
|
|
var ids = entities.Select(x => x.ID).ToArray();
|
|
|
- var entityList = Query(new Filter<T>(x => x.ID).InList(ids)).Rows.Select(x => x.ToObject<T>()).ToList();
|
|
|
+ var entityList = Query(
|
|
|
+ new Filter<T>(x => x.ID).InList(ids),
|
|
|
+ DeletionData.DeletionColumns<T>()).Rows.Select(x => x.ToObject<T>()).ToList();
|
|
|
if (!entityList.Any())
|
|
|
return;
|
|
|
|
|
|
+ var deletionData = new DeletionData();
|
|
|
+ foreach (var entity in entityList)
|
|
|
+ {
|
|
|
+ deletionData.DeleteEntity(entity);
|
|
|
+ CascadeDelete(typeof(T), entity.ID, deletionData);
|
|
|
+ }
|
|
|
+
|
|
|
var tableName = typeof(T).Name;
|
|
|
- var deletion = new Deletion() {
|
|
|
+ var deletion = new Deletion()
|
|
|
+ {
|
|
|
DeletionDate = DateTime.Now,
|
|
|
HeadTable = tableName,
|
|
|
Description = $"Deleted {entityList.Count} entries",
|
|
|
- DeletedBy = userID
|
|
|
+ DeletedBy = userID,
|
|
|
+ Data = Serialization.Serialize(deletionData)
|
|
|
};
|
|
|
OnSave(deletion);
|
|
|
-
|
|
|
- foreach(var entity in entityList)
|
|
|
- {
|
|
|
- entity.Deleted = deletion.ID;
|
|
|
- OnSave(entity, true);
|
|
|
- CascadeDelete(typeof(T), entity.ID, deletion);
|
|
|
- }
|
|
|
-#else
|
|
|
+ //#else
|
|
|
Purge(entities);
|
|
|
-#endif
|
|
|
+//#endif
|
|
|
}
|
|
|
|
|
|
private void AddDeletionType(Type type, List<Type> deletions)
|
|
@@ -2848,7 +2896,7 @@ namespace InABox.Database.SQLite
|
|
|
return deletionTypes;
|
|
|
}
|
|
|
|
|
|
- private void DoSetNull<TChild>(string field, Guid[] parentIDs) where TChild : Entity, new()
|
|
|
+ /*private void DoSetNull<TChild>(string field, Guid[] parentIDs) where TChild : Entity, new()
|
|
|
{
|
|
|
var columns = new Columns<TChild>(x => x.ID);
|
|
|
columns.Add(field);
|
|
@@ -2865,9 +2913,9 @@ namespace InABox.Database.SQLite
|
|
|
CoreUtils.SetPropertyValue(child, field, Guid.Empty);
|
|
|
}
|
|
|
OnSave(children);
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
- private void PurgeEntityType<T>(Deletion deletion) where T : Entity, new()
|
|
|
+ /*private void PurgeEntityType<T>(Deletion deletion) where T : Entity, new()
|
|
|
{
|
|
|
var entities = QueryDeleted(deletion, null, new Columns<T>(x => x.ID)).Rows.Select(x => x.ToObject<T>()).ToList();
|
|
|
if (_setNulls.TryGetValue(typeof(T), out var setNulls))
|
|
@@ -2884,9 +2932,9 @@ namespace InABox.Database.SQLite
|
|
|
}
|
|
|
}
|
|
|
Purge(entities);
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
- private void RecoverEntityType<T>(Deletion deletion) where T : Entity, new()
|
|
|
+ /*private void RecoverEntityType<T>(Deletion deletion) where T : Entity, new()
|
|
|
{
|
|
|
var entities = QueryDeleted(deletion, null, new Columns<T>(x => x.ID, x => x.Deleted)).Rows.Select(x => x.ToObject<T>()).ToList();
|
|
|
foreach (var entity in entities)
|
|
@@ -2894,11 +2942,11 @@ namespace InABox.Database.SQLite
|
|
|
entity.Deleted = Guid.Empty;
|
|
|
}
|
|
|
OnSave(entities, true);
|
|
|
- }
|
|
|
+ }*/
|
|
|
|
|
|
public void Purge(Deletion deletion)
|
|
|
{
|
|
|
- if(deletion.ID == Guid.Empty)
|
|
|
+ /*if(deletion.ID == Guid.Empty)
|
|
|
{
|
|
|
Logger.Send(LogType.Error, "", "Empty Deletion ID; Purge cancelled");
|
|
|
return;
|
|
@@ -2918,7 +2966,7 @@ namespace InABox.Database.SQLite
|
|
|
{
|
|
|
purgeMethod.MakeGenericMethod(type).Invoke(this, new object[] { deletion });
|
|
|
}
|
|
|
-
|
|
|
+ */
|
|
|
Purge<Deletion>(deletion);
|
|
|
}
|
|
|
|
|
@@ -2930,18 +2978,37 @@ namespace InABox.Database.SQLite
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- var entityType = CoreUtils.Entities.FirstOrDefault(x => x.Name == deletion.HeadTable);
|
|
|
- if (entityType is null)
|
|
|
+ var data = Serialization.Deserialize<DeletionData>(deletion.Data);
|
|
|
+ if (data is null)
|
|
|
{
|
|
|
- Logger.Send(LogType.Error, "", $"Entity {deletion.HeadTable} does not exist; Recovery cancelled");
|
|
|
+ Logger.Send(LogType.Error, "", "Deletion Data deserialisation failed; Recovery cancelled");
|
|
|
return;
|
|
|
}
|
|
|
- var deletionTypes = GetDeletionTypes(entityType);
|
|
|
+ foreach (var (entityName, setNulls) in data.SetNulls)
|
|
|
+ {
|
|
|
+ if (!CoreUtils.TryGetEntity(entityName, out var entityType)) continue;
|
|
|
+
|
|
|
+ var saves = new List<Entity>();
|
|
|
+
|
|
|
+ foreach(var setNull in setNulls)
|
|
|
+ {
|
|
|
+ var row = DoQueryNonGeneric(entityType,
|
|
|
+ Filter.Create<Entity>(entityType, x => x.ID).IsEqualTo(setNull.EntityID),
|
|
|
+ Columns.Create(entityType).Add<Entity>(x => x.ID).Add(setNull.Property)).Rows.FirstOrDefault();
|
|
|
+ if (row is null) continue;
|
|
|
+
|
|
|
+ var entity = (row.ToObject(entityType) as Entity)!;
|
|
|
+ CoreUtils.SetPropertyValue(entity, setNull.Property, setNull.ParentID);
|
|
|
+ saves.Add(entity);
|
|
|
+ }
|
|
|
|
|
|
- var recoveryMethod = typeof(SQLiteProvider).GetMethod(nameof(RecoverEntityType), BindingFlags.NonPublic | BindingFlags.Instance)!;
|
|
|
- foreach (var type in deletionTypes)
|
|
|
+ OnSaveNonGeneric(entityType, saves);
|
|
|
+ }
|
|
|
+ foreach(var (entityName, cascade) in data.Cascades)
|
|
|
{
|
|
|
- recoveryMethod.MakeGenericMethod(type).Invoke(this, new object[] { deletion });
|
|
|
+ if (!CoreUtils.TryGetEntity(entityName, out var entityType)) continue;
|
|
|
+
|
|
|
+ OnSaveNonGeneric(entityType, cascade.ToObjects(entityType).Cast<Entity>());
|
|
|
}
|
|
|
|
|
|
Purge<Deletion>(deletion);
|
|
@@ -2955,5 +3022,7 @@ namespace InABox.Database.SQLite
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
}
|
|
|
}
|