|
@@ -35,6 +35,24 @@ namespace InABox.Clients
|
|
|
where T: BaseObject, new()
|
|
|
=> Results[typeof(T).Name].ToObjects<T>();
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Like <see cref="Get{T}"/>, but calls <see cref="CoreTable.ToArray{T}"/> on the table.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T"></typeparam>
|
|
|
+ /// <returns></returns>
|
|
|
+ public T[] GetArray<T>()
|
|
|
+ where T: BaseObject, new()
|
|
|
+ => Results[typeof(T).Name].ToArray<T>();
|
|
|
+
|
|
|
+ /// <summary>
|
|
|
+ /// Like <see cref="Get{T}"/>, but calls <see cref="CoreTable.ToList{T}"/> on the table.
|
|
|
+ /// </summary>
|
|
|
+ /// <typeparam name="T"></typeparam>
|
|
|
+ /// <returns></returns>
|
|
|
+ public List<T> GetList<T>()
|
|
|
+ where T: BaseObject, new()
|
|
|
+ => Results[typeof(T).Name].ToList<T>();
|
|
|
+
|
|
|
public CoreTable Get(string name) => Results[name];
|
|
|
|
|
|
public CoreTable GetOrDefault(string name) => Results.GetValueOrDefault(name);
|
|
@@ -659,4 +677,104 @@ namespace InABox.Clients
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+ public static class ClientExtensions
|
|
|
+ {
|
|
|
+ /// <summary>
|
|
|
+ /// Load the properties of any <see cref="EntityLink{T}"/>s on this <typeparamref name="T"/> where the <see cref="IEntityLink.ID"/> is not <see cref="Guid.Empty"/>.
|
|
|
+ /// This allows us to populate columns of transient objects, as long as they are linked by the ID. What this actually then does is query each
|
|
|
+ /// linked table with the required columns.
|
|
|
+ /// </summary>
|
|
|
+ /// <param name="columns"></param>
|
|
|
+ public static void LoadForeignProperties<T>(this IEnumerable<T> items, Columns<T> columns)
|
|
|
+ where T : BaseObject, new()
|
|
|
+ {
|
|
|
+ // Lists of properties that we need, arranged by the entity link property which is their parent.
|
|
|
+ // LinkIDProperty : (Type, Properties: [(columnName, property)], Objects)
|
|
|
+ var newData = new Dictionary<IProperty, Tuple<Type, List<Tuple<string, IProperty>>, HashSet<T>>>();
|
|
|
+
|
|
|
+ foreach (var column in columns)
|
|
|
+ {
|
|
|
+ var property = DatabaseSchema.Property(typeof(T), column.Property);
|
|
|
+ if (property?.GetOuterParent(x => x.IsEntityLink) is IProperty linkProperty)
|
|
|
+ {
|
|
|
+ var remaining = column.Property[(linkProperty.Name.Length + 1)..];
|
|
|
+ if (remaining.Equals(nameof(IEntityLink.ID)))
|
|
|
+ {
|
|
|
+ // This guy isn't foreign, so we don't pull him.
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ var idProperty = DatabaseSchema.Property(typeof(T), linkProperty.Name + "." + nameof(IEntityLink.ID))!;
|
|
|
+
|
|
|
+ var linkType = linkProperty.PropertyType.GetInterfaceDefinition(typeof(IEntityLink<>))!.GenericTypeArguments[0];
|
|
|
+ if (!newData.TryGetValue(idProperty, out var data))
|
|
|
+ {
|
|
|
+ data = new Tuple<Type, List<Tuple<string, IProperty>>, HashSet<T>>(
|
|
|
+ linkType,
|
|
|
+ new List<Tuple<string, IProperty>>(),
|
|
|
+ new HashSet<T>());
|
|
|
+ newData.Add(idProperty, data);
|
|
|
+ }
|
|
|
+
|
|
|
+ var any = false;
|
|
|
+ foreach (var item in items)
|
|
|
+ {
|
|
|
+ if (!item.LoadedColumns.Contains(column.Property))
|
|
|
+ {
|
|
|
+ var linkID = (Guid)idProperty.Getter()(item);
|
|
|
+ if (linkID != Guid.Empty)
|
|
|
+ {
|
|
|
+ any = true;
|
|
|
+ data.Item3.Add(item);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (any)
|
|
|
+ {
|
|
|
+ data.Item2.Add(new Tuple<string, IProperty>(remaining, property));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var queryDefs = new List<IKeyedQueryDef>();
|
|
|
+ foreach (var (prop, data) in newData)
|
|
|
+ {
|
|
|
+ if (data.Item2.Count != 0)
|
|
|
+ {
|
|
|
+ var ids = data.Item3.Select(prop.Getter()).Cast<Guid>().ToArray();
|
|
|
+ queryDefs.Add(new KeyedQueryDef(prop.Name, data.Item1,
|
|
|
+ Filter.Create<Entity>(data.Item1, x => x.ID).InList(ids),
|
|
|
+ Columns.None(data.Item1)
|
|
|
+ .Add(data.Item2.Select(x => x.Item1))
|
|
|
+ .Add<Entity>(x => x.ID)));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ var results = Client.QueryMultiple(queryDefs);
|
|
|
+ foreach(var (prop, data) in newData)
|
|
|
+ {
|
|
|
+ var table = results.GetOrDefault(prop.Name);
|
|
|
+ if(table is null)
|
|
|
+ {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ foreach (var entity in data.Item3)
|
|
|
+ {
|
|
|
+ var linkID = (Guid)prop.Getter()(entity);
|
|
|
+ var row = table.Rows.FirstOrDefault(x => x.Get<Entity, Guid>(x => x.ID) == linkID);
|
|
|
+ if (row != null)
|
|
|
+ {
|
|
|
+ foreach (var (name, property) in data.Item2)
|
|
|
+ {
|
|
|
+ if (!entity.LoadedColumns.Contains(property.Name))
|
|
|
+ {
|
|
|
+ property.Setter()(entity, row[name]);
|
|
|
+ entity.LoadedColumns.Add(property.Name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|