|
@@ -24,8 +24,6 @@ public interface IDynamicDataGrid : IDynamicGrid
|
|
|
/// the name of <typeparamref name="TEntity"/> is used as a default.
|
|
|
/// </summary>
|
|
|
string? ColumnsTag { get; set; }
|
|
|
-
|
|
|
- IColumns LoadEditorColumns();
|
|
|
}
|
|
|
|
|
|
public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid where TEntity : Entity, IRemotable, IPersistent, new()
|
|
@@ -81,10 +79,10 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
|
|
|
MergeBtn = AddButton("Merge", Wpf.Resources.merge.AsBitmapImage(Color.White), DoMerge);
|
|
|
}
|
|
|
|
|
|
- protected override void SelectItems(CoreRow[]? rows)
|
|
|
+ public override void SelectItems(CoreRow[]? rows)
|
|
|
{
|
|
|
base.SelectItems(rows);
|
|
|
- MergeBtn.Visibility = Options.MultiSelect && typeof(T).IsAssignableTo(typeof(IMergeable)) && Security.CanMerge<TEntity>()
|
|
|
+ MergeBtn.Visibility = Options.MultiSelect && typeof(TEntity).IsAssignableTo(typeof(IMergeable)) && Security.CanMerge<TEntity>()
|
|
|
&& rows != null && rows.Length > 1
|
|
|
? Visibility.Visible
|
|
|
: Visibility.Collapsed;
|
|
@@ -139,20 +137,6 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
- private void AuditTrailClick(object sender, object? item)
|
|
|
- {
|
|
|
- var entity = (item as TEntity)!;
|
|
|
- var window = new AuditWindow(entity.ID);
|
|
|
- window.ShowDialog();
|
|
|
- }
|
|
|
-
|
|
|
protected override DynamicGridColumns LoadColumns()
|
|
|
{
|
|
|
return ColumnsComponent.LoadColumns();
|
|
@@ -199,121 +183,6 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
|
|
|
|
|
|
#region Duplicate
|
|
|
|
|
|
- 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 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();
|
|
|
-
|
|
|
- Task<List<string?>>? codetask = null;
|
|
|
- if (!string.IsNullOrWhiteSpace(code))
|
|
|
- {
|
|
|
- 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 children = new Dictionary<Type, CoreTable>();
|
|
|
- foreach (var childtype in childtypes)
|
|
|
- {
|
|
|
- var childtask = Task.Run(() =>
|
|
|
- {
|
|
|
- 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)
|
|
|
- {
|
|
|
- r["ID"] = Guid.Empty;
|
|
|
- r[prop.Name + ".ID"] = Guid.Empty;
|
|
|
- }
|
|
|
-
|
|
|
- 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();
|
|
|
- }
|
|
|
-
|
|
|
- //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;
|
|
|
-
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
protected override IEnumerable<TEntity> LoadDuplicatorItems(CoreRow[] rows)
|
|
|
{
|
|
|
return rows.Select(x => x.ToObject<TEntity>());
|
|
@@ -321,162 +190,16 @@ public class DynamicDataGrid<TEntity> : DynamicGrid<TEntity>, IDynamicDataGrid w
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
- 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);
|
|
|
- }
|
|
|
-
|
|
|
- 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 tableType = table.Item1;
|
|
|
-
|
|
|
- PropertyInfo? property = null;
|
|
|
-
|
|
|
- var m2m = CoreUtils.GetManyToMany(tableType, typeof(TEntity));
|
|
|
-
|
|
|
- IFilter? queryFilter = null;
|
|
|
- if (m2m != null)
|
|
|
- {
|
|
|
- property = CoreUtils.GetManyToManyThisProperty(tableType, typeof(TEntity));
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- var o2m = CoreUtils.GetOneToMany(tableType, typeof(TEntity));
|
|
|
- if (o2m != null)
|
|
|
- {
|
|
|
- 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);
|
|
|
-
|
|
|
- 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
|
|
|
- };
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- var results = Client.QueryMultiple(queries);
|
|
|
-
|
|
|
- return columns.Select(x => new Tuple<Type?, CoreTable>(x.Item1, results[x.Item1.Name]));
|
|
|
- }
|
|
|
-
|
|
|
- protected override CoreTable LoadImportKeys(String[] fields)
|
|
|
- {
|
|
|
- return Client.Query(null, Columns.None<TEntity>().Add(fields));
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
#region Merge
|
|
|
|
|
|
private bool DoMerge(Button arg1, CoreRow[] arg2)
|
|
|
{
|
|
|
if (arg2 == null || arg2.Length <= 1)
|
|
|
return false;
|
|
|
- var targetid = arg2.Last().Get<T, Guid>(x => x.ID);
|
|
|
- var target = arg2.Last().ToObject<T>().ToString();
|
|
|
- var otherids = arg2.Select(r => r.Get<T, Guid>(x => x.ID)).Where(x => x != targetid).ToArray();
|
|
|
- string[] others = arg2.Where(r => otherids.Contains(r.Get<Guid>("ID"))).Select(x => x.ToObject<T>().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.Entities.Where(
|
|
|
- x =>
|
|
|
- x.IsClass
|
|
|
- && !x.IsGenericType
|
|
|
- && x.IsSubclassOf(typeof(Entity))
|
|
|
- && !x.Equals(typeof(AuditTrail))
|
|
|
- && !x.Equals(typeof(T))
|
|
|
- && x.GetCustomAttribute<AutoEntity>() == null
|
|
|
- && x.HasInterface<IRemotable>()
|
|
|
- && x.HasInterface<IPersistent>()
|
|
|
- ).ToArray();
|
|
|
-
|
|
|
- foreach (var type in types)
|
|
|
- {
|
|
|
- var props = CoreUtils.PropertyList(
|
|
|
- type,
|
|
|
- x =>
|
|
|
- x.PropertyType.GetInterfaces().Contains(typeof(IEntityLink))
|
|
|
- && x.PropertyType.GetInheritedGenericTypeArguments().Contains(typeof(T))
|
|
|
- );
|
|
|
- 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())
|
|
|
- {
|
|
|
- foreach (var update in updates)
|
|
|
- CoreUtils.SetPropertyValue(update, propname, targetid);
|
|
|
- ClientFactory.CreateClient(type).Save(updates,
|
|
|
- string.Format("Merged {0} Records", typeof(T).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 T();
|
|
|
- CoreUtils.SetPropertyValue(delete, "ID", otherid);
|
|
|
- deletes.Add(delete);
|
|
|
- }
|
|
|
-
|
|
|
- ClientFactory.CreateClient(typeof(T))
|
|
|
- .Delete(deletes, string.Format("Merged {0} Records", typeof(T).EntityName().Split('.').Last()));
|
|
|
- return true;
|
|
|
- }
|
|
|
+ var target = arg2.Last().ToObject<TEntity>();
|
|
|
+ return DynamicGridUtils.MergeEntities(
|
|
|
+ target,
|
|
|
+ arg2.ToObjects<TEntity>().Where(x => x.ID != target.ID).ToArray());
|
|
|
}
|
|
|
|
|
|
#endregion
|