public static FluentInclude <T> WithVirtualMListInitializeOnly <T, L>(this FluentInclude <T> fi, Func <T, MList <L> > getMList, Expression <Func <L, Lite <T> > > getBackReference, Action <L, T> onSave = null) where T : Entity where L : Entity { Action <L, Lite <T> > setter = null; var sb = fi.SchemaBuilder; sb.Schema.EntityEvents <T>().Saving += (T e) => { if (GraphExplorer.IsGraphModified(getMList(e))) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { var mlist = getMList(e); if (!GraphExplorer.IsGraphModified(mlist)) { return; } if (setter == null) { setter = CreateSetter(getBackReference); } mlist.ForEach(line => setter(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } mlist.SetCleanModified(false); }; return(fi); }
public virtual void UpdateUser(UserEntity user, IAutoCreateUserContext ctx) { if (this.GetConfig().AutoUpdateUsers == false) { return; } UpdateUserInternal(user, ctx); if (GraphExplorer.IsGraphModified(user)) { using (AuthLogic.Disable()) using (OperationLogic.AllowSave <UserEntity>()) { user.Save(); } } }
public static FluentInclude <T> WithVirtualMList <T, L>(this FluentInclude <T> fi, Expression <Func <T, MList <L> > > mListField, Expression <Func <L, Lite <T>?> > backReference, Action <L, T>?onSave = null, Action <L, T>?onRemove = null, bool?lazyRetrieve = null, bool?lazyDelete = null) //To avoid StackOverflows where T : Entity where L : Entity { fi.SchemaBuilder.Include <L>(); var mListPropertRoute = PropertyRoute.Construct(mListField); var backReferenceRoute = PropertyRoute.Construct(backReference, avoidLastCasting: true); if (fi.SchemaBuilder.Settings.FieldAttribute <IgnoreAttribute>(mListPropertRoute) == null) { throw new InvalidOperationException($"The property {mListPropertRoute} should have an IgnoreAttribute to be used as Virtual MList"); } RegisteredVirtualMLists.GetOrCreate(typeof(T)).Add(mListPropertRoute, new VirtualMListInfo(mListPropertRoute, backReferenceRoute)); var defLazyRetrieve = lazyRetrieve ?? (typeof(L) == typeof(T)); var defLazyDelete = lazyDelete ?? (typeof(L) == typeof(T)); Func <T, MList <L> > getMList = GetAccessor(mListField); Action <L, Lite <T> >?setter = null; bool preserveOrder = fi.SchemaBuilder.Settings.FieldAttributes(mListPropertRoute) ! .OfType <PreserveOrderAttribute>() .Any(); if (preserveOrder && !typeof(ICanBeOrdered).IsAssignableFrom(typeof(L))) { throw new InvalidOperationException($"'{typeof(L).Name}' should implement '{nameof(ICanBeOrdered)}' because '{ReflectionTools.GetPropertyInfo(mListField).Name}' contains '[{nameof(PreserveOrderAttribute)}]'"); } var sb = fi.SchemaBuilder; if (defLazyRetrieve) { sb.Schema.EntityEvents <T>().Retrieved += (T e, PostRetrievingContext ctx) => { if (ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } var query = Database.Query <L>() .Where(line => backReference.Evaluate(line) == e.ToLite()); MList <L> newList = preserveOrder ? query.ToVirtualMListWithOrder() : query.ToVirtualMList(); mlist.AssignAndPostRetrieving(newList, ctx); }; } if (preserveOrder) { sb.Schema.EntityEvents <T>().RegisterBinding <MList <L> >(mListField, shouldSet: () => !defLazyRetrieve && !VirtualMList.ShouldAvoidMListType(typeof(L)), valueExpression: (e, rowId) => Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMListWithOrder(), valueFunction: (e, rowId, retriever) => Schema.Current.CacheController <L>() !.Enabled ? Schema.Current.CacheController <L>() !.RequestByBackReference <T>(retriever, backReference, e.ToLite()).ToVirtualMListWithOrder(): Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMListWithOrder() ); } else { sb.Schema.EntityEvents <T>().RegisterBinding(mListField, shouldSet: () => !defLazyRetrieve && !VirtualMList.ShouldAvoidMListType(typeof(L)), valueExpression: (e, rowId) => Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMList(), valueFunction: (e, rowId, retriever) => Schema.Current.CacheController <L>() !.Enabled ? Schema.Current.CacheController <L>() !.RequestByBackReference <T>(retriever, backReference, e.ToLite()).ToVirtualMList() : Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMList() ); } sb.Schema.EntityEvents <T>().PreSaving += (T e, PreSavingContext ctx) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } if (mlist.Count > 0) { var graph = Saver.PreSaving(() => GraphExplorer.FromRoot(mlist).RemoveAllNodes(ctx.Graph)); GraphExplorer.PropagateModifications(graph.Inverse()); var errors = GraphExplorer.FullIntegrityCheck(graph); if (errors != null) { #if DEBUG var withEntites = errors.WithEntities(graph); throw new IntegrityCheckException(withEntites); #else throw new IntegrityCheckException(errors); #endif } } if (mlist.IsGraphModified) { e.SetSelfModified(); } }; sb.Schema.EntityEvents <T>().Saving += (T e) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } if (preserveOrder) { mlist.ForEach((o, i) => ((ICanBeOrdered)o).Order = i); } if (GraphExplorer.IsGraphModified(mlist)) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist != null && !GraphExplorer.IsGraphModified(mlist)) { return; } if (!(args.WasNew || ShouldConsiderNew(typeof(T)))) { var oldElements = mlist.EmptyIfNull().Where(line => !line.IsNew); var query = Database.Query <L>() .Where(p => backReference.Evaluate(p) == e.ToLite()); if (onRemove == null) { query.Where(p => !oldElements.Contains(p)).UnsafeDelete(); } else { query.Where(p => !oldElements.Contains(p)).ToList().ForEach(line => onRemove !(line, e)); } } if (mlist != null) { if (mlist.Any()) { if (setter == null) { setter = CreateSetter(backReference); } mlist.ForEach(line => setter !(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave !(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } } mlist.SetCleanModified(false); } }; sb.Schema.EntityEvents <T>().PreUnsafeDelete += query => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return(null); } //You can do a VirtualMList to itself at the table level, but there should not be cycles inside the instances var toDelete = Database.Query <L>().Where(se => query.Any(e => backReference.Evaluate(se).Is(e))); if (defLazyDelete) { if (toDelete.Any()) { toDelete.UnsafeDelete(); } } else { toDelete.UnsafeDelete(); } return(null); }; return(fi); }
public static FluentInclude <T> WithVirtualMListInitializeOnly <T, L>(this FluentInclude <T> fi, Expression <Func <T, MList <L> > > mListField, Expression <Func <L, Lite <T>?> > backReference, Action <L, T>?onSave = null) where T : Entity where L : Entity { fi.SchemaBuilder.Include <L>(); Func <T, MList <L> > getMList = GetAccessor(mListField); Action <L, Lite <T> >?setter = null; var sb = fi.SchemaBuilder; sb.Schema.EntityEvents <T>().RegisterBinding(mListField, shouldSet: () => false, valueExpression: (e, rowId) => Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMListWithOrder() ); sb.Schema.EntityEvents <T>().Saving += (T e) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } if (GraphExplorer.IsGraphModified(getMList(e))) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } if (!GraphExplorer.IsGraphModified(mlist)) { return; } if (setter == null) { setter = CreateSetter(backReference); } mlist.ForEach(line => setter !(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave !(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } mlist.SetCleanModified(false); }; return(fi); }
public static void Start(SchemaBuilder sb, DynamicQueryManager dqm) { if (sb.NotDefined(MethodInfo.GetCurrentMethod())) { var ib = sb.Schema.Settings.FieldAttribute <ImplementedByAttribute>(PropertyRoute.Construct((ScheduledTaskEntity e) => e.Rule)); sb.Schema.Settings.FieldAttributes((WorkflowEventTaskModel a) => a.Rule).Replace(new ImplementedByAttribute(ib.ImplementedTypes)); sb.Include <WorkflowEventTaskEntity>() .WithDelete(WorkflowEventTaskOperation.Delete) .WithQuery(dqm, () => e => new { Entity = e, e.Id, e.Workflow, e.TriggeredOn, e.Event, }); new Graph <WorkflowEventTaskEntity> .Execute(WorkflowEventTaskOperation.Save) { AllowsNew = true, Lite = false, Execute = (e, _) => { if (e.TriggeredOn == TriggeredOn.Always) { e.Condition = null; } e.Save(); }, } .Register(); sb.Schema.EntityEvents <WorkflowEventTaskEntity>().PreUnsafeDelete += tasks => tasks.SelectMany(a => a.ConditionResults()).UnsafeDelete(); ExceptionLogic.DeleteLogs += ExceptionLogic_DeleteLogs; sb.Include <WorkflowEventTaskConditionResultEntity>() .WithQuery(dqm, () => e => new { Entity = e, e.Id, e.CreationDate, e.WorkflowEventTask, e.Result, }); SchedulerLogic.ExecuteTask.Register((WorkflowEventTaskEntity wet, ScheduledTaskContext ctx) => ExecuteTask(wet)); sb.AddIndex((WorkflowEventTaskConditionResultEntity e) => e.CreationDate); WorkflowEventTaskModel.GetModel = (@event) => { if ([email protected]()) { return(null); } var schedule = @event.ScheduledTask(); var task = (schedule?.Task as WorkflowEventTaskEntity); var triggeredOn = task?.TriggeredOn ?? TriggeredOn.Always; return(new WorkflowEventTaskModel { Suspended = schedule?.Suspended ?? true, Rule = schedule?.Rule, TriggeredOn = triggeredOn, Condition = triggeredOn == TriggeredOn.Always ? null : new WorkflowEventTaskConditionEval() { Script = task.Condition.Script }, Action = new WorkflowEventTaskActionEval() { Script = task?.Action.Script ?? "" } }); }; WorkflowEventTaskModel.ApplyModel = (@event, model) => { var schedule = @event.IsNew ? null : @event.ScheduledTask(); if ([email protected]()) { if (schedule != null) { DeleteWorkflowEventScheduledTask(schedule); } return; } if (schedule != null) { var task = (schedule.Task as WorkflowEventTaskEntity); schedule.Suspended = model.Suspended; if (!object.ReferenceEquals(schedule.Rule, model.Rule)) { schedule.Rule = null; schedule.Rule = model.Rule; } task.TriggeredOn = model.TriggeredOn; if (model.TriggeredOn == TriggeredOn.Always) { task.Condition = null; } else { if (task.Condition == null) { task.Condition = new WorkflowEventTaskConditionEval(); } task.Condition.Script = model.Condition.Script; }; task.Action.Script = model.Action.Script; if (GraphExplorer.IsGraphModified(schedule)) { task.Execute(WorkflowEventTaskOperation.Save); schedule.Execute(ScheduledTaskOperation.Save); } } else { var newTask = new WorkflowEventTaskEntity() { Workflow = @event.Lane.Pool.Workflow.ToLite(), Event = @event.ToLite(), TriggeredOn = model.TriggeredOn, Condition = model.TriggeredOn == TriggeredOn.Always ? null : new WorkflowEventTaskConditionEval() { Script = model.Condition.Script }, Action = new WorkflowEventTaskActionEval() { Script = model.Action.Script }, }.Execute(WorkflowEventTaskOperation.Save); schedule = new ScheduledTaskEntity() { Suspended = model.Suspended, Rule = model.Rule, Task = newTask, User = AuthLogic.SystemUser.ToLite(), }.Execute(ScheduledTaskOperation.Save); } }; } }
public static FluentInclude <T> WithVirtualMList <T, L>(this FluentInclude <T> fi, Expression <Func <T, MList <L> > > mListField, Expression <Func <L, Lite <T> > > backReference, Action <L, T> onSave = null, Action <L, T> onRemove = null, bool?lazyRetrieveAndDelete = null) //To avoid StackOverflows where T : Entity where L : Entity { RegisteredVirtualMLists.GetOrCreate(typeof(T)).Add(typeof(L)); var lazy = lazyRetrieveAndDelete ?? (typeof(L) == typeof(T)); Func <T, MList <L> > getMList = GetAccessor(mListField); Action <L, Lite <T> > setter = null; bool preserveOrder = fi.SchemaBuilder.Settings.FieldAttributes(mListField) .OfType <PreserveOrderAttribute>() .Any(); if (preserveOrder && !typeof(ICanBeOrdered).IsAssignableFrom(typeof(L))) { throw new InvalidOperationException($"'{typeof(L).Name}' should implement '{nameof(ICanBeOrdered)}' because '{ReflectionTools.GetPropertyInfo(mListField).Name}' contains '[{nameof(PreserveOrderAttribute)}]'"); } var sb = fi.SchemaBuilder; if (lazy) { sb.Schema.EntityEvents <T>().Retrieved += (T e) => { if (ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } var query = Database.Query <L>() .Where(line => backReference.Evaluate(line) == e.ToLite()); MList <L> newList = preserveOrder ? query.ToVirtualMListWithOrder() : query.ToVirtualMList(); mlist.AssignAndPostRetrieving(newList); }; } if (preserveOrder) { sb.Schema.EntityEvents <T>().RegisterBinding <MList <L> >(mListField, shouldSet: () => !lazy && !VirtualMList.ShouldAvoidMListType(typeof(L)), valueExpression: e => Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMListWithOrder(), valueFunction: (e, retriever) => Schema.Current.CacheController <L>().RequestByBackReference <T>(retriever, backReference, e.ToLite()).ToVirtualMListWithOrder() ); } else { sb.Schema.EntityEvents <T>().RegisterBinding(mListField, shouldSet: () => !lazy && !VirtualMList.ShouldAvoidMListType(typeof(L)), valueExpression: e => Database.Query <L>().Where(line => backReference.Evaluate(line) == e.ToLite()).ExpandLite(line => backReference.Evaluate(line), ExpandLite.ToStringLazy).ToVirtualMList(), valueFunction: (e, retriever) => Schema.Current.CacheController <L>().RequestByBackReference <T>(retriever, backReference, e.ToLite()).ToVirtualMList() ); } sb.Schema.EntityEvents <T>().Saving += (T e) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist == null) { return; } if (preserveOrder) { mlist.ForEach((o, i) => ((ICanBeOrdered)o).Order = i); } if (GraphExplorer.IsGraphModified(mlist)) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return; } var mlist = getMList(e); if (mlist != null && !GraphExplorer.IsGraphModified(mlist)) { return; } if (!(args.WasNew || ShouldConsiderNew(typeof(T)))) { var oldElements = mlist.EmptyIfNull().Where(line => !line.IsNew); var query = Database.Query <L>() .Where(p => backReference.Evaluate(p) == e.ToLite()); if (onRemove == null) { query.Where(p => !oldElements.Contains(p)).UnsafeDelete(); } else { query.ToList().ForEach(line => onRemove(line, e)); } } if (mlist != null) { if (setter == null) { setter = CreateSetter(backReference); } mlist.ForEach(line => setter(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } mlist.SetCleanModified(false); } }; sb.Schema.EntityEvents <T>().PreUnsafeDelete += query => { if (VirtualMList.ShouldAvoidMListType(typeof(L))) { return(null); } //You can do a VirtualMList to itself at the table level, but there should not be cycles inside the instances var toDelete = Database.Query <L>().Where(se => query.Any(e => backReference.Evaluate(se).RefersTo(e))); if (lazy) { if (toDelete.Any()) { toDelete.UnsafeDelete(); } } else { toDelete.UnsafeDelete(); } return(null); }; return(fi); }
public static FluentInclude <T> WithVirtualMList <T, L>(this FluentInclude <T> fi, Expression <Func <T, MList <L> > > mListField, Expression <Func <L, Lite <T> > > getBackReference, Action <L, T> onSave = null, Action <L, T> onRemove = null) where T : Entity where L : Entity { Func <T, MList <L> > getMList = mListField.Compile(); Action <L, Lite <T> > setter = null; bool preserveOrder = fi.SchemaBuilder.Settings.FieldAttributes(mListField) .OfType <PreserveOrderAttribute>() .Any(); var sb = fi.SchemaBuilder; sb.Schema.EntityEvents <T>().Retrieved += (T e) => { var mlist = getMList(e); List <L> list = Database.Query <L>() .Where(line => getBackReference.Evaluate(line) == e.ToLite()) .ToList(); if (preserveOrder) { list = list.OrderBy(le => ((ICanBeOrdered)le).Order).ToList(); } var rowIdElements = list .Select(line => new MList <L> .RowIdElement(line, line.Id, null)); ((IMListPrivate <L>)mlist).InnerList.AddRange(rowIdElements); }; sb.Schema.EntityEvents <T>().Saving += (T e) => { var mlist = getMList(e); if (preserveOrder) { mlist.ForEach((o, i) => ((ICanBeOrdered)o).Order = i); } if (GraphExplorer.IsGraphModified(mlist)) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { var mlist = getMList(e); if (!GraphExplorer.IsGraphModified(mlist)) { return; } if (!args.WasNew) { var oldElements = mlist.Where(line => !line.IsNew); var query = Database.Query <L>() .Where(p => getBackReference.Evaluate(p) == e.ToLite()); if (onRemove == null) { query.Where(p => !oldElements.Contains(p)).UnsafeDelete(); } else { query.ToList().ForEach(line => onRemove(line, e)); } } if (setter == null) { setter = CreateSetter(getBackReference); } mlist.ForEach(line => setter(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } mlist.SetCleanModified(false); }; sb.Schema.EntityEvents <T>().PreUnsafeDelete += query => query.SelectMany(e => Database.Query <L>().Where(se => getBackReference.Evaluate(se).RefersTo(e))).UnsafeDelete(); return(fi); }
public static FluentInclude <T> WithVirtualMList <T, L>(this FluentInclude <T> fi, Func <T, MList <L> > getMList, Expression <Func <L, Lite <T> > > getBackReference, Action <L, T> onSave = null, Action <L, T> onRemove = null) where T : Entity where L : Entity { Action <L, Lite <T> > setter = null; var sb = fi.SchemaBuilder; sb.Schema.EntityEvents <T>().Retrieved += (T e) => { var mlist = getMList(e); var rowIdElements = Database.Query <L>() .Where(line => getBackReference.Evaluate(line) == e.ToLite()) .ToList() .Select(line => new MList <L> .RowIdElement(line, line.Id, null)); ((IMListPrivate <L>)mlist).InnerList.AddRange(rowIdElements); }; sb.Schema.EntityEvents <T>().Saving += (T e) => { if (GraphExplorer.IsGraphModified(getMList(e))) { e.SetModified(); } }; sb.Schema.EntityEvents <T>().Saved += (T e, SavedEventArgs args) => { var mlist = getMList(e); if (!GraphExplorer.IsGraphModified(mlist)) { return; } if (!args.WasNew) { var oldElements = mlist.Where(line => !line.IsNew); var query = Database.Query <L>() .Where(p => getBackReference.Evaluate(p) == e.ToLite()); if (onRemove == null) { query.Where(p => !oldElements.Contains(p)).UnsafeDelete(); } else { query.ToList().ForEach(line => onRemove(line, e)); } } if (setter == null) { setter = CreateGetter(getBackReference); } mlist.ForEach(line => setter(line, e.ToLite())); if (onSave == null) { mlist.SaveList(); } else { mlist.ForEach(line => { if (GraphExplorer.IsGraphModified(line)) { onSave(line, e); } }); } var priv = (IMListPrivate)mlist; for (int i = 0; i < mlist.Count; i++) { if (priv.GetRowId(i) == null) { priv.SetRowId(i, mlist[i].Id); } } mlist.SetCleanModified(false); }; return(fi); }