|
@@ -230,7 +230,7 @@ namespace InABox.Core
|
|
AddTable(new Filter<User>(x => x.ID).IsEqualTo(ClientFactory.UserGuid), null, true);
|
|
AddTable(new Filter<User>(x => x.ID).IsEqualTo(ClientFactory.UserGuid), null, true);
|
|
}
|
|
}
|
|
|
|
|
|
- public IEnumerable<KeyValuePair<string, DataModelTable>> ModelTables => _tables;
|
|
|
|
|
|
+ public IEnumerable<KeyValuePair<string, IDataModelTable>> ModelTables => _tables;
|
|
|
|
|
|
public abstract string Name { get; }
|
|
public abstract string Name { get; }
|
|
|
|
|
|
@@ -409,19 +409,29 @@ namespace InABox.Core
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- public class DataModelLoadTable<T> : IDataModelTable
|
|
|
|
- where T : Entity, IRemotable, IPersistent, new()
|
|
|
|
|
|
+ private interface IDataModelLoadTable : IDataModelTable
|
|
{
|
|
{
|
|
- private CoreTable? _data = null;
|
|
|
|
|
|
+ public IFilter? GetFilter();
|
|
|
|
+
|
|
|
|
+ public IQueryDef GetQueryDef();
|
|
|
|
+
|
|
|
|
+ public void LoadData(CoreTable data);
|
|
|
|
+ }
|
|
|
|
|
|
|
|
+ public class DataModelLoadTable<T> : IDataModelTable, IDataModelLoadTable
|
|
|
|
+ where T : Entity, IRemotable, IPersistent, new()
|
|
|
|
+ {
|
|
public string Name { get; set; }
|
|
public string Name { get; set; }
|
|
|
|
|
|
public Type? Type => typeof(T);
|
|
public Type? Type => typeof(T);
|
|
|
|
|
|
public DataModel Model { get; set; }
|
|
public DataModel Model { get; set; }
|
|
|
|
|
|
- public CoreTable Data => throw new NotImplementedException();
|
|
|
|
|
|
+ public CoreTable Data { get; private set; }
|
|
|
|
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// Set to <see langword="true"/> if this table should be included in lists of default required tables. Thus, this is not used for the actual loading of data; use <see cref="IsRequired"/> for that.
|
|
|
|
+ /// </summary>
|
|
public bool IsDefault { get; set; }
|
|
public bool IsDefault { get; set; }
|
|
public bool IsRequired { get; set; }
|
|
public bool IsRequired { get; set; }
|
|
|
|
|
|
@@ -429,7 +439,8 @@ namespace InABox.Core
|
|
|
|
|
|
public Columns<T> Columns { get; set; }
|
|
public Columns<T> Columns { get; set; }
|
|
|
|
|
|
- public IEnumerable<IDataModelTable> ChildTables => Model._relationships.Where(x => x.ParentTable == Name).Select(x => Model._tables[x.ChildTable]);
|
|
|
|
|
|
+ public IEnumerable<IDataModelTable> ChildTables =>
|
|
|
|
+ Model._relationships.Where(x => x.ParentTable == Name).Select(x => Model._tables[x.ChildTable]);
|
|
|
|
|
|
public DataModelLoadTable(DataModel model, string name, Filter<T> filter, Columns<T> columns)
|
|
public DataModelLoadTable(DataModel model, string name, Filter<T> filter, Columns<T> columns)
|
|
{
|
|
{
|
|
@@ -469,96 +480,50 @@ namespace InABox.Core
|
|
}
|
|
}
|
|
|
|
|
|
var childName = TableName<TChild>(alias);
|
|
var childName = TableName<TChild>(alias);
|
|
- var single = relations.Where(x => x.Name == childName).SingleOrDefault();
|
|
|
|
- if(single is null)
|
|
|
|
- {
|
|
|
|
- throw new AmbiguousTableException<TChild>();
|
|
|
|
- }
|
|
|
|
|
|
+ var single = relations.Where(x => x.Name == childName).SingleOrDefault()
|
|
|
|
+ ?? throw new AmbiguousTableException<TChild>();
|
|
return single;
|
|
return single;
|
|
}
|
|
}
|
|
|
|
|
|
public void Load()
|
|
public void Load()
|
|
{
|
|
{
|
|
- throw new NotImplementedException();
|
|
|
|
|
|
+ Data = Client.Query(GetQueryDef());
|
|
}
|
|
}
|
|
- }
|
|
|
|
-
|
|
|
|
- #region New Load Methods
|
|
|
|
-
|
|
|
|
- private Filter<TChild> GetSubquery<TParent, TChild>(IDataModelRelationship relation, Dictionary<string, IQueryDef> requiredQueries)
|
|
|
|
- where TParent : Entity, IRemotable, IPersistent, new()
|
|
|
|
- where TChild : Entity, IRemotable, IPersistent, new()
|
|
|
|
- {
|
|
|
|
- var parentFilter = GetTableFilter<TParent>(relation.ParentTable, requiredQueries);
|
|
|
|
- var subQuery = new SubQuery<TParent>(parentFilter, new Column<TParent>(relation.ParentColumnAsPropertyName()));
|
|
|
|
-
|
|
|
|
- var filter = new Filter<TChild>();
|
|
|
|
- filter.Expression = CoreUtils.CreateMemberExpression(typeof(TChild), relation.ChildColumnAsPropertyName());
|
|
|
|
- filter.Operator = Operator.InQuery;
|
|
|
|
- filter.Value = subQuery;
|
|
|
|
|
|
|
|
- return filter;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private Filter<TType>? GetTableFilter<TType>(string tableName, Dictionary<string, IQueryDef> requiredQueries)
|
|
|
|
- where TType : Entity, IRemotable, IPersistent, new()
|
|
|
|
- {
|
|
|
|
- var newFilter = _tables[tableName].Filter as Filter<TType>;
|
|
|
|
-
|
|
|
|
- IQueryDef? query = null;
|
|
|
|
- requiredQueries?.TryGetValue(tableName, out query);
|
|
|
|
- if (query?.Filter is Filter<TType> filter)
|
|
|
|
|
|
+ public Filter<T>? GetFilter()
|
|
{
|
|
{
|
|
- if (newFilter != null)
|
|
|
|
- newFilter.And(filter);
|
|
|
|
- else
|
|
|
|
- newFilter = filter;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- var relation = _relationships.Where(x => x.ChildTable == tableName).FirstOrDefault();
|
|
|
|
- if (relation != null)
|
|
|
|
- {
|
|
|
|
- var table = _tables[relation.ParentTable];
|
|
|
|
-
|
|
|
|
- if(table.Type != null)
|
|
|
|
|
|
+ var relation = Model._relationships.Where(x => x.ChildTable == Name).FirstOrDefault();
|
|
|
|
+ if(relation != null && Model._tables[relation.ParentTable] is IDataModelLoadTable loadTable && loadTable.Type is Type parentType)
|
|
{
|
|
{
|
|
- var subFilter = (typeof(DataModel).GetMethod(nameof(GetSubquery), BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
|
- .MakeGenericMethod(_tables[relation.ParentTable].Type, typeof(TType))
|
|
|
|
- .Invoke(this, new object?[] { relation, requiredQueries }) as Filter<TType>)!;
|
|
|
|
|
|
+ var subFilter = new Filter<T>(relation.ChildColumnAsPropertyName());
|
|
|
|
+ subFilter.Operator = Operator.InQuery;
|
|
|
|
+ subFilter.Value = SubQuery.Create(parentType,
|
|
|
|
+ loadTable.GetFilter(),
|
|
|
|
+ Column.Create(parentType, relation.ParentColumnAsPropertyName()));
|
|
|
|
|
|
- if (newFilter != null)
|
|
|
|
- newFilter.And(subFilter);
|
|
|
|
- else
|
|
|
|
- newFilter = subFilter;
|
|
|
|
|
|
+ return Filters<T>.Combine(Filter, subFilter);
|
|
}
|
|
}
|
|
|
|
+ return Filter;
|
|
}
|
|
}
|
|
|
|
|
|
- return newFilter;
|
|
|
|
- }
|
|
|
|
|
|
+ IFilter? IDataModelLoadTable.GetFilter() => GetFilter();
|
|
|
|
|
|
- private IQueryDef LoadModelTable<TType>(string tableName, Dictionary<string, IQueryDef> requiredQueries)
|
|
|
|
- where TType : Entity, IRemotable, IPersistent, new()
|
|
|
|
- {
|
|
|
|
- var newFilter = GetTableFilter<TType>(tableName, requiredQueries);
|
|
|
|
-
|
|
|
|
- var newColumns = _tables[tableName].Columns as Columns<TType>;
|
|
|
|
-
|
|
|
|
- var newSort = LookupFactory.DefineSort<TType>();
|
|
|
|
-
|
|
|
|
- IQueryDef? query = null;
|
|
|
|
- requiredQueries?.TryGetValue(tableName, out query);
|
|
|
|
|
|
+ public QueryDef<T> GetQueryDef()
|
|
|
|
+ {
|
|
|
|
+ return new QueryDef<T>(GetFilter(), Columns, LookupFactory.DefineSort<T>());
|
|
|
|
+ }
|
|
|
|
|
|
- if (query == null) return new QueryDef<TType>(newFilter, newColumns, newSort);
|
|
|
|
|
|
+ IQueryDef IDataModelLoadTable.GetQueryDef() => GetQueryDef();
|
|
|
|
|
|
- if (query.Columns != null) newColumns = query.Columns as Columns<TType>;
|
|
|
|
- return new QueryDef<TType>(
|
|
|
|
- newFilter,
|
|
|
|
- newColumns,
|
|
|
|
- query.SortOrder as SortOrder<TType>
|
|
|
|
- );
|
|
|
|
|
|
+ public void LoadData(CoreTable data)
|
|
|
|
+ {
|
|
|
|
+ Data = data;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- public virtual void LoadModel(IEnumerable<string>? requiredTables, Dictionary<string, IQueryDef>? requiredQueries = null)
|
|
|
|
|
|
+ #region New Load Methods
|
|
|
|
+
|
|
|
|
+ public virtual void LoadModel(IEnumerable<string>? requiredTables)
|
|
{
|
|
{
|
|
var requiredTablesList = requiredTables != null ? requiredTables.ToList() : new List<string>();
|
|
var requiredTablesList = requiredTables != null ? requiredTables.ToList() : new List<string>();
|
|
CheckRequiredTables(requiredTablesList);
|
|
CheckRequiredTables(requiredTablesList);
|
|
@@ -568,36 +533,33 @@ namespace InABox.Core
|
|
if (!args.Cancel) BeforeLoad(requiredTablesList);
|
|
if (!args.Cancel) BeforeLoad(requiredTablesList);
|
|
|
|
|
|
var queries = new Dictionary<string, IQueryDef>();
|
|
var queries = new Dictionary<string, IQueryDef>();
|
|
- var genericMethod = typeof(DataModel).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
|
|
|
|
- .Where(x => x.Name == nameof(LoadModelTable) && x.IsGenericMethod)
|
|
|
|
- .FirstOrDefault()!;
|
|
|
|
- foreach (var table in _tables)
|
|
|
|
- if (table.Value.ShouldLoad)
|
|
|
|
- if (requiredTables == null || requiredTablesList.Contains(table.Key))
|
|
|
|
- queries[table.Key] = (genericMethod.MakeGenericMethod(table.Value.Type).Invoke(this, new object?[]
|
|
|
|
- {
|
|
|
|
- table.Key,
|
|
|
|
- requiredQueries
|
|
|
|
- }) as IQueryDef)!;
|
|
|
|
|
|
+ foreach (var (key, table) in _tables)
|
|
|
|
+ {
|
|
|
|
+ if(requiredTables is null || requiredTablesList.Contains(key))
|
|
|
|
+ {
|
|
|
|
+ if(table is IDataModelLoadTable loadTable)
|
|
|
|
+ {
|
|
|
|
+ queries[key] = loadTable.GetQueryDef();
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ table.Load();
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
var results = Client.QueryMultiple(queries);
|
|
var results = Client.QueryMultiple(queries);
|
|
- foreach (var result in results)
|
|
|
|
- if (_tables.TryGetValue(result.Key, out var table))
|
|
|
|
- table.Table = result.Value;
|
|
|
|
|
|
+ foreach (var (key, data) in results)
|
|
|
|
+ if (_tables.TryGetValue(key, out var table) && table is IDataModelLoadTable loadTable)
|
|
|
|
+ loadTable.LoadData(data);
|
|
else
|
|
else
|
|
- Logger.Send(LogType.Error, "",
|
|
|
|
- string.Format("QueryMultiple returned table with key {0}, which is not in the data model!", result.Key));
|
|
|
|
|
|
+ Logger.Send(LogType.Error, "", $"QueryMultiple returned table with key {key}, which is not in the data model!");
|
|
|
|
|
|
args = new CancelEventArgs();
|
|
args = new CancelEventArgs();
|
|
OnAfterLoad?.Invoke(args);
|
|
OnAfterLoad?.Invoke(args);
|
|
if (!args.Cancel) AfterLoad(requiredTablesList);
|
|
if (!args.Cancel) AfterLoad(requiredTablesList);
|
|
}
|
|
}
|
|
|
|
|
|
- public void LoadModel(IEnumerable<string>? requiredTables, params IDataModelQueryDef[] requiredQueries)
|
|
|
|
- {
|
|
|
|
- LoadModel(requiredTables, requiredQueries.ToDictionary(x => x.TableName, x => x as IQueryDef));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
public void LoadModel()
|
|
public void LoadModel()
|
|
{
|
|
{
|
|
LoadModel(DefaultTableNames);
|
|
LoadModel(DefaultTableNames);
|
|
@@ -819,51 +781,6 @@ namespace InABox.Core
|
|
public bool RemoveTable<TType>(string? alias = null) => RemoveTable(typeof(TType), alias);
|
|
public bool RemoveTable<TType>(string? alias = null) => RemoveTable(typeof(TType), alias);
|
|
|
|
|
|
#endregion
|
|
#endregion
|
|
-
|
|
|
|
- #region Cache of Link Values based on relationships
|
|
|
|
-
|
|
|
|
- // Type = Parent, String = ParentColumn, List=Values
|
|
|
|
- //private Dictionary<Type, Dictionary<String, List<object>>> _ids = new Dictionary<Type, Dictionary<String, List<object>>>();
|
|
|
|
-
|
|
|
|
- // private void SetupIds<TType>(String columnname)
|
|
|
|
- //{
|
|
|
|
- // if (!_ids.ContainsKey(typeof(TParent)))
|
|
|
|
- // _ids[typeof(TParent)] = new Dictionary<string, List<object>>();
|
|
|
|
- // _ids[typeof(TParent)][relationship.ParentColumn] = new List<object>();
|
|
|
|
- //}
|
|
|
|
-
|
|
|
|
- //private void ClearIDs<TType>()
|
|
|
|
- //{
|
|
|
|
- // if (_ids.ContainsKey(typeof(TType)))
|
|
|
|
- // {
|
|
|
|
- // var cols = _ids[typeof(TType)];
|
|
|
|
- // foreach (var col in cols.Keys)
|
|
|
|
- // cols[col].Clear();
|
|
|
|
- // }
|
|
|
|
- //}
|
|
|
|
-
|
|
|
|
- //private void UpdateIDs<TType>()
|
|
|
|
- //{
|
|
|
|
- // if (_ids.ContainsKey(typeof(TType)))
|
|
|
|
- // {
|
|
|
|
- // var cols = _ids[typeof(TType)];
|
|
|
|
- // foreach (var col in cols.Keys)
|
|
|
|
- // cols[col].AddRange(GetTable<TType>().ExtractValues<object>(col, true));
|
|
|
|
- // }
|
|
|
|
- //}
|
|
|
|
-
|
|
|
|
- //protected object[] GetIDs<TType>(String column)
|
|
|
|
- //{
|
|
|
|
- // if (_ids.ContainsKey(typeof(TType)))
|
|
|
|
- // {
|
|
|
|
- // var cols = _ids[typeof(TType)];
|
|
|
|
- // if (cols.ContainsKey(column))
|
|
|
|
- // return cols[column].ToArray();
|
|
|
|
- // }
|
|
|
|
- // return new object[] { };
|
|
|
|
- //}
|
|
|
|
-
|
|
|
|
- #endregion
|
|
|
|
}
|
|
}
|
|
|
|
|
|
public abstract class DataModel<T> : DataModel, IDataModel<T>
|
|
public abstract class DataModel<T> : DataModel, IDataModel<T>
|