|
@@ -317,6 +317,90 @@ namespace InABox.DynamicGrid
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /// <summary>
|
|
|
+ /// Load the properties of any <see cref="EntityLink{T}"/>s on this <see cref="TMany"/> 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>
|
|
|
+ private void LoadForeignProperties(Columns<TMany> columns)
|
|
|
+ {
|
|
|
+ // 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<TMany>>>();
|
|
|
+
|
|
|
+ foreach (var column in columns)
|
|
|
+ {
|
|
|
+ var property = DatabaseSchema.Property(typeof(TMany), 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(TMany), 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<TMany>>(
|
|
|
+ linkType,
|
|
|
+ new List<Tuple<string, IProperty>>(),
|
|
|
+ new HashSet<TMany>());
|
|
|
+ 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(remaining, property));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ foreach (var (prop, data) in newData)
|
|
|
+ {
|
|
|
+ if (data.Item2.Any())
|
|
|
+ {
|
|
|
+ var ids = data.Item3.Select(prop.Getter()).Cast<Guid>().ToArray();
|
|
|
+ var table = Client.Create(data.Item1).Query(
|
|
|
+ Filter.Create<Entity>(data.Item1, x => x.ID).InList(ids),
|
|
|
+ Columns.Create(data.Item1, data.Item2.Select(x => x.Item1).ToArray()).Add<Entity>(x => x.ID));
|
|
|
+ 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 is not null)
|
|
|
+ {
|
|
|
+ foreach (var (name, property) in data.Item2)
|
|
|
+ {
|
|
|
+ if (!entity.LoadedColumns.Contains(property.Name))
|
|
|
+ {
|
|
|
+ property.Setter()(entity, row[name]);
|
|
|
+ entity.LoadedColumns.Add(property.Name);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
protected override void Reload(Filters<TMany> criteria, Columns<TMany> columns, ref SortOrder<TMany>? sort,
|
|
|
Action<CoreTable?, Exception?> action)
|
|
|
{
|
|
@@ -348,6 +432,7 @@ namespace InABox.DynamicGrid
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+ LoadForeignProperties(columns);
|
|
|
|
|
|
if (sort != null)
|
|
|
{
|