|
|
@@ -14,717 +14,716 @@ using InABox.Core;
|
|
|
using InABox.WPF;
|
|
|
using Expression = System.Linq.Expressions.Expression;
|
|
|
|
|
|
-namespace InABox.DynamicGrid
|
|
|
-{
|
|
|
- public interface IDynamicDataGrid : IDynamicGrid
|
|
|
- {
|
|
|
- /// <summary>
|
|
|
- /// The tag the the DynamicGridColumns are stored against. If set to <see langword="null"/>,
|
|
|
- /// the name of <typeparamref name="TEntity"/> is used as a default.
|
|
|
- /// </summary>
|
|
|
- string? ColumnsTag { get; set; }
|
|
|
+namespace InABox.DynamicGrid;
|
|
|
|
|
|
- IColumns LoadEditorColumns();
|
|
|
- }
|
|
|
+public interface IDynamicDataGrid : IDynamicGrid
|
|
|
+{
|
|
|
+ /// <summary>
|
|
|
+ /// The tag the the DynamicGridColumns are stored against. If set to <see langword="null"/>,
|
|
|
+ /// the name of <typeparamref name="TEntity"/> is used as a default.
|
|
|
+ /// </summary>
|
|
|
+ string? ColumnsTag { get; set; }
|
|
|
|
|
|
- public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid where TEntity : Entity, IRemotable, IPersistent, new()
|
|
|
- {
|
|
|
+ IColumns LoadEditorColumns();
|
|
|
+}
|
|
|
|
|
|
- public delegate void OnReloadEventHandler(object sender, Filters<TEntity> criteria, Columns<TEntity> columns, ref SortOrder<TEntity>? sortby);
|
|
|
+public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid where TEntity : Entity, IRemotable, IPersistent, new()
|
|
|
+{
|
|
|
|
|
|
- private readonly int ChunkSize = 500;
|
|
|
- private Button MergeBtn = null!; //Late-initialised
|
|
|
+ public delegate void OnReloadEventHandler(object sender, Filters<TEntity> criteria, Columns<TEntity> columns, ref SortOrder<TEntity>? sortby);
|
|
|
|
|
|
- public DynamicGridFilterButtonComponent<TEntity> FilterComponent;
|
|
|
- protected DynamicGridCustomColumnsComponent<TEntity> ColumnsComponent;
|
|
|
+ private readonly int ChunkSize = 500;
|
|
|
+ private Button MergeBtn = null!; //Late-initialised
|
|
|
|
|
|
- private Column<TEntity>[] FilterColumns;
|
|
|
+ public DynamicGridFilterButtonComponent<TEntity> FilterComponent;
|
|
|
+ protected DynamicGridCustomColumnsComponent<TEntity> ColumnsComponent;
|
|
|
|
|
|
- public DynamicDataGrid() : base()
|
|
|
- {
|
|
|
- var fields = DatabaseSchema.Properties(typeof(TEntity));
|
|
|
+ private Column<TEntity>[] FilterColumns;
|
|
|
|
|
|
- foreach (var field in fields)
|
|
|
- if (!MasterColumns.Any(x => x.ColumnName == field.Name))
|
|
|
- MasterColumns.Add(new DynamicGridColumn { ColumnName = field.Name });
|
|
|
+ public DynamicDataGrid() : base()
|
|
|
+ {
|
|
|
+ var fields = DatabaseSchema.Properties(typeof(TEntity));
|
|
|
|
|
|
- var cols = LookupFactory.DefineColumns<TEntity>();
|
|
|
+ foreach (var field in fields)
|
|
|
+ if (!MasterColumns.Any(x => x.ColumnName == field.Name))
|
|
|
+ MasterColumns.Add(new DynamicGridColumn { ColumnName = field.Name });
|
|
|
|
|
|
- // Minimum Columns for Lookup values
|
|
|
- foreach (var col in cols)
|
|
|
- HiddenColumns.Add(CoreUtils.CreateLambdaExpression<TEntity>(col.Property));
|
|
|
+ var cols = LookupFactory.DefineColumns<TEntity>();
|
|
|
|
|
|
- // Minimum Columns for Successful Saving
|
|
|
- // This should be cross-checked with the relevant Store<>
|
|
|
- // so that clients will (usually) provide sufficient columns for saving
|
|
|
- foreach (var col in LookupFactory.RequiredColumns<TEntity>())
|
|
|
- HiddenColumns.Add(CoreUtils.CreateLambdaExpression<TEntity>(col.Property));
|
|
|
+ // Minimum Columns for Lookup values
|
|
|
+ foreach (var col in cols)
|
|
|
+ HiddenColumns.Add(CoreUtils.CreateLambdaExpression<TEntity>(col.Property));
|
|
|
|
|
|
- //HiddenColumns.Add(x => x.ID);
|
|
|
+ // Minimum Columns for Successful Saving
|
|
|
+ // This should be cross-checked with the relevant Store<>
|
|
|
+ // so that clients will (usually) provide sufficient columns for saving
|
|
|
+ foreach (var col in LookupFactory.RequiredColumns<TEntity>())
|
|
|
+ HiddenColumns.Add(CoreUtils.CreateLambdaExpression<TEntity>(col.Property));
|
|
|
|
|
|
- if (typeof(TEntity).GetInterfaces().Contains(typeof(IIssues)))
|
|
|
- {
|
|
|
- HiddenColumns.Add(x => (x as IIssues)!.Issues);
|
|
|
- var coltype = typeof(DynamicIssuesColumn<>).MakeGenericType(typeof(TEntity));
|
|
|
- ActionColumns.Add((Activator.CreateInstance(coltype, this) as DynamicActionColumn)!);
|
|
|
- }
|
|
|
+ //HiddenColumns.Add(x => x.ID);
|
|
|
|
|
|
- SetupFilterColumns();
|
|
|
+ if (typeof(TEntity).GetInterfaces().Contains(typeof(IIssues)))
|
|
|
+ {
|
|
|
+ HiddenColumns.Add(x => (x as IIssues)!.Issues);
|
|
|
+ var coltype = typeof(DynamicIssuesColumn<>).MakeGenericType(typeof(TEntity));
|
|
|
+ ActionColumns.Add((Activator.CreateInstance(coltype, this) as DynamicActionColumn)!);
|
|
|
}
|
|
|
|
|
|
- protected override void Init()
|
|
|
- {
|
|
|
- FilterComponent = new(this,
|
|
|
- new GlobalConfiguration<CoreFilterDefinitions>(GetTag()),
|
|
|
- new UserConfiguration<CoreFilterDefinitions>(GetTag()));
|
|
|
- FilterComponent.OnFilterRefresh += () => Refresh(false, true);
|
|
|
+ SetupFilterColumns();
|
|
|
+ }
|
|
|
|
|
|
- ColumnsComponent = new DynamicGridCustomColumnsComponent<TEntity>(this, GetTag());
|
|
|
+ protected override void Init()
|
|
|
+ {
|
|
|
+ FilterComponent = new(this,
|
|
|
+ new GlobalConfiguration<CoreFilterDefinitions>(GetTag()),
|
|
|
+ new UserConfiguration<CoreFilterDefinitions>(GetTag()));
|
|
|
+ FilterComponent.OnFilterRefresh += () => Refresh(false, true);
|
|
|
|
|
|
- MergeBtn = AddButton("Merge", Wpf.Resources.merge.AsBitmapImage(Color.White), DoMerge);
|
|
|
- }
|
|
|
- protected override void DoReconfigure(FluentList<DynamicGridOption> options)
|
|
|
- {
|
|
|
- options.BeginUpdate();
|
|
|
- if (Security.CanEdit<TEntity>())
|
|
|
- options.Add(DynamicGridOption.AddRows).Add(DynamicGridOption.EditRows);
|
|
|
- if (Security.CanDelete<TEntity>())
|
|
|
- options.Add(DynamicGridOption.DeleteRows);
|
|
|
- if (Security.CanImport<TEntity>() && typeof(TEntity).HasInterface<IImportable>())
|
|
|
- options.Add(DynamicGridOption.ImportData);
|
|
|
- if (Security.CanExport<TEntity>() && typeof(TEntity).HasInterface<IExportable>())
|
|
|
- options.Add(DynamicGridOption.ExportData);
|
|
|
- if (Security.CanMerge<TEntity>())
|
|
|
- options.Add(DynamicGridOption.MultiSelect);
|
|
|
- options.EndUpdate();
|
|
|
- }
|
|
|
+ ColumnsComponent = new DynamicGridCustomColumnsComponent<TEntity>(this, GetTag());
|
|
|
+
|
|
|
+ MergeBtn = AddButton("Merge", Wpf.Resources.merge.AsBitmapImage(Color.White), DoMerge);
|
|
|
+ }
|
|
|
+ protected override void DoReconfigure(FluentList<DynamicGridOption> options)
|
|
|
+ {
|
|
|
+ options.BeginUpdate();
|
|
|
+ if (Security.CanEdit<TEntity>())
|
|
|
+ options.Add(DynamicGridOption.AddRows).Add(DynamicGridOption.EditRows);
|
|
|
+ if (Security.CanDelete<TEntity>())
|
|
|
+ options.Add(DynamicGridOption.DeleteRows);
|
|
|
+ if (Security.CanImport<TEntity>() && typeof(TEntity).HasInterface<IImportable>())
|
|
|
+ options.Add(DynamicGridOption.ImportData);
|
|
|
+ if (Security.CanExport<TEntity>() && typeof(TEntity).HasInterface<IExportable>())
|
|
|
+ options.Add(DynamicGridOption.ExportData);
|
|
|
+ if (Security.CanMerge<TEntity>())
|
|
|
+ options.Add(DynamicGridOption.MultiSelect);
|
|
|
+ options.EndUpdate();
|
|
|
+ }
|
|
|
|
|
|
- [MemberNotNull(nameof(FilterColumns))]
|
|
|
- private void SetupFilterColumns()
|
|
|
+ [MemberNotNull(nameof(FilterColumns))]
|
|
|
+ private void SetupFilterColumns()
|
|
|
+ {
|
|
|
+ if (typeof(TEntity).GetCustomAttribute<AutoEntity>() is AutoEntity auto)
|
|
|
{
|
|
|
- if (typeof(TEntity).GetCustomAttribute<AutoEntity>() is AutoEntity auto)
|
|
|
+ if (auto.Generator is not null)
|
|
|
{
|
|
|
- if (auto.Generator is not null)
|
|
|
- {
|
|
|
- var columns = auto.Generator.IDColumns;
|
|
|
- FilterColumns = columns.Select(x => new Column<TEntity>(x.Property)).ToArray();
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- FilterColumns = Array.Empty<Column<TEntity>>();
|
|
|
- }
|
|
|
+ var columns = auto.Generator.IDColumns;
|
|
|
+ FilterColumns = columns.Select(x => new Column<TEntity>(x.Property)).ToArray();
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- FilterColumns = new[] { new Column<TEntity>(x => x.ID) };
|
|
|
- }
|
|
|
-
|
|
|
- foreach (var column in FilterColumns)
|
|
|
- {
|
|
|
- AddHiddenColumn(column.Property);
|
|
|
+ FilterColumns = Array.Empty<Column<TEntity>>();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
- protected override void BeforeLoad(IDynamicEditorForm form, TEntity[] items)
|
|
|
+ else
|
|
|
{
|
|
|
- form.ReadOnly = form.ReadOnly || !Security.CanEdit<TEntity>();
|
|
|
- base.BeforeLoad(form, items);
|
|
|
+ FilterColumns = new[] { new Column<TEntity>(x => x.ID) };
|
|
|
}
|
|
|
|
|
|
- private string? _columnsTag;
|
|
|
- public string? ColumnsTag
|
|
|
+ foreach (var column in FilterColumns)
|
|
|
{
|
|
|
- get => _columnsTag;
|
|
|
- set
|
|
|
- {
|
|
|
- _columnsTag = value;
|
|
|
- ColumnsComponent.Tag = GetTag();
|
|
|
- }
|
|
|
+ AddHiddenColumn(column.Property);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- protected override void OptionsChanged()
|
|
|
- {
|
|
|
- base.OptionsChanged();
|
|
|
- if (MergeBtn != null)
|
|
|
- MergeBtn.Visibility = Visibility.Collapsed;
|
|
|
-
|
|
|
- FilterComponent.ShowFilterList = HasOption(DynamicGridOption.FilterRows) && !HasOption(DynamicGridOption.HideDatabaseFilters);
|
|
|
- }
|
|
|
+ protected override void BeforeLoad(IDynamicEditorForm form, TEntity[] items)
|
|
|
+ {
|
|
|
+ form.ReadOnly = form.ReadOnly || !Security.CanEdit<TEntity>();
|
|
|
+ base.BeforeLoad(form, items);
|
|
|
+ }
|
|
|
|
|
|
- protected override void SelectItems(CoreRow[]? rows)
|
|
|
+ private string? _columnsTag;
|
|
|
+ public string? ColumnsTag
|
|
|
+ {
|
|
|
+ get => _columnsTag;
|
|
|
+ set
|
|
|
{
|
|
|
- base.SelectItems(rows);
|
|
|
- MergeBtn.Visibility = HasOption(DynamicGridOption.MultiSelect) && typeof(TEntity).IsAssignableTo(typeof(IMergeable)) && Security.CanMerge<TEntity>() && rows != null && rows.Length > 1
|
|
|
- ? Visibility.Visible
|
|
|
- : Visibility.Collapsed;
|
|
|
+ _columnsTag = value;
|
|
|
+ ColumnsComponent.Tag = GetTag();
|
|
|
}
|
|
|
-
|
|
|
- public event OnReloadEventHandler? OnReload;
|
|
|
+ }
|
|
|
|
|
|
- protected override void Reload(Filters<TEntity> criteria, Columns<TEntity> columns, ref SortOrder<TEntity>? sort,
|
|
|
- Action<CoreTable?, Exception?> action)
|
|
|
- {
|
|
|
- criteria.Add(FilterComponent.GetFilter());
|
|
|
+ protected override void OptionsChanged()
|
|
|
+ {
|
|
|
+ base.OptionsChanged();
|
|
|
+ if (MergeBtn != null)
|
|
|
+ MergeBtn.Visibility = Visibility.Collapsed;
|
|
|
|
|
|
- OnReload?.Invoke(this, criteria, columns, ref sort);
|
|
|
- new Client<TEntity>().Query(criteria.Combine(), columns, sort, action);
|
|
|
- }
|
|
|
+ FilterComponent.ShowFilterList = HasOption(DynamicGridOption.FilterRows) && !HasOption(DynamicGridOption.HideDatabaseFilters);
|
|
|
+ }
|
|
|
|
|
|
- private CoreRow[]? SelectedBeforeRefresh;
|
|
|
- protected override void OnAfterRefresh()
|
|
|
- {
|
|
|
- base.OnAfterRefresh();
|
|
|
+ protected override void SelectItems(CoreRow[]? rows)
|
|
|
+ {
|
|
|
+ base.SelectItems(rows);
|
|
|
+ MergeBtn.Visibility = HasOption(DynamicGridOption.MultiSelect) && typeof(TEntity).IsAssignableTo(typeof(IMergeable)) && Security.CanMerge<TEntity>() && rows != null && rows.Length > 1
|
|
|
+ ? Visibility.Visible
|
|
|
+ : Visibility.Collapsed;
|
|
|
+ }
|
|
|
+
|
|
|
+ public event OnReloadEventHandler? OnReload;
|
|
|
|
|
|
- if (SelectedBeforeRefresh is not null)
|
|
|
- {
|
|
|
- var selectedValues = SelectedBeforeRefresh
|
|
|
- .Select(x => FilterColumns.Select(c => x[c.Property]).ToList())
|
|
|
- .ToList();
|
|
|
+ protected override void Reload(Filters<TEntity> criteria, Columns<TEntity> columns, ref SortOrder<TEntity>? sort,
|
|
|
+ Action<CoreTable?, Exception?> action)
|
|
|
+ {
|
|
|
+ criteria.Add(FilterComponent.GetFilter());
|
|
|
|
|
|
- SelectedBeforeRefresh = null;
|
|
|
+ OnReload?.Invoke(this, criteria, columns, ref sort);
|
|
|
+ new Client<TEntity>().Query(criteria.Combine(), columns, sort, action);
|
|
|
+ }
|
|
|
|
|
|
- var selectedRows = Data.Rows.Where(r =>
|
|
|
- {
|
|
|
- return selectedValues.Any(v =>
|
|
|
- {
|
|
|
- for (int i = 0; i < v.Count; ++i)
|
|
|
- {
|
|
|
- if (v[i]?.Equals(r[FilterColumns[i].Property]) != true)
|
|
|
- return false;
|
|
|
- }
|
|
|
- return true;
|
|
|
- });
|
|
|
- }).ToArray();
|
|
|
-
|
|
|
- SelectedRows = selectedRows;
|
|
|
- SelectItems(selectedRows);
|
|
|
- }
|
|
|
- }
|
|
|
+ private CoreRow[]? SelectedBeforeRefresh;
|
|
|
+ protected override void OnAfterRefresh()
|
|
|
+ {
|
|
|
+ base.OnAfterRefresh();
|
|
|
|
|
|
- public override void Refresh(bool reloadcolumns, bool reloaddata)
|
|
|
+ if (SelectedBeforeRefresh is not null)
|
|
|
{
|
|
|
- SelectedBeforeRefresh = SelectedRows;
|
|
|
- base.Refresh(reloadcolumns, reloaddata);
|
|
|
- }
|
|
|
+ var selectedValues = SelectedBeforeRefresh
|
|
|
+ .Select(x => FilterColumns.Select(c => x[c.Property]).ToList())
|
|
|
+ .ToList();
|
|
|
|
|
|
- IColumns IDynamicDataGrid.LoadEditorColumns() => LoadEditorColumns();
|
|
|
+ SelectedBeforeRefresh = null;
|
|
|
|
|
|
- public Columns<TEntity> LoadEditorColumns()
|
|
|
- {
|
|
|
- return DynamicGridUtils.LoadEditorColumns(DataColumns());
|
|
|
- }
|
|
|
-
|
|
|
- private Filter<TEntity>? GetRowFilter(CoreRow row)
|
|
|
- {
|
|
|
- var newFilters = new Filters<TEntity>();
|
|
|
- foreach (var column in FilterColumns)
|
|
|
+ var selectedRows = Data.Rows.Where(r =>
|
|
|
{
|
|
|
- newFilters.Add(new Filter<TEntity>(column.Property).IsEqualTo(row[column.Property]));
|
|
|
- }
|
|
|
- return newFilters.Combine();
|
|
|
- }
|
|
|
-
|
|
|
- public override TEntity[] LoadItems(CoreRow[] rows)
|
|
|
- {
|
|
|
- Filter<TEntity>? filter = null;
|
|
|
- var results = new List<TEntity>();
|
|
|
- for (var i = 0; i < rows.Length; i += ChunkSize)
|
|
|
- {
|
|
|
- var chunk = rows.Skip(i).Take(ChunkSize);
|
|
|
- foreach (var row in chunk)
|
|
|
+ return selectedValues.Any(v =>
|
|
|
{
|
|
|
- var newFilter = GetRowFilter(row);
|
|
|
-
|
|
|
- if (newFilter is not null)
|
|
|
+ for (int i = 0; i < v.Count; ++i)
|
|
|
{
|
|
|
- //var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
- if (filter is null)
|
|
|
- filter = newFilter;//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
- else
|
|
|
- filter = filter.Or(newFilter);//.Or(x => x.ID).IsEqualTo(id);
|
|
|
+ if (v[i]?.Equals(r[FilterColumns[i].Property]) != true)
|
|
|
+ return false;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- var columns = LoadEditorColumns(); // new Columns<TEntity>().Default(ColumnType.IncludeOptional, ColumnType.IncludeForeignKeys, ColumnType.IncludeUserProperties);
|
|
|
- var data = Client.Query(filter, columns);
|
|
|
- results.AddRange(data.ToObjects<TEntity>());
|
|
|
- }
|
|
|
+ return true;
|
|
|
+ });
|
|
|
+ }).ToArray();
|
|
|
|
|
|
- return results.ToArray();
|
|
|
+ SelectedRows = selectedRows;
|
|
|
+ SelectItems(selectedRows);
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- public override TEntity LoadItem(CoreRow row)
|
|
|
- {
|
|
|
- var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
- var filter = GetRowFilter(row);//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
- return Client.Query(filter, LoadEditorColumns()).ToObjects<TEntity>().FirstOrDefault()
|
|
|
- ?? throw new Exception($"No {typeof(TEntity).Name} with ID {id}");
|
|
|
- }
|
|
|
+ public override void Refresh(bool reloadcolumns, bool reloaddata)
|
|
|
+ {
|
|
|
+ SelectedBeforeRefresh = SelectedRows;
|
|
|
+ base.Refresh(reloadcolumns, reloaddata);
|
|
|
+ }
|
|
|
|
|
|
- public override void SaveItem(TEntity item)
|
|
|
- {
|
|
|
- Client.Save(item, "Edited by User");
|
|
|
- }
|
|
|
+ IColumns IDynamicDataGrid.LoadEditorColumns() => LoadEditorColumns();
|
|
|
+
|
|
|
+ public Columns<TEntity> LoadEditorColumns()
|
|
|
+ {
|
|
|
+ return DynamicGridUtils.LoadEditorColumns(DataColumns());
|
|
|
+ }
|
|
|
|
|
|
- public override void SaveItems(TEntity[] items)
|
|
|
+ private Filter<TEntity>? GetRowFilter(CoreRow row)
|
|
|
+ {
|
|
|
+ var newFilters = new Filters<TEntity>();
|
|
|
+ foreach (var column in FilterColumns)
|
|
|
{
|
|
|
- Client.Save(items, "Edited by User");
|
|
|
+ newFilters.Add(new Filter<TEntity>(column.Property).IsEqualTo(row[column.Property]));
|
|
|
}
|
|
|
+ return newFilters.Combine();
|
|
|
+ }
|
|
|
|
|
|
- public override void DeleteItems(params CoreRow[] rows)
|
|
|
+ public override TEntity[] LoadItems(CoreRow[] rows)
|
|
|
+ {
|
|
|
+ Filter<TEntity>? filter = null;
|
|
|
+ var results = new List<TEntity>();
|
|
|
+ for (var i = 0; i < rows.Length; i += ChunkSize)
|
|
|
{
|
|
|
- var deletes = new List<TEntity>();
|
|
|
- foreach (var row in rows)
|
|
|
+ var chunk = rows.Skip(i).Take(ChunkSize);
|
|
|
+ foreach (var row in chunk)
|
|
|
{
|
|
|
- var delete = new TEntity();
|
|
|
- foreach (var column in FilterColumns)
|
|
|
+ var newFilter = GetRowFilter(row);
|
|
|
+
|
|
|
+ if (newFilter is not null)
|
|
|
{
|
|
|
- CoreUtils.SetPropertyValue(delete, column.Property, row[column.Property]);
|
|
|
+ //var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
+ if (filter is null)
|
|
|
+ filter = newFilter;//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
+ else
|
|
|
+ filter = filter.Or(newFilter);//.Or(x => x.ID).IsEqualTo(id);
|
|
|
}
|
|
|
-
|
|
|
- //var delete = /* row.ToObject<TEntity>(); */
|
|
|
- deletes.Add(delete);
|
|
|
}
|
|
|
|
|
|
- Client.Delete(deletes, "Deleted on User Request");
|
|
|
+ var columns = LoadEditorColumns(); // new Columns<TEntity>().Default(ColumnType.IncludeOptional, ColumnType.IncludeForeignKeys, ColumnType.IncludeUserProperties);
|
|
|
+ var data = Client.Query(filter, columns);
|
|
|
+ results.AddRange(data.ToObjects<TEntity>());
|
|
|
}
|
|
|
|
|
|
- private object GetPropertyValue(Expression member, object obj)
|
|
|
- {
|
|
|
- var objectMember = Expression.Convert(member, typeof(object));
|
|
|
+ return results.ToArray();
|
|
|
+ }
|
|
|
|
|
|
- var getterLambda = Expression.Lambda<Func<object>>(objectMember);
|
|
|
+ public override TEntity LoadItem(CoreRow row)
|
|
|
+ {
|
|
|
+ var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
+ var filter = GetRowFilter(row);//new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
+ return Client.Query(filter, LoadEditorColumns()).ToObjects<TEntity>().FirstOrDefault()
|
|
|
+ ?? throw new Exception($"No {typeof(TEntity).Name} with ID {id}");
|
|
|
+ }
|
|
|
|
|
|
- var getter = getterLambda.Compile();
|
|
|
+ public override void SaveItem(TEntity item)
|
|
|
+ {
|
|
|
+ Client.Save(item, "Edited by User");
|
|
|
+ }
|
|
|
|
|
|
- return getter();
|
|
|
- }
|
|
|
+ public override void SaveItems(TEntity[] items)
|
|
|
+ {
|
|
|
+ Client.Save(items, "Edited by User");
|
|
|
+ }
|
|
|
|
|
|
- protected override void ObjectToRow(TEntity obj, CoreRow row)
|
|
|
+ public override void DeleteItems(params CoreRow[] rows)
|
|
|
+ {
|
|
|
+ var deletes = new List<TEntity>();
|
|
|
+ foreach (var row in rows)
|
|
|
{
|
|
|
- foreach (var column in Data.Columns)
|
|
|
+ var delete = new TEntity();
|
|
|
+ foreach (var column in FilterColumns)
|
|
|
{
|
|
|
- var prop = DatabaseSchema.Property(obj.GetType(), column.ColumnName);
|
|
|
- if (prop is StandardProperty)
|
|
|
- row.Set(column.ColumnName, CoreUtils.GetPropertyValue(obj, prop.Name));
|
|
|
- else if (prop is CustomProperty)
|
|
|
- row.Set(column.ColumnName, obj.UserProperties[column.ColumnName]);
|
|
|
+ CoreUtils.SetPropertyValue(delete, column.Property, row[column.Property]);
|
|
|
}
|
|
|
|
|
|
- //base.ObjectToRow(obj, row);
|
|
|
+ //var delete = /* row.ToObject<TEntity>(); */
|
|
|
+ deletes.Add(delete);
|
|
|
}
|
|
|
|
|
|
- //private void Auditgrid_OnReload(object sender, Dictionary<string, object> criteria, ref String sort)
|
|
|
- //{
|
|
|
- // criteria["DocumentType"] = typeof(TEntity).EntityName();
|
|
|
- // criteria["DocumentID"] = (sender as FrameworkElement).Tag;
|
|
|
+ Client.Delete(deletes, "Deleted on User Request");
|
|
|
+ }
|
|
|
|
|
|
- // sort = "TimeStamp";
|
|
|
- //}
|
|
|
+ private object GetPropertyValue(Expression member, object obj)
|
|
|
+ {
|
|
|
+ var objectMember = Expression.Convert(member, typeof(object));
|
|
|
|
|
|
- public override void LoadEditorButtons(TEntity item, DynamicEditorButtons buttons)
|
|
|
- {
|
|
|
- base.LoadEditorButtons(item, buttons);
|
|
|
- if (ClientFactory.IsSupported<AuditTrail>())
|
|
|
- buttons.Add("Audit Trail", Wpf.Resources.view.AsBitmapImage(), item, AuditTrailClick);
|
|
|
- }
|
|
|
+ var getterLambda = Expression.Lambda<Func<object>>(objectMember);
|
|
|
|
|
|
- private void AuditTrailClick(object sender, object item)
|
|
|
- {
|
|
|
- var entity = (TEntity)item;
|
|
|
- var window = new AuditWindow(entity.ID);
|
|
|
- window.ShowDialog();
|
|
|
- }
|
|
|
+ var getter = getterLambda.Compile();
|
|
|
|
|
|
- protected override DynamicGridColumns LoadColumns()
|
|
|
- {
|
|
|
- return ColumnsComponent.LoadColumns();
|
|
|
- }
|
|
|
+ return getter();
|
|
|
+ }
|
|
|
|
|
|
- protected override void SaveColumns(DynamicGridColumns columns)
|
|
|
+ protected override void ObjectToRow(TEntity obj, CoreRow row)
|
|
|
+ {
|
|
|
+ foreach (var column in Data.Columns)
|
|
|
{
|
|
|
- ColumnsComponent.SaveColumns(columns);
|
|
|
+ var prop = DatabaseSchema.Property(obj.GetType(), column.ColumnName);
|
|
|
+ if (prop is StandardProperty)
|
|
|
+ row.Set(column.ColumnName, CoreUtils.GetPropertyValue(obj, prop.Name));
|
|
|
+ else if (prop is CustomProperty)
|
|
|
+ row.Set(column.ColumnName, obj.UserProperties[column.ColumnName]);
|
|
|
}
|
|
|
|
|
|
- protected override void LoadColumnsMenu(ContextMenu menu)
|
|
|
- {
|
|
|
- base.LoadColumnsMenu(menu);
|
|
|
- ColumnsComponent.LoadColumnsMenu(menu);
|
|
|
- }
|
|
|
+ //base.ObjectToRow(obj, row);
|
|
|
+ }
|
|
|
|
|
|
- private string GetTag()
|
|
|
- {
|
|
|
- var tag = typeof(TEntity).Name;
|
|
|
- if (!string.IsNullOrWhiteSpace(ColumnsTag))
|
|
|
- tag = string.Format("{0}.{1}", tag, ColumnsTag);
|
|
|
- return tag;
|
|
|
- }
|
|
|
+ //private void Auditgrid_OnReload(object sender, Dictionary<string, object> criteria, ref String sort)
|
|
|
+ //{
|
|
|
+ // criteria["DocumentType"] = typeof(TEntity).EntityName();
|
|
|
+ // criteria["DocumentID"] = (sender as FrameworkElement).Tag;
|
|
|
|
|
|
- protected override DynamicGridSettings LoadSettings()
|
|
|
- {
|
|
|
- var tag = GetTag();
|
|
|
+ // sort = "TimeStamp";
|
|
|
+ //}
|
|
|
|
|
|
- var user = Task.Run(() => new UserConfiguration<DynamicGridSettings>(tag).Load());
|
|
|
- user.Wait();
|
|
|
+ public override void LoadEditorButtons(TEntity item, DynamicEditorButtons buttons)
|
|
|
+ {
|
|
|
+ base.LoadEditorButtons(item, buttons);
|
|
|
+ if (ClientFactory.IsSupported<AuditTrail>())
|
|
|
+ buttons.Add("Audit Trail", Wpf.Resources.view.AsBitmapImage(), item, AuditTrailClick);
|
|
|
+ }
|
|
|
|
|
|
- //var global = Task.Run(() => new GlobalConfiguration<DynamicGridSettings>(tag).Load());
|
|
|
- //global.Wait();
|
|
|
- //Task.WaitAll(user, global);
|
|
|
- //var columns = user.Result.Any() ? user.Result : global.Result;
|
|
|
+ private void AuditTrailClick(object sender, object item)
|
|
|
+ {
|
|
|
+ var entity = (TEntity)item;
|
|
|
+ var window = new AuditWindow(entity.ID);
|
|
|
+ window.ShowDialog();
|
|
|
+ }
|
|
|
|
|
|
- return user.Result;
|
|
|
- }
|
|
|
- protected override void SaveSettings(DynamicGridSettings settings)
|
|
|
- {
|
|
|
- var tag = GetTag();
|
|
|
- new UserConfiguration<DynamicGridSettings>(tag).Save(settings);
|
|
|
- }
|
|
|
+ protected override DynamicGridColumns LoadColumns()
|
|
|
+ {
|
|
|
+ return ColumnsComponent.LoadColumns();
|
|
|
+ }
|
|
|
|
|
|
- protected override BaseEditor? GetEditor(object item, DynamicGridColumn column)
|
|
|
- {
|
|
|
- var prop = DatabaseSchema.Properties(typeof(TEntity)).FirstOrDefault(x => x.Name == column.ColumnName);
|
|
|
- if (prop != null)
|
|
|
- return prop.Editor;
|
|
|
- return base.GetEditor(item, column);
|
|
|
- }
|
|
|
+ protected override void SaveColumns(DynamicGridColumns columns)
|
|
|
+ {
|
|
|
+ ColumnsComponent.SaveColumns(columns);
|
|
|
+ }
|
|
|
|
|
|
- protected override object? GetEditorValue(object item, string name)
|
|
|
- {
|
|
|
- if (item is TEntity entity)
|
|
|
- {
|
|
|
- var prop = DatabaseSchema.Properties(typeof(TEntity)).FirstOrDefault(x => x.Name == name);
|
|
|
- if (prop is CustomProperty)
|
|
|
- {
|
|
|
- if (entity.UserProperties.ContainsKey(name))
|
|
|
- return entity.UserProperties[name];
|
|
|
- return null;
|
|
|
- }
|
|
|
- }
|
|
|
+ protected override void LoadColumnsMenu(ContextMenu menu)
|
|
|
+ {
|
|
|
+ base.LoadColumnsMenu(menu);
|
|
|
+ ColumnsComponent.LoadColumnsMenu(menu);
|
|
|
+ }
|
|
|
|
|
|
- return base.GetEditorValue(item, name);
|
|
|
- }
|
|
|
+ private string GetTag()
|
|
|
+ {
|
|
|
+ var tag = typeof(TEntity).Name;
|
|
|
+ if (!string.IsNullOrWhiteSpace(ColumnsTag))
|
|
|
+ tag = string.Format("{0}.{1}", tag, ColumnsTag);
|
|
|
+ return tag;
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override DynamicGridSettings LoadSettings()
|
|
|
+ {
|
|
|
+ var tag = GetTag();
|
|
|
+
|
|
|
+ var user = Task.Run(() => new UserConfiguration<DynamicGridSettings>(tag).Load());
|
|
|
+ user.Wait();
|
|
|
+
|
|
|
+ //var global = Task.Run(() => new GlobalConfiguration<DynamicGridSettings>(tag).Load());
|
|
|
+ //global.Wait();
|
|
|
+ //Task.WaitAll(user, global);
|
|
|
+ //var columns = user.Result.Any() ? user.Result : global.Result;
|
|
|
+
|
|
|
+ return user.Result;
|
|
|
+ }
|
|
|
+ protected override void SaveSettings(DynamicGridSettings settings)
|
|
|
+ {
|
|
|
+ var tag = GetTag();
|
|
|
+ new UserConfiguration<DynamicGridSettings>(tag).Save(settings);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override BaseEditor? GetEditor(object item, DynamicGridColumn column)
|
|
|
+ {
|
|
|
+ var prop = DatabaseSchema.Properties(typeof(TEntity)).FirstOrDefault(x => x.Name == column.ColumnName);
|
|
|
+ if (prop != null)
|
|
|
+ return prop.Editor;
|
|
|
+ return base.GetEditor(item, column);
|
|
|
+ }
|
|
|
|
|
|
- protected override void SetEditorValue(object item, string name, object value)
|
|
|
+ protected override object? GetEditorValue(object item, string name)
|
|
|
+ {
|
|
|
+ if (item is TEntity entity)
|
|
|
{
|
|
|
var prop = DatabaseSchema.Properties(typeof(TEntity)).FirstOrDefault(x => x.Name == name);
|
|
|
- if (prop is CustomProperty && item is TEntity entity)
|
|
|
+ if (prop is CustomProperty)
|
|
|
{
|
|
|
- entity.UserProperties[name] = value;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- base.SetEditorValue(item, name, value);
|
|
|
+ if (entity.UserProperties.ContainsKey(name))
|
|
|
+ return entity.UserProperties[name];
|
|
|
+ return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- protected bool Duplicate(
|
|
|
- CoreRow row,
|
|
|
- Expression<Func<TEntity, object?>> codefield,
|
|
|
- Type[] childtypes)
|
|
|
+ return base.GetEditorValue(item, name);
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override void SetEditorValue(object item, string name, object value)
|
|
|
+ {
|
|
|
+ var prop = DatabaseSchema.Properties(typeof(TEntity)).FirstOrDefault(x => x.Name == name);
|
|
|
+ if (prop is CustomProperty && item is TEntity entity)
|
|
|
{
|
|
|
- var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
+ entity.UserProperties[name] = value;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ base.SetEditorValue(item, name, value);
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- var code = row.Get(codefield) as string;
|
|
|
+ protected bool Duplicate(
|
|
|
+ CoreRow row,
|
|
|
+ Expression<Func<TEntity, object?>> codefield,
|
|
|
+ Type[] childtypes)
|
|
|
+ {
|
|
|
+ var id = row.Get<TEntity, Guid>(x => x.ID);
|
|
|
+
|
|
|
+ var code = row.Get(codefield) as string;
|
|
|
|
|
|
- var tasks = new List<Task>();
|
|
|
+ var tasks = new List<Task>();
|
|
|
+
|
|
|
+ var itemtask = Task.Run(() =>
|
|
|
+ {
|
|
|
+ var filter = new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
+ var result = new Client<TEntity>().Load(filter).FirstOrDefault()
|
|
|
+ ?? throw new Exception("Entity does not exist!");
|
|
|
+ return result;
|
|
|
+ });
|
|
|
+ tasks.Add(itemtask);
|
|
|
+ //itemtask.Wait();
|
|
|
|
|
|
- var itemtask = Task.Run(() =>
|
|
|
+ Task<List<string?>>? codetask = null;
|
|
|
+ if (!string.IsNullOrWhiteSpace(code))
|
|
|
+ {
|
|
|
+ codetask = Task.Run(() =>
|
|
|
{
|
|
|
- var filter = new Filter<TEntity>(x => x.ID).IsEqualTo(id);
|
|
|
- var result = new Client<TEntity>().Load(filter).FirstOrDefault()
|
|
|
- ?? throw new Exception("Entity does not exist!");
|
|
|
+ var columns = Columns.None<TEntity>().Add(codefield);
|
|
|
+ //columns.Add<String>(codefield);
|
|
|
+ var filter = new Filter<TEntity>(codefield).BeginsWith(code);
|
|
|
+ var table = new Client<TEntity>().Query(filter, columns);
|
|
|
+ var result = table.Rows.Select(x => x.Get(codefield) as string).ToList();
|
|
|
return result;
|
|
|
});
|
|
|
- tasks.Add(itemtask);
|
|
|
- //itemtask.Wait();
|
|
|
+ tasks.Add(codetask);
|
|
|
+ }
|
|
|
+ //codetask.Wait();
|
|
|
|
|
|
- Task<List<string?>>? codetask = null;
|
|
|
- if (!string.IsNullOrWhiteSpace(code))
|
|
|
+ var children = new Dictionary<Type, CoreTable>();
|
|
|
+ foreach (var childtype in childtypes)
|
|
|
+ {
|
|
|
+ var childtask = Task.Run(() =>
|
|
|
{
|
|
|
- codetask = Task.Run(() =>
|
|
|
- {
|
|
|
- var columns = Columns.None<TEntity>().Add(codefield);
|
|
|
- //columns.Add<String>(codefield);
|
|
|
- var filter = new Filter<TEntity>(codefield).BeginsWith(code);
|
|
|
- var table = new Client<TEntity>().Query(filter, columns);
|
|
|
- var result = table.Rows.Select(x => x.Get(codefield) as string).ToList();
|
|
|
- return result;
|
|
|
- });
|
|
|
- tasks.Add(codetask);
|
|
|
- }
|
|
|
- //codetask.Wait();
|
|
|
+ var prop = childtype.GetProperties().FirstOrDefault(x =>
|
|
|
+ x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) &&
|
|
|
+ x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(TEntity));
|
|
|
|
|
|
- var children = new Dictionary<Type, CoreTable>();
|
|
|
- foreach (var childtype in childtypes)
|
|
|
- {
|
|
|
- var childtask = Task.Run(() =>
|
|
|
+ if (prop is not null)
|
|
|
{
|
|
|
- var prop = childtype.GetProperties().FirstOrDefault(x =>
|
|
|
- x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink)) &&
|
|
|
- x.PropertyType.GetInheritedGenericTypeArguments().FirstOrDefault() == typeof(TEntity));
|
|
|
-
|
|
|
- if (prop is not null)
|
|
|
+ var filter = Core.Filter.Create(childtype);
|
|
|
+ filter.Expression = CoreUtils.GetMemberExpression(childtype, prop.Name + ".ID");
|
|
|
+ filter.Operator = Operator.IsEqualTo;
|
|
|
+ filter.Value = id;
|
|
|
+ var sort = LookupFactory.DefineSort(childtype);
|
|
|
+ var client = ClientFactory.CreateClient(childtype);
|
|
|
+ var table = client.Query(filter, null, sort);
|
|
|
+ foreach (var r in table.Rows)
|
|
|
{
|
|
|
- var filter = Core.Filter.Create(childtype);
|
|
|
- filter.Expression = CoreUtils.GetMemberExpression(childtype, prop.Name + ".ID");
|
|
|
- filter.Operator = Operator.IsEqualTo;
|
|
|
- filter.Value = id;
|
|
|
- var sort = LookupFactory.DefineSort(childtype);
|
|
|
- var client = ClientFactory.CreateClient(childtype);
|
|
|
- var table = client.Query(filter, null, sort);
|
|
|
- foreach (var r in table.Rows)
|
|
|
- {
|
|
|
- r["ID"] = Guid.Empty;
|
|
|
- r[prop.Name + ".ID"] = Guid.Empty;
|
|
|
- }
|
|
|
-
|
|
|
- children[childtype] = table;
|
|
|
+ r["ID"] = Guid.Empty;
|
|
|
+ r[prop.Name + ".ID"] = Guid.Empty;
|
|
|
}
|
|
|
- else
|
|
|
- {
|
|
|
- Logger.Send(LogType.Error, "", $"DynamicDataGrid<{typeof(TEntity)}>.Duplicate(): No parent property found for child type {childtype}");
|
|
|
- }
|
|
|
- });
|
|
|
- tasks.Add(childtask);
|
|
|
- //childtask.Wait();
|
|
|
- }
|
|
|
|
|
|
- //var manytomanys = CoreUtils.TypeList(
|
|
|
- // AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
- // x => x.GetInterfaces().Any(intf => intf.IsGenericType && intf.GetGenericTypeDefinition() == typeof(IManyToMany<,>) && intf.GenericTypeArguments.Contains(typeof(T)))
|
|
|
- //);
|
|
|
-
|
|
|
- //Task<CoreTable> childtask = Task.Run(() =>
|
|
|
- //{
|
|
|
- // var result = new CoreTable();
|
|
|
- // result.LoadColumns(typeof(TChild));
|
|
|
- // var children = new Client<TChild>().Load(new Filter<TChild>(x => linkfield).IsEqualTo(id));
|
|
|
- // foreach (var child in children)
|
|
|
- // {
|
|
|
- // child.ID = Guid.Empty;
|
|
|
- // String linkprop = CoreUtils.GetFullPropertyName<TChild, Guid>(linkfield, ".");
|
|
|
- // CoreUtils.SetPropertyValue(child, linkprop, Guid.Empty);
|
|
|
- // var newrow = result.NewRow();
|
|
|
- // result.LoadRow(newrow, child);
|
|
|
- // result.Rows.Add(newrow);
|
|
|
- // }
|
|
|
- // return result;
|
|
|
- //});
|
|
|
- //tasks.Add(childtask);
|
|
|
-
|
|
|
- Task.WaitAll(tasks.ToArray());
|
|
|
-
|
|
|
- var item = itemtask.Result;
|
|
|
- item.ID = Guid.Empty;
|
|
|
-
|
|
|
- if (codetask != null)
|
|
|
- {
|
|
|
- var codes = codetask.Result;
|
|
|
- var i = 1;
|
|
|
+ children[childtype] = table;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ Logger.Send(LogType.Error, "", $"DynamicDataGrid<{typeof(TEntity)}>.Duplicate(): No parent property found for child type {childtype}");
|
|
|
+ }
|
|
|
+ });
|
|
|
+ tasks.Add(childtask);
|
|
|
+ //childtask.Wait();
|
|
|
+ }
|
|
|
|
|
|
- while (codes.Contains(string.Format("{0} ({1})", code, i)))
|
|
|
- i++;
|
|
|
- var codeprop = CoreUtils.GetFullPropertyName(codefield, ".");
|
|
|
- CoreUtils.SetPropertyValue(item, codeprop, string.Format("{0} ({1})", code, i));
|
|
|
- }
|
|
|
+ //var manytomanys = CoreUtils.TypeList(
|
|
|
+ // AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
+ // x => x.GetInterfaces().Any(intf => intf.IsGenericType && intf.GetGenericTypeDefinition() == typeof(IManyToMany<,>) && intf.GenericTypeArguments.Contains(typeof(T)))
|
|
|
+ //);
|
|
|
|
|
|
- var grid = new DynamicDataGrid<TEntity>();
|
|
|
- return grid.EditItems(new[] { item }, t => children.ContainsKey(t) ? children[t] : null, true);
|
|
|
- }
|
|
|
+ //Task<CoreTable> childtask = Task.Run(() =>
|
|
|
+ //{
|
|
|
+ // var result = new CoreTable();
|
|
|
+ // result.LoadColumns(typeof(TChild));
|
|
|
+ // var children = new Client<TChild>().Load(new Filter<TChild>(x => linkfield).IsEqualTo(id));
|
|
|
+ // foreach (var child in children)
|
|
|
+ // {
|
|
|
+ // child.ID = Guid.Empty;
|
|
|
+ // String linkprop = CoreUtils.GetFullPropertyName<TChild, Guid>(linkfield, ".");
|
|
|
+ // CoreUtils.SetPropertyValue(child, linkprop, Guid.Empty);
|
|
|
+ // var newrow = result.NewRow();
|
|
|
+ // result.LoadRow(newrow, child);
|
|
|
+ // result.Rows.Add(newrow);
|
|
|
+ // }
|
|
|
+ // return result;
|
|
|
+ //});
|
|
|
+ //tasks.Add(childtask);
|
|
|
+
|
|
|
+ Task.WaitAll(tasks.ToArray());
|
|
|
+
|
|
|
+ var item = itemtask.Result;
|
|
|
+ item.ID = Guid.Empty;
|
|
|
+
|
|
|
+ if (codetask != null)
|
|
|
+ {
|
|
|
+ var codes = codetask.Result;
|
|
|
+ var i = 1;
|
|
|
+
|
|
|
+ while (codes.Contains(string.Format("{0} ({1})", code, i)))
|
|
|
+ i++;
|
|
|
+ var codeprop = CoreUtils.GetFullPropertyName(codefield, ".");
|
|
|
+ CoreUtils.SetPropertyValue(item, codeprop, string.Format("{0} ({1})", code, i));
|
|
|
+ }
|
|
|
+
|
|
|
+ var grid = new DynamicDataGrid<TEntity>();
|
|
|
+ return grid.EditItems(new[] { item }, t => children.ContainsKey(t) ? children[t] : null, true);
|
|
|
+ }
|
|
|
|
|
|
- private bool DoMerge(Button arg1, CoreRow[] arg2)
|
|
|
- {
|
|
|
- if (arg2 == null || arg2.Length <= 1)
|
|
|
- return false;
|
|
|
- var targetid = arg2.Last().Get<TEntity, Guid>(x => x.ID);
|
|
|
- var target = arg2.Last().ToObject<TEntity>().ToString();
|
|
|
- var otherids = arg2.Select(r => r.Get<TEntity, Guid>(x => x.ID)).Where(x => x != targetid).ToArray();
|
|
|
- string[] others = arg2.Where(r => otherids.Contains(r.Get<Guid>("ID"))).Select(x => x.ToObject<TEntity>().ToString()!).ToArray();
|
|
|
- var rows = arg2.Length;
|
|
|
- if (MessageBox.Show(
|
|
|
- string.Format(
|
|
|
- "This will merge the following items:\n\n- {0}\n\n into:\n\n- {1}\n\nAfter this, the items will be permanently removed.\nAre you sure you wish to do this?",
|
|
|
- string.Join("\n- ", others),
|
|
|
- target
|
|
|
- ),
|
|
|
- "Merge Items Warning",
|
|
|
- MessageBoxButton.YesNo,
|
|
|
- MessageBoxImage.Stop) != MessageBoxResult.Yes
|
|
|
- )
|
|
|
- return false;
|
|
|
-
|
|
|
- using (new WaitCursor())
|
|
|
+ private bool DoMerge(Button arg1, CoreRow[] arg2)
|
|
|
+ {
|
|
|
+ if (arg2 == null || arg2.Length <= 1)
|
|
|
+ return false;
|
|
|
+ var targetid = arg2.Last().Get<TEntity, Guid>(x => x.ID);
|
|
|
+ var target = arg2.Last().ToObject<TEntity>().ToString();
|
|
|
+ var otherids = arg2.Select(r => r.Get<TEntity, Guid>(x => x.ID)).Where(x => x != targetid).ToArray();
|
|
|
+ string[] others = arg2.Where(r => otherids.Contains(r.Get<Guid>("ID"))).Select(x => x.ToObject<TEntity>().ToString()!).ToArray();
|
|
|
+ var rows = arg2.Length;
|
|
|
+ if (MessageBox.Show(
|
|
|
+ string.Format(
|
|
|
+ "This will merge the following items:\n\n- {0}\n\n into:\n\n- {1}\n\nAfter this, the items will be permanently removed.\nAre you sure you wish to do this?",
|
|
|
+ string.Join("\n- ", others),
|
|
|
+ target
|
|
|
+ ),
|
|
|
+ "Merge Items Warning",
|
|
|
+ MessageBoxButton.YesNo,
|
|
|
+ MessageBoxImage.Stop) != MessageBoxResult.Yes
|
|
|
+ )
|
|
|
+ return false;
|
|
|
+
|
|
|
+ using (new WaitCursor())
|
|
|
+ {
|
|
|
+ var types = CoreUtils.TypeList(
|
|
|
+ AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
+ x =>
|
|
|
+ x.IsClass
|
|
|
+ && !x.IsAbstract
|
|
|
+ && !x.IsGenericType
|
|
|
+ && x.IsSubclassOf(typeof(Entity))
|
|
|
+ && !x.Equals(typeof(AuditTrail))
|
|
|
+ && !x.Equals(typeof(TEntity))
|
|
|
+ && x.GetCustomAttribute<AutoEntity>() == null
|
|
|
+ && x.HasInterface<IRemotable>()
|
|
|
+ && x.HasInterface<IPersistent>()
|
|
|
+ ).ToArray();
|
|
|
+
|
|
|
+ foreach (var type in types)
|
|
|
{
|
|
|
- var types = CoreUtils.TypeList(
|
|
|
- AppDomain.CurrentDomain.GetAssemblies(),
|
|
|
+ var props = CoreUtils.PropertyList(
|
|
|
+ type,
|
|
|
x =>
|
|
|
- x.IsClass
|
|
|
- && !x.IsAbstract
|
|
|
- && !x.IsGenericType
|
|
|
- && x.IsSubclassOf(typeof(Entity))
|
|
|
- && !x.Equals(typeof(AuditTrail))
|
|
|
- && !x.Equals(typeof(TEntity))
|
|
|
- && x.GetCustomAttribute<AutoEntity>() == null
|
|
|
- && x.HasInterface<IRemotable>()
|
|
|
- && x.HasInterface<IPersistent>()
|
|
|
- ).ToArray();
|
|
|
-
|
|
|
- foreach (var type in types)
|
|
|
+ x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
|
|
|
+ && x.PropertyType.GetInheritedGenericTypeArguments().Contains(typeof(TEntity))
|
|
|
+ );
|
|
|
+ foreach (var prop in props)
|
|
|
{
|
|
|
- var props = CoreUtils.PropertyList(
|
|
|
- type,
|
|
|
- x =>
|
|
|
- x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
|
|
|
- && x.PropertyType.GetInheritedGenericTypeArguments().Contains(typeof(TEntity))
|
|
|
- );
|
|
|
- foreach (var prop in props)
|
|
|
+ var propname = string.Format(prop.Name + ".ID");
|
|
|
+ var filter = Core.Filter.Create(type);
|
|
|
+ filter.Expression = CoreUtils.CreateMemberExpression(type, propname);
|
|
|
+ filter.Operator = Operator.InList;
|
|
|
+ filter.Value = otherids;
|
|
|
+ var columns = Columns.None(type)
|
|
|
+ .Add("ID")
|
|
|
+ .Add(propname);
|
|
|
+ var updates = ClientFactory.CreateClient(type).Query(filter, columns).Rows.Select(r => r.ToObject(type)).ToArray();
|
|
|
+ if (updates.Any())
|
|
|
{
|
|
|
- var propname = string.Format(prop.Name + ".ID");
|
|
|
- var filter = Core.Filter.Create(type);
|
|
|
- filter.Expression = CoreUtils.CreateMemberExpression(type, propname);
|
|
|
- filter.Operator = Operator.InList;
|
|
|
- filter.Value = otherids;
|
|
|
- var columns = Columns.Create(type)
|
|
|
- .Add("ID")
|
|
|
- .Add(propname);
|
|
|
- var updates = ClientFactory.CreateClient(type).Query(filter, columns).Rows.Select(r => r.ToObject(type)).ToArray();
|
|
|
- if (updates.Any())
|
|
|
- {
|
|
|
- foreach (var update in updates)
|
|
|
- CoreUtils.SetPropertyValue(update, propname, targetid);
|
|
|
- ClientFactory.CreateClient(type).Save(updates,
|
|
|
- string.Format("Merged {0} Records", typeof(TEntity).EntityName().Split('.').Last()));
|
|
|
- }
|
|
|
+ foreach (var update in updates)
|
|
|
+ CoreUtils.SetPropertyValue(update, propname, targetid);
|
|
|
+ ClientFactory.CreateClient(type).Save(updates,
|
|
|
+ string.Format("Merged {0} Records", typeof(TEntity).EntityName().Split('.').Last()));
|
|
|
}
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- var histories = new Client<AuditTrail>()
|
|
|
- .Query(
|
|
|
- new Filter<AuditTrail>(x => x.EntityID).InList(otherids),
|
|
|
- Columns.None<AuditTrail>()
|
|
|
- .Add(x => x.ID).Add(x => x.EntityID))
|
|
|
- .ToArray<AuditTrail>();
|
|
|
- foreach (var history in histories)
|
|
|
- history.EntityID = targetid;
|
|
|
- if (histories.Length != 0)
|
|
|
- new Client<AuditTrail>().Save(histories, "");
|
|
|
-
|
|
|
- var deletes = new List<object>();
|
|
|
- foreach (var otherid in otherids)
|
|
|
- {
|
|
|
- var delete = new TEntity();
|
|
|
- CoreUtils.SetPropertyValue(delete, "ID", otherid);
|
|
|
- deletes.Add(delete);
|
|
|
- }
|
|
|
-
|
|
|
- ClientFactory.CreateClient(typeof(TEntity))
|
|
|
- .Delete(deletes, string.Format("Merged {0} Records", typeof(TEntity).EntityName().Split('.').Last()));
|
|
|
- return true;
|
|
|
+ var histories = new Client<AuditTrail>()
|
|
|
+ .Query(
|
|
|
+ new Filter<AuditTrail>(x => x.EntityID).InList(otherids),
|
|
|
+ Columns.None<AuditTrail>()
|
|
|
+ .Add(x => x.ID).Add(x => x.EntityID))
|
|
|
+ .ToArray<AuditTrail>();
|
|
|
+ foreach (var history in histories)
|
|
|
+ history.EntityID = targetid;
|
|
|
+ if (histories.Length != 0)
|
|
|
+ new Client<AuditTrail>().Save(histories, "");
|
|
|
+
|
|
|
+ var deletes = new List<object>();
|
|
|
+ foreach (var otherid in otherids)
|
|
|
+ {
|
|
|
+ var delete = new TEntity();
|
|
|
+ CoreUtils.SetPropertyValue(delete, "ID", otherid);
|
|
|
+ deletes.Add(delete);
|
|
|
}
|
|
|
+
|
|
|
+ ClientFactory.CreateClient(typeof(TEntity))
|
|
|
+ .Delete(deletes, string.Format("Merged {0} Records", typeof(TEntity).EntityName().Split('.').Last()));
|
|
|
+ return true;
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- protected override IEnumerable<TEntity> LoadDuplicatorItems(CoreRow[] rows)
|
|
|
+ protected override IEnumerable<TEntity> LoadDuplicatorItems(CoreRow[] rows)
|
|
|
+ {
|
|
|
+ return rows.Select(x => x.ToObject<TEntity>());
|
|
|
+ }
|
|
|
+
|
|
|
+ protected override bool BeforePaste(IEnumerable<TEntity> items, ClipAction action)
|
|
|
+ {
|
|
|
+ if (action == ClipAction.Copy)
|
|
|
{
|
|
|
- return rows.Select(x => x.ToObject<TEntity>());
|
|
|
+ foreach (var item in items)
|
|
|
+ item.ID = Guid.Empty;
|
|
|
+ return true;
|
|
|
}
|
|
|
|
|
|
- protected override bool BeforePaste(IEnumerable<TEntity> items, ClipAction action)
|
|
|
- {
|
|
|
- if (action == ClipAction.Copy)
|
|
|
- {
|
|
|
- foreach (var item in items)
|
|
|
- item.ID = Guid.Empty;
|
|
|
- return true;
|
|
|
- }
|
|
|
+ return base.BeforePaste(items, action);
|
|
|
+ }
|
|
|
|
|
|
- return base.BeforePaste(items, action);
|
|
|
- }
|
|
|
+ protected override void CustomiseExportFilters(Filters<TEntity> filters, CoreRow[] visiblerows)
|
|
|
+ {
|
|
|
+ base.CustomiseExportFilters(filters, visiblerows);
|
|
|
|
|
|
- protected override void CustomiseExportFilters(Filters<TEntity> filters, CoreRow[] visiblerows)
|
|
|
+ /*if (IsEntity)
|
|
|
+ {
|
|
|
+ var ids = visiblerows.Select(r => r.Get<TEntity, Guid>(c => c.ID)).ToArray();
|
|
|
+ filters.Add(new Filter<TEntity>(x => x.ID).InList(ids));
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- base.CustomiseExportFilters(filters, visiblerows);
|
|
|
+ Filter<TEntity>? filter = null;
|
|
|
|
|
|
- /*if (IsEntity)
|
|
|
- {
|
|
|
- var ids = visiblerows.Select(r => r.Get<TEntity, Guid>(c => c.ID)).ToArray();
|
|
|
- filters.Add(new Filter<TEntity>(x => x.ID).InList(ids));
|
|
|
- }
|
|
|
- else
|
|
|
+ foreach (var row in visiblerows)
|
|
|
{
|
|
|
- Filter<TEntity>? filter = null;
|
|
|
-
|
|
|
- foreach (var row in visiblerows)
|
|
|
+ var rowFilter = GetRowFilter(row);
|
|
|
+ if(rowFilter is not null)
|
|
|
{
|
|
|
- var rowFilter = GetRowFilter(row);
|
|
|
- if(rowFilter is not null)
|
|
|
+ if (filter is null)
|
|
|
+ {
|
|
|
+ filter = rowFilter;
|
|
|
+ }
|
|
|
+ else
|
|
|
{
|
|
|
- if (filter is null)
|
|
|
- {
|
|
|
- filter = rowFilter;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- filter.Or(rowFilter);
|
|
|
- }
|
|
|
+ filter.Or(rowFilter);
|
|
|
}
|
|
|
}
|
|
|
- filters.Add(filter);
|
|
|
- }*/
|
|
|
- }
|
|
|
+ }
|
|
|
+ filters.Add(filter);
|
|
|
+ }*/
|
|
|
+ }
|
|
|
|
|
|
- protected override IEnumerable<Tuple<Type?, CoreTable>> LoadExportTables(Filters<TEntity> filter, IEnumerable<Tuple<Type, IColumns>> tableColumns)
|
|
|
+ protected override IEnumerable<Tuple<Type?, CoreTable>> LoadExportTables(Filters<TEntity> filter, IEnumerable<Tuple<Type, IColumns>> tableColumns)
|
|
|
+ {
|
|
|
+ var queries = new Dictionary<string, IQueryDef>();
|
|
|
+ var columns = tableColumns.ToList();
|
|
|
+ foreach (var table in columns)
|
|
|
{
|
|
|
- var queries = new Dictionary<string, IQueryDef>();
|
|
|
- var columns = tableColumns.ToList();
|
|
|
- foreach (var table in columns)
|
|
|
- {
|
|
|
- var tableType = table.Item1;
|
|
|
+ var tableType = table.Item1;
|
|
|
|
|
|
- PropertyInfo? property = null;
|
|
|
+ PropertyInfo? property = null;
|
|
|
|
|
|
- var m2m = CoreUtils.GetManyToMany(tableType, typeof(TEntity));
|
|
|
+ var m2m = CoreUtils.GetManyToMany(tableType, typeof(TEntity));
|
|
|
|
|
|
- IFilter? queryFilter = null;
|
|
|
- if (m2m != null)
|
|
|
- {
|
|
|
- property = CoreUtils.GetManyToManyThisProperty(tableType, typeof(TEntity));
|
|
|
- }
|
|
|
- else
|
|
|
+ IFilter? queryFilter = null;
|
|
|
+ if (m2m != null)
|
|
|
+ {
|
|
|
+ property = CoreUtils.GetManyToManyThisProperty(tableType, typeof(TEntity));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ var o2m = CoreUtils.GetOneToMany(tableType, typeof(TEntity));
|
|
|
+ if (o2m != null)
|
|
|
{
|
|
|
- var o2m = CoreUtils.GetOneToMany(tableType, typeof(TEntity));
|
|
|
- if (o2m != null)
|
|
|
- {
|
|
|
- property = CoreUtils.GetOneToManyProperty(tableType, typeof(TEntity));
|
|
|
- }
|
|
|
+ property = CoreUtils.GetOneToManyProperty(tableType, typeof(TEntity));
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- if (property != null)
|
|
|
- {
|
|
|
- var subQuery = new SubQuery<TEntity>();
|
|
|
- subQuery.Filter = filter.Combine();
|
|
|
- subQuery.Column = new Column<TEntity>(x => x.ID);
|
|
|
+ if (property != null)
|
|
|
+ {
|
|
|
+ var subQuery = new SubQuery<TEntity>();
|
|
|
+ subQuery.Filter = filter.Combine();
|
|
|
+ subQuery.Column = new Column<TEntity>(x => x.ID);
|
|
|
|
|
|
- queryFilter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(tableType)) as IFilter)!;
|
|
|
- queryFilter.Expression = CoreUtils.GetMemberExpression(tableType, property.Name + ".ID");
|
|
|
- queryFilter.InQuery(subQuery);
|
|
|
+ queryFilter = (Activator.CreateInstance(typeof(Filter<>).MakeGenericType(tableType)) as IFilter)!;
|
|
|
+ queryFilter.Expression = CoreUtils.GetMemberExpression(tableType, property.Name + ".ID");
|
|
|
+ queryFilter.InQuery(subQuery);
|
|
|
|
|
|
- queries[tableType.Name] = new QueryDef(tableType)
|
|
|
- {
|
|
|
- Filter = queryFilter,
|
|
|
- Columns = table.Item2
|
|
|
- };
|
|
|
- }
|
|
|
+ queries[tableType.Name] = new QueryDef(tableType)
|
|
|
+ {
|
|
|
+ Filter = queryFilter,
|
|
|
+ Columns = table.Item2
|
|
|
+ };
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- var results = Client.QueryMultiple(queries);
|
|
|
+ var results = Client.QueryMultiple(queries);
|
|
|
|
|
|
- return columns.Select(x => new Tuple<Type?, CoreTable>(x.Item1, results[x.Item1.Name]));
|
|
|
- }
|
|
|
+ return columns.Select(x => new Tuple<Type?, CoreTable>(x.Item1, results[x.Item1.Name]));
|
|
|
+ }
|
|
|
|
|
|
- protected override CoreTable LoadImportKeys(String[] fields)
|
|
|
- {
|
|
|
- return new Client<TEntity>().Query(null, new Columns<TEntity>(fields));
|
|
|
- }
|
|
|
-
|
|
|
+ protected override CoreTable LoadImportKeys(String[] fields)
|
|
|
+ {
|
|
|
+ return Client.Query(null, Columns.None<TEntity>().Add(fields));
|
|
|
}
|
|
|
+
|
|
|
}
|