/// <summary> /// This function permits to do a PROPAGATE action. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> public async Task PropagateAsync(SelectorInstance selectorInstance) { //try //{ // selectorInstance.Status = SelectorStateEnum.Propagate; // await SelectorInstanceDomain.Update(selectorInstance); // // Create each sub selector instances // Task<IEnumerable<SelectorInstance>> taskResult = SelectorInstanceDomain.CreateAllInstances(selectorInstance.WorkflowInstance); // await taskResult.ContinueWith(t => // { // if (t.IsCompleted) // { // foreach (SelectorInstance instance in t.Result) // { // //Init(instance).Start(); // } // } // }); // //selectorInstance.Status = SelectorStateEnum.Rest; // await SelectorInstanceDomain.Update(selectorInstance); // await Task.FromResult(0); //} //catch //{ // throw new SequenceException("Process.Selector.Propagate: Error while propagating."); //} }
/// <summary> /// This function permits to do a MODIFY action. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">Workflow instance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message</returns> public async Task <HttpResponseMessageResult> Modify(SelectorInstance selectorInstance, WorkflowInstance wfInstance, IEnumerable <KeyValuePair <long, double> > values) { // Mise à jour de la table ValueObject IEnumerable <long> idsUpdated = values.Select(v => v.Key); List <ValueObject> lstVO = await UnitOfWork.GetDbContext().ValueObject .Where(vo => idsUpdated.Contains(vo.Id)) .ToAsyncEnumerable() .ToList(); Dictionary <long, double> dicVO = values.ToDictionary(k => k.Key, v => v.Value); foreach (ValueObject vo in lstVO) { if (!dicVO.ContainsKey(vo.Id)) { continue; } UnitOfWork.ValueObjectRepository.PrepareUpdateForObject(vo); vo.FutureValue = dicVO[vo.Id]; } int nbr = await UnitOfWork.GetDbContext().SaveChangesAsync(); // Mise à jour de la table temporaire HttpResponseMessageResult res = await GridConfigurationDomain.SaveDataInTemporyTable(selectorInstance, selectorInstance.WorkflowInstance, values); return(res); }
/// <summary> /// Modifie les données d'un SelectorInstance. Les données sont d'abord sauvées, puis le SelectorInstance passe en Act et en Constraints. /// </summary> /// <param name="selectorInstanceId">Id du SelectorInstance</param> /// <param name="values">Valeurs à modifier</param> /// <remarks>Les valeurs à modifier sont au format suivant : {id de la cellule}:{nouvelle valeur}</remarks> /// <returns>Message à modifier</returns> public async Task <HttpResponseMessageResult> SaveData(long selectorInstanceId, IEnumerable <KeyValuePair <long, double> > values) { // Création de la transaction using (IDbContextTransaction transaction = UnitOfWork.GetDbContext().Database.BeginTransaction()) { SessionStatsHelper.HttpHitSaveDBTransaction(transaction, _serviceProvider); // Recherche du selectorInstance List <SelectorInstance> lstSelectInst = await UnitOfWork.GetDbContext().SelectorInstance .Where(si => si.Id == selectorInstanceId) .Include(si => si.SelectorConfig) .Include(si => si.WorkflowInstance) .ThenInclude(wfi => wfi.WorkflowConfig) .ToAsyncEnumerable() .ToList(); SelectorInstance selectorInstance = lstSelectInst.FirstOrDefault(); if (selectorInstance == null) { throw new WrongParameterException($"SelectorEngine.SaveData: bad SelectorInstance Id ({selectorInstanceId})."); } // On pousse les valeurs volatiles vers les futures valeurs. HttpResponseMessageResult res = await SelectorInstanceDomain.PushVolatileToFuture(selectorInstance); // Passage aux étapes suivantes UnitOfWork.SelectorInstanceRepository.PrepareUpdateForObject(selectorInstance); res.Append(await NextStep(selectorInstance, selectorInstance.WorkflowInstance, SelectorStateEnum.Init, values)); transaction.Commit(); return(res); } }
/// <summary> /// Déclenche le PrevPropagate sur l'ensemble des selectorInstances issus du SelectorConfig original. /// </summary> /// <param name="selectIns">SelectorInstance</param> /// <param name="wfInstance">Workflow instance</param> /// <returns>Message</returns> public async Task <HttpResponseMessageResult> PrevPropagate(SelectorInstance selectIns, WorkflowInstance wfInstance) { if ((selectIns == null) || (selectIns.SelectorConfig == null)) { throw new SequenceException("Process.SelectorInstance.PrevPropagate: SelectorInstance or SelectorInstance.SelectorConfig is null."); } SelectorConfig selectConf = selectIns.SelectorConfig; // S'il y a d'autres SelectorConfig en PrevPropagate, on les lance avant if (selectConf.PrevPropagateId > 0) { SelectorConfig prevSelectConf = await UnitOfWork.GetDbContext() .SelectorConfig .Include(sc => sc.Criterias) .ThenInclude(c => c.Dimension) .Where(sc => sc.Id == selectConf.PrevPropagateId) .AsNoTracking() .ToAsyncEnumerable() .FirstOrDefault(); if (prevSelectConf == null) { throw new SequenceException("Process.SelectorConfig.Init: Bad PrevPropagate Id."); } HttpResponseMessageResult prevRes = await GenerateSelectorsInstances(prevSelectConf, wfInstance, selectIns); return(prevRes); } return(await NextStep(selectIns, wfInstance)); }
/// <summary> /// Génére tous les SelectorInstance depuis les criteria donnés. /// </summary> /// <param name="selectConf">SelectorConfig cible</param> /// <param name="wfInstance">WorkflowInstance nouvellement démarré</param> /// <param name="parent">Eventuel SelectorInstance pouvant être à l'origine de la création de nouvelles instances</param> /// <returns>Message de résultat</returns> public async Task <HttpResponseMessageResult> GenerateSelectorsInstances(SelectorConfig selectConf, WorkflowInstance wfInstance, SelectorInstance parent = null) { if (selectConf == null) { throw new SequenceException("Process.SelectorConfig.Init: SelectorConfig are null."); } if (selectConf.Criterias == null) { throw new DataLoadingException("SelectorConfig : Criterias not loaded!"); } // WOR-174 - Créer en chaine les SelectorInstance selon la liste de Criterias... // On passe directement les criteria valorisés dans la requête de sélection... IEnumerable <IEnumerable <CriteriaValues> > lstCV = await CriteriaDomain.ExtractAllCriteriaValues(selectConf.Criterias, wfInstance); IEnumerable <IEnumerable <CriteriaValues> > lstCrit = await GetValueObjectsFromCriteria(lstCV, wfInstance.DataSetId); HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; foreach (IEnumerable <CriteriaValues> cvs in lstCrit) { SelectorInstance si = await SelectorInstanceDomain.Create(selectConf, cvs, parent, wfInstance); UnitOfWork.SelectorInstanceRepository.PrepareUpdateForObject(si); res.Append(await NextStep(si, wfInstance)); } return(res); }
/// <summary> /// This function permits to do a COMMIT action. /// </summary> /// <remarks> /// This method can to execute from the frontal /// </remarks> /// <param name="selectorInstance">SelectorInstance</param> public async Task Commit(SelectorInstance selectorInstance) { selectorInstance.Status = SelectorStateEnum.Commit; await SelectorInstanceDomain.Update(selectorInstance); await PropagateAsync(selectorInstance); }
/// <summary> /// Donne les colonnes et le nom de la table temporaire liée au SelectorInstance. /// </summary> /// <param name="selectorInstance">Instance du SelectorInstance</param> /// <param name="wfInstance">Instance du WorkflowInstance</param> /// <returns>Liste de string : en element 0, le nom de la table, puis suivent les noms des colones.</returns> public async Task <IEnumerable <string> > GetColumnsFromGridConfiguration(SelectorInstance selectorInstance, WorkflowInstance wfInstance) { if (selectorInstance == null) { throw new WrongParameterException("GridConfiguration.GetColumnsFromGridConfiguration : SelectorInstance is null!"); } if (wfInstance == null) { throw new WrongParameterException("GridConfiguration.GetColumnsFromGridConfiguration : WorkflowInstance is null!"); } if (wfInstance.WorkflowConfig == null) { throw new WrongParameterException("GridConfiguration.GetColumnsFromGridConfiguration : WorkflowInstance.WorkflowConfig is null!"); } // On récupére la configuration de l'opérateur List <GridConfig> lstGridConf = await UnitOfWork.GetDbContext().GridConfig .Include(gc => gc.ColumnDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.RowDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.FixedDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.WorkflowConfig) .Where(gc => gc.WorkflowConfig.Id == wfInstance.WorkflowConfig.Id) .AsNoTracking() .ToAsyncEnumerable() .ToList(); GridConfig gridConf = lstGridConf.FirstOrDefault(); IEnumerable <DistributionDimensionGrid> lstDistCols = GenerateDistribution(gridConf.ColumnDimensions); string nomTable = string.Format(Constant.TEMPLATE_TEMPORARY_TABLENAME, selectorInstance.Id.ToString()); List <string> nomsTableEtCols = new List <string>(); nomsTableEtCols.Add(nomTable); foreach (GridDimensionConfig fixes in gridConf.FixedDimensions.OrderBy(c => c.Order)) { string nomCol = $"Dim{((int)fixes.InternalName).ToString()}"; nomsTableEtCols.Add(nomCol); } foreach (GridDimensionConfig row in gridConf.RowDimensions.OrderBy(r => r.Order)) { string nomCol = $"Dim{((int)row.InternalName).ToString()}"; nomsTableEtCols.Add(nomCol); } foreach (DistributionDimensionGrid ddg in lstDistCols) { nomsTableEtCols.Add($"{ddg.ColumnName}_ID"); nomsTableEtCols.Add($"{ddg.ColumnName}_VAL"); } return(nomsTableEtCols); }
public async Task <HttpResponseMessageResult> Finish(SelectorInstance selectorInstance, WorkflowInstance wfInstance) { HttpResponseMessageResult res = new HttpResponseMessageResult(); if (selectorInstance.ParentSelectorInstanceId != 0) { // Construire l'appel pour passer en NoWait le parent. } return(res); }
/// <summary> /// Etabli l'étape Constraint. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">Workflow Instance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> Constraint(SelectorInstance selectorInstance, WorkflowInstance wfInstance, IEnumerable <KeyValuePair <long, double> > values) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; if (selectorInstance == null) { throw new WrongParameterException("SelectorEngine.Constraint : SelectorInstance is null."); } if (selectorInstance.SelectorConfig == null) { throw new DataLoadingException($"SelectorEngine.Constraint : SelectorConfig of SelectorInstance (Id = {selectorInstance.Id}) is null."); } if (wfInstance == null) { throw new WrongParameterException("SelectorEngine.Constraint : WorkflowInstance is null."); } if (wfInstance.WorkflowConfig == null) { throw new DataLoadingException($"SelectorEngine.Constraint : WorkflowConfig of WorkflowInstance (Id = {wfInstance.Id}) is null."); } long refSeq = -1; if (selectorInstance.SelectorConfig.ConstraintSequenceRef >= 0) { refSeq = selectorInstance.SelectorConfig.ConstraintSequenceRef; } else if (wfInstance.WorkflowConfig.ConstraintSequenceRef >= 0) { refSeq = wfInstance.WorkflowConfig.ConstraintSequenceRef; } if (refSeq >= 0) { List <ConstraintSequence> lstSeqConstraints = await UnitOfWork.GetDbContext().ConstraintSequence .Where(a => a.Reference == refSeq) .OrderBy(a => a.Order) .Include(a => a.Constraint) .AsNoTracking() .ToAsyncEnumerable() .ToList(); res.Append(await ConstraintSequenceDomain.CheckConstraintSequence(lstSeqConstraints, selectorInstance, wfInstance, values)); } return(res); }
/// <summary> /// Récupére la configuration d'une grid selon un SelectorInstance /// </summary> /// <param name="selectorInstanceId">Id du SelectorInstance</param> /// <returns>Configuration de la grid</returns> public async Task <GridConfig> GetBySelectorInstanceId(long selectorInstanceId) { List <SelectorInstance> lst = await UnitOfWork.GetDbContext().SelectorInstance .Where(si => si.Id == selectorInstanceId) .Include(si => si.WorkflowInstance) .ThenInclude(wi => wi.WorkflowConfig) .AsNoTracking() .ToAsyncEnumerable() .ToList(); if ((lst == null) || (lst.Count == 0)) { throw new WrongParameterException($"GridConfiguration.GetBySelectorInstanceId : Id SelectorInstance ({selectorInstanceId}) don't exist!"); } SelectorInstance selectorInstance = lst.FirstOrDefault(); if (selectorInstance == null) { throw new WrongParameterException("GridConfiguration.GetBySelectorInstanceId : SelectorInstance is null!"); } if (selectorInstance.WorkflowInstance == null) { throw new WrongParameterException("GridConfiguration.GetBySelectorInstanceId : SelectorInstance.WorkflowInstance is null!"); } if (selectorInstance.WorkflowInstance.WorkflowConfig == null) { throw new WrongParameterException("GridConfiguration.GetBySelectorInstanceId : SelectorInstance.WorkflowInstance.WorkflowConfig is null!"); } // On récupére la configuration de l'opérateur List <GridConfig> lstGridConf = await UnitOfWork.GetDbContext().GridConfig .Include(gc => gc.ColumnDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.RowDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.FixedDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.WorkflowConfig) .Where(gc => gc.WorkflowConfig.Id == selectorInstance.WorkflowInstance.WorkflowConfig.Id) .AsNoTracking() .ToAsyncEnumerable() .ToList(); GridConfig gridConf = lstGridConf.FirstOrDefault(); return(gridConf); }
/// <summary> /// Enregistre les valeurs modifiées dans la table temporaire correspondant au SelectorInstance donné. /// </summary> /// <param name="selectIns">SelectorInstance</param> /// <param name="wfInst">WorkflowInstance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> SaveDataInTemporyTable(SelectorInstance selectIns, WorkflowInstance wfInst, IEnumerable <KeyValuePair <long, double> > values) { // Transaction IDbContextTransaction transaction = SessionStatsHelper.HttpHitGetDBTransaction(_serviceProvider); if (transaction == null) { throw new DatabaseException("GridConfigurationDomain.SaveDataInTemporyTable: impossible to retrieve transaction connexion."); } IEnumerable <string> cols = await GetColumnsFromGridConfiguration(selectIns, wfInst); StringBuilder qryUpdate = new StringBuilder(); string nomTable = cols.ElementAt(0); // le 1er élément est le nom de la table temporaire qryUpdate.AppendLine($"UPDATE {nomTable}"); qryUpdate.AppendLine($"SET "); StringBuilder qryCase = new StringBuilder(); foreach (KeyValuePair <long, double> kvp in values) { qryCase.AppendLine($"WHEN {kvp.Key} THEN '{kvp.Value.ToString(CultureInfo.InvariantCulture)}'"); } foreach (string col in cols.Where(c => c.EndsWith("_ID"))) { string colVal = col.Substring(0, col.IndexOf("_ID")) + "_VAL"; qryUpdate.AppendLine($"{colVal} = "); qryUpdate.AppendLine($"CASE {col}"); qryUpdate.Append(qryCase); qryUpdate.AppendLine($"ELSE {colVal}"); qryUpdate.AppendLine("END,"); } // Nettoyage qryUpdate.SkipComma(); // Exécution de la requete de création de table temporaire. int nbrQry = await ExecSqlHelper.ExecuteNonQueryTransactionAsync(qryUpdate.ToString(), transaction); return(new HttpResponseMessageResult() { IsSuccess = nbrQry > 0 }); }
/// <summary> /// This function permits to update values from the workflow. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> public async Task UpdateFutureValues(SelectorInstance selectorInstance) { IEnumerable <ValueObject> valueObjects = await ValueObjectDomain.Get(); foreach (ValueObject valueObject in valueObjects.Where(s => s.SelectionInstance == selectorInstance)) { if (valueObject.Status == ValueObjectStatusEnum.Rest) { valueObject.Status = ValueObjectStatusEnum.Modify; valueObject.FutureValue = valueObject.CurrentValue; valueObject.CurrentValue = Convert.ToDouble(null); await ValueObjectDomain.Update(valueObject); } else { throw new SequenceException("Process.Selector.UpdateFutureValues: ValueObject (ID=" + valueObject.Id + ") is not in Rest state."); } } }
/// <summary> /// This function permits to do a VALIDATE action. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">Workflow Instance</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> Validate(SelectorInstance selectorInstance, WorkflowInstance wfInstance) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; return(res); //selectorInstance.Status = SelectorStateEnum.Valid; //await SelectorInstanceDomain.Update(selectorInstance); //IEnumerable<ValueObject> valueObjects = await ValueObjectDomain.Get(); //if (valueObjects.Any(s => s.SelectionInstance == selectorInstance //&& s.Status == ValueObjectStatusEnum.Locked)) //{ // await Commit(selectorInstance); //} //else //{ // //await StartModify(selectorInstance); //} }
/// <summary> /// Pour un SelectorInstance donné, passe à l'étape suivant dans le flux. /// </summary> /// <param name="selectIns">SelectorInstance sujet de la transition</param> /// <param name="wfInstance">Workflow instance</param> /// <returns>Message</returns> public async Task <HttpResponseMessageResult> NextStep(SelectorInstance selectIns, WorkflowInstance wfInstance, SelectorStateEnum scope = SelectorStateEnum.Void, IEnumerable <KeyValuePair <long, double> > values = null) { if (selectIns == null) { throw new SequenceException("Process.SelectorInstance.NextStep: SelectorInstance is null."); } HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; switch (selectIns.PreviousStatus) { case SelectorStateEnum.Create: if (selectIns.Status == SelectorStateEnum.Create) { selectIns.Status = SelectorStateEnum.PrevPropagate; res = await PrevPropagate(selectIns, wfInstance); selectIns.PreviousStatus = selectIns.Status; } if (selectIns.Status == SelectorStateEnum.PrevPropagate) { selectIns.Status = SelectorStateEnum.Init; res = await Init(selectIns, wfInstance); selectIns.PreviousStatus = SelectorStateEnum.Init; } break; case SelectorStateEnum.PrevPropagate: selectIns.Status = SelectorStateEnum.Init; res = await Init(selectIns, wfInstance); selectIns.PreviousStatus = SelectorStateEnum.Init; break; case SelectorStateEnum.Init: case SelectorStateEnum.Constraint: selectIns.Status = SelectorStateEnum.Modify; res = await Modify(selectIns, wfInstance, values); selectIns.PreviousStatus = SelectorStateEnum.Modify; selectIns.Status = SelectorStateEnum.Act; res.Append(await Act(selectIns, wfInstance, values)); selectIns.PreviousStatus = SelectorStateEnum.Act; selectIns.Status = SelectorStateEnum.Constraint; res.Append(await Constraint(selectIns, wfInstance, values)); selectIns.PreviousStatus = SelectorStateEnum.Constraint; selectIns.Status = SelectorStateEnum.Modify; if (scope == SelectorStateEnum.Validate) { selectIns.Status = SelectorStateEnum.Validate; res.Append(await Validate(selectIns, wfInstance)); selectIns.PreviousStatus = SelectorStateEnum.Validate; } break; case SelectorStateEnum.Modify: selectIns.Status = SelectorStateEnum.Act; res.Append(await Act(selectIns, wfInstance, values)); selectIns.PreviousStatus = SelectorStateEnum.Act; selectIns.Status = SelectorStateEnum.Constraint; res.Append(await Constraint(selectIns, wfInstance, values)); selectIns.PreviousStatus = SelectorStateEnum.Constraint; selectIns.Status = SelectorStateEnum.Modify; if (scope == SelectorStateEnum.Validate) { selectIns.Status = SelectorStateEnum.Validate; res.Append(await Validate(selectIns, wfInstance)); selectIns.PreviousStatus = SelectorStateEnum.Validate; } break; case SelectorStateEnum.Act: selectIns.Status = SelectorStateEnum.Constraint; res.Append(await Constraint(selectIns, wfInstance, values)); selectIns.PreviousStatus = SelectorStateEnum.Constraint; selectIns.Status = SelectorStateEnum.Modify; if (scope == SelectorStateEnum.Validate) { selectIns.Status = SelectorStateEnum.Validate; res.Append(await Validate(selectIns, wfInstance)); selectIns.PreviousStatus = SelectorStateEnum.Validate; } break; //... case SelectorStateEnum.Finish: selectIns.Status = SelectorStateEnum.Finish; res = await Finish(selectIns, wfInstance); selectIns.PreviousStatus = SelectorStateEnum.Finish; break; } // Afin de sauver les modifications d'états int nbr = await UnitOfWork.GetDbContext().SaveChangesAsync(); return(res); }
/// <summary> /// Permet de vérifier toutes les contraintes dans l'ordre d'une séquence de contraintes sur un SelectorInstance. /// </summary> /// <param name="sequences">Sequences de contraintes</param> /// <param name="selectorInstance">SelectorInstance cible</param> /// <param name="workflowInstance">WorkflowInstance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> CheckConstraint(Constraint contrainte, long referenceSequence, int ordreSequence, ConstraintLevelEnum level, SelectorInstance selectorInstance, WorkflowInstance workflowInstance, IEnumerable <KeyValuePair <long, double> > values) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; if (contrainte.Type == ConstraintTypeEnum.Hardcode) { if (contrainte.Name == Constant.CONSTRAINT_TREESUM) { return(await CheckTreeSum(referenceSequence, ordreSequence, level, selectorInstance, workflowInstance)); } //if (contrainte.Name == Constant.ACTION_SPLIT_COPY) // ; //if (contrainte.Name == Constant.ACTION_AGREGATE_PRIMEUM) // ; } if (contrainte.Type == ConstraintTypeEnum.Dynamic) { // TODO } return(res); }
private async Task <HttpResponseMessageResult> CheckTreeSum(long referenceSequence, int ordreSequence, ConstraintLevelEnum level, SelectorInstance selectorInstance, WorkflowInstance workflowInstance) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; await ConfigVariableDomain.LoadVariables(); string nomDimension = await GetConstraintParameter(referenceSequence, ordreSequence, Constant.PARAMETER_CONSTRAINT_ALIGNMENTNAME); Dictionary <long, Tuple <ValueObject, int, string, bool> > dicVo = await ValueObjectDomain.CreateDictionaryVO(nomDimension, selectorInstance); // Construction des arbres int topLvl = dicVo.Values.Select(t => t.Item2).Min(); int bottomLvl = dicVo.Values.Select(t => t.Item2).Max(); IEnumerable <TreeValueObject> lstTree = ValueObjectDomain.BuildTreeVO(dicVo, nomDimension, topLvl, bottomLvl); // On parcours les arbres et on vérifie les valeurs HashSet <long> idsAlreadyComputed = new HashSet <long>(); //Dictionary<long, Tuple<double, double>> outOfConstraint = new Dictionary<long, Tuple<double, double>>(); Dictionary <long, object> outOfConstraint = new Dictionary <long, object>(); foreach (TreeValueObject tvo in lstTree) { string format = await ValueObjectDomain.GetNumericalFormat(tvo.Node.TypeValue, workflowInstance.DataSetId); for (int currentLvl = bottomLvl; currentLvl > topLvl; currentLvl--) { IEnumerable <TreeValueObject> nodes = TreeValueObject.GetNodesFromLevel(tvo, currentLvl); foreach (TreeValueObject child in nodes) { if ((child.Parent == null) || idsAlreadyComputed.Contains(child.Parent.Node.Id)) { continue; } double sumComputed = child.Parent.Children.Select(subnode => ValueObjectDomain.GetMostCurrentValue(subnode.Node)).Sum(); double sumParent = ValueObjectDomain.GetMostCurrentValue(child.Parent.Node); if (!ValueObjectHelper.AlmostEqual(sumComputed, sumParent, format)) { outOfConstraint.Add(child.Parent.Node.Id, new { expected = sumParent, computed = sumComputed }); } idsAlreadyComputed.Add(child.Parent.Node.Id); } } } if (outOfConstraint.Count > 0) { res.Json = JsonConvert.SerializeObject(outOfConstraint); res.Message = "Some values are not sum of their children."; if ((level == ConstraintLevelEnum.Info) || (level == ConstraintLevelEnum.Warning)) { res.IsSuccess = true; } if (level == ConstraintLevelEnum.Error) { res.IsSuccess = false; } } return(res); }
/// <summary> /// Vérifie une contrainte sur un SelectorInstance. /// </summary> /// <param name="contrainte">Contrainte</param> /// <param name="referenceSequence">Reference de la sequence de contrainte</param> /// <param name="ordreSequence">Ordre de la contrainte dans la sequence</param> /// <param name="level">Niveau d'alerte si la vérification échoue</param> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="workflowInstance">WorkflowInstance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> CheckConstraintSequence(IEnumerable <ConstraintSequence> sequences, SelectorInstance selectorInstance, WorkflowInstance workflowInstance, IEnumerable <KeyValuePair <long, double> > values) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; foreach (ConstraintSequence seq in sequences.OrderBy(s => s.Order)) { if (seq.Constraint == null) { res.IsSuccess = false; res.Message = $"ConstraintSequenceDomaine.CheckConstraintSequence : Constraint is null for sequence {seq.SequenceName} of SelectorInstance {selectorInstance.Id}"; continue; } Logger.LogInformation($"Starting action {seq.Constraint.Name} of sequence {seq.SequenceName}."); res.Append(await CheckConstraint(seq.Constraint, seq.Reference, seq.Order, seq.Level, selectorInstance, workflowInstance, values)); } return(res); }
/// <summary> /// Permet d'exécuter toutes les actions, dans l'ordre, d'une séquence sur un SelectorInstance. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">WorkflowInstance</param> /// <param name="sequences">Sequence d'actions</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> ExecuteActionSequence(IEnumerable <ActionSequence> sequences, SelectorInstance selectorInstance, WorkflowInstance wfInstance, IEnumerable <KeyValuePair <long, double> > values) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; foreach (ActionSequence seq in sequences.OrderBy(s => s.Order)) { if (seq.Action == null) { res.IsSuccess = false; res.Message = $"ActionSequenceDomaine.ExecuteActionSequence : Action is null for sequence {seq.SequenceName} of SelectorInstance {selectorInstance.Id}"; continue; } Logger.LogInformation($"Starting action {seq.Action.Name} of sequence {seq.SequenceName}."); res.Append(await ExecuteAction(seq.Action, seq.Reference, seq.Order, selectorInstance, wfInstance, values)); } return(res); }
private async Task <HttpResponseMessageResult> ExecuteAggregatePrimeum(long referenceSequence, int OrderSequence, SelectorInstance selectorInstance, WorkflowInstance wfInstance) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; await ConfigVariableDomain.LoadVariables(); string nomDimension = await GetActionParameter(referenceSequence, OrderSequence, Constant.PARAMETER_ACTION_AGGREGATE_PRIMEUM_ALIGNMENTNAME); long idDimension = await GetIdDimensionTree(nomDimension, Constant.PARAMETER_ACTION_AGGREGATE_PRIMEUM_ALIGNMENTNAME, wfInstance); // niveau utiisateur CriteriaValues cvTree = await UnitOfWork.GetDbContext().CriteriaValues .Include(cv => cv.Criteria) .ThenInclude(c => c.Dimension) .Where(cv => cv.SelectorInstanceModifier != null && cv.SelectorInstanceModifier.Id == selectorInstance.Id && cv.Criteria.Dimension.Id == idDimension) .AsNoTracking() .FirstOrDefaultAsync(); string valueTopUser = cvTree?.Value; int levelTopUser = 0; if (!string.IsNullOrWhiteSpace(valueTopUser)) { levelTopUser = valueTopUser.Split(ConfigVariableDomain.AlignmentChar).Length; } Dictionary <long, Tuple <ValueObject, int, string, bool> > dicVo = await ValueObjectDomain.CreateDictionaryVO(nomDimension, selectorInstance); // Construction des arbres int topLvl = dicVo.Values.Select(t => t.Item2).Min(); int bottomLvl = dicVo.Values.Select(t => t.Item2).Max(); IEnumerable <TreeValueObject> lstTree = ValueObjectDomain.BuildTreeVO(dicVo, nomDimension, topLvl, bottomLvl); // On part du dernier niveau editable pour remonter jusqu'au niveau user. int bottom = dicVo.Values.Where(t => t.Item4).Select(t => t.Item2).Max(); HashSet <long> idsAlreadyComputed = new HashSet <long>(); HashSet <KeyValuePair <long, double> > modifiedValues = new HashSet <KeyValuePair <long, double> >(); foreach (TreeValueObject tvo in lstTree) { for (int currentLvl = bottom; currentLvl > levelTopUser; currentLvl--) { IEnumerable <TreeValueObject> nodes = TreeValueObject.GetNodesFromLevel(tvo, currentLvl); foreach (TreeValueObject child in nodes) { if ((child.Parent == null) || idsAlreadyComputed.Contains(child.Parent.Node.Id) || (child.Parent.Level <= levelTopUser)) { continue; } double sum = child.Parent.Children.Select(subnode => ValueObjectDomain.GetMostCurrentValue(subnode.Node)).Sum(); child.Parent.Node.FutureValue = sum; modifiedValues.Add(new KeyValuePair <long, double>(child.Parent.Node.Id, sum)); idsAlreadyComputed.Add(child.Parent.Node.Id); } } } // On sauve les modifications int nbr = await UnitOfWork.GetDbContext().SaveChangesAsync(); // Mise à jour de la table temporaire res.Append(await GridConfigurationDomain.SaveDataInTemporyTable(selectorInstance, wfInstance, modifiedValues)); return(res); }
/// <summary> /// Seconde méthode de répartition, par copie de valeur sur les noeuds inférieurs (typiquement pour des valeurs qui ne sont pas sommables). /// </summary> /// <param name="referenceSequence">Référence de la séquence d'action</param> /// <param name="OrderSequence">Numéro d'ordre de l'action dans la séquence</param> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">WorkflowInstance</param> /// <returns>Message de retour</returns> private async Task <HttpResponseMessageResult> ExecuteSplitCopy(long referenceSequence, int OrderSequence, SelectorInstance selectorInstance, WorkflowInstance wfInstance) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; // Récupération du nom de la dimension de la secto et du dictionnaire des objects. string nomDimension = await Split_GetDimensionName(referenceSequence, OrderSequence, wfInstance); Dictionary <long, Tuple <ValueObject, int, string, bool> > dicAllVo = await ValueObjectDomain.CreateDictionaryVO(nomDimension, selectorInstance); HashSet <KeyValuePair <long, double> > modifiedValues = new HashSet <KeyValuePair <long, double> >(); // On créé la queue pour parcourir l'arbre procéduralement. Queue <ValueObject> voToSplit = new Queue <ValueObject>(); foreach (ValueObject vo in dicAllVo.Values.Where(val => val.Item4).OrderBy(val => val.Item2).Select(val => val.Item1).ToList()) { voToSplit.Enqueue(vo); } // Parcours des noeuds while (voToSplit.Count > 0) { ValueObject node = voToSplit.Dequeue(); IEnumerable <ValueObject> children = GetChildren(node, nomDimension, dicAllVo); if ((children != null) && (children.Count() > 0)) { Split_CopyToOnChildren(node, children, voToSplit, dicAllVo, modifiedValues); } } // On sauve les modifications int nbr = await UnitOfWork.GetDbContext().SaveChangesAsync(); // Mise à jour de la table temporaire res.Append(await GridConfigurationDomain.SaveDataInTemporyTable(selectorInstance, wfInstance, modifiedValues)); return(res); }
/// <summary> /// Exécute une action sur un SelectorInstance /// </summary> /// <param name="action">Action</param> /// <param name="referenceSequence">Référence de la séquence d'action</param> /// <param name="OrderSequence">Numéro d'ordre de l'action dans la séquence</param> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">WorkflowInstance</param> /// <param name="values">Valeurs à modifier</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> ExecuteAction(ENT.Action action, long referenceSequence, int OrderSequence, SelectorInstance selectorInstance, WorkflowInstance wfInstance, IEnumerable <KeyValuePair <long, double> > values) { HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; if (action.Type == ActionTypeEnum.Hardcode) { if (action.Name == Constant.ACTION_SPLIT_PRIMEUM) { return(await ExecuteSplitPrimeum(referenceSequence, OrderSequence, selectorInstance, wfInstance)); } if (action.Name == Constant.ACTION_SPLIT_COPY) { return(await ExecuteSplitCopy(referenceSequence, OrderSequence, selectorInstance, wfInstance)); } if (action.Name == Constant.ACTION_AGREGATE_PRIMEUM) { return(await ExecuteAggregatePrimeum(referenceSequence, OrderSequence, selectorInstance, wfInstance)); } } if (action.Type == ActionTypeEnum.Dynamic) { // TODO } return(res); }
/// <summary> /// Créé un dictionnaire de ValueObject avec comme clé l'id des ValueObject et présente pour chacun un tuple contenant les infos sur une dimension arborescente. /// </summary> /// <param name="nomDimension">Nom de la dimension arborescente</param> /// <param name="selectorInstance">SelectorInstance déterminant le périmétre des ValueObject</param> /// <returns>Dictionnaire des ValueObject</returns> /// <remarks>Le tuple présente le ValueObject, le niveau sur l'arbre donné, la valeur du noeud de l'arbre et un flag permettant de savoir si le ValueObject est éditable ou non.</remarks> public async Task <Dictionary <long, Tuple <ValueObject, int, string, bool> > > CreateDictionaryVO(string nomDimension, SelectorInstance selectorInstance) { await ConfigVariableDomain.LoadVariables(); List <SelectorInstanceValueObject> lstSivoAll = await UnitOfWork.GetDbContext().SelectorInstanceValueObject .Include(sivo => sivo.ValueObject) .Where(sivo => sivo.SelectorInstanceId == selectorInstance.Id) .ToAsyncEnumerable() .ToList(); Dictionary <long, Tuple <ValueObject, int, string, bool> > dicAllVo = new Dictionary <long, Tuple <ValueObject, int, string, bool> >(); foreach (SelectorInstanceValueObject sivo in lstSivoAll) { if ((sivo.ValueObject == null) || (dicAllVo.ContainsKey(sivo.ValueObject.Id))) { continue; } UnitOfWork.ValueObjectRepository.PrepareUpdateForObject(sivo.ValueObject); string valNodeTree = GetValueByDimensionName(sivo.ValueObject, nomDimension); int level = valNodeTree.Split(ConfigVariableDomain.AlignmentChar).Length; bool isEditable = sivo.IsEditable; dicAllVo.Add(sivo.ValueObject.Id, Tuple.Create(sivo.ValueObject, level, valNodeTree, isEditable)); } return(dicAllVo); }
/// <summary> /// This function permits to do a INIT action. /// </summary> /// <param name="selectorInstance">SelectorInstance</param> /// <param name="wfInstance">Workflow instance</param> /// <returns>Message</returns> public async Task <HttpResponseMessageResult> Init(SelectorInstance selectorInstance, WorkflowInstance wfInstance) { if ((selectorInstance == null) || (wfInstance == null)) { throw new WrongParameterException("Process.SelectorInstance.Init: SelectorInstance or WorkflowInstance are null!"); } HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; // Sélection des données et enregistrement des liaisons (subset) ICollection <CriteriaValues> lstCv = selectorInstance.CriteriaValues; Dictionary <long, DataSetDimension> dimIds = await DataSetDimensionDomain.GetDimensionColumns(wfInstance.DataSetId); List <Expression <Func <ValueObject, bool> > > where = new List <Expression <Func <ValueObject, bool> > >(); res.Append(ValueObjectDomain.BuildFilterRequest(where, new List <IEnumerable <CriteriaValues> >() { lstCv }, dimIds, true)); IQueryable <ValueObject> dbQuery = UnitOfWork.GetDbContext().Set <ValueObject>(); // Vérification que le SelectorInstance n'utilise pas les données d'un autre SelectorInstance. int nbrLinkVoSi = await where .Aggregate(dbQuery, (current, predicate) => current.Where(predicate)) .Include(vo => vo.SelectorInstanceValueObject) .Where(vo => vo.SelectorInstanceValueObject.Count > 0) .AsNoTracking() .CountAsync(); if (nbrLinkVoSi > 0) { throw new SequenceException($"SelecotrEngine.Init: Can't allocate data for SelectorInstance (from {selectorInstance?.SelectorConfig?.Name}) because there are already SelectorInstance for data."); } IEnumerable <ValueObject> lstValueObject = await where .Aggregate(dbQuery, (current, predicate) => current.Where(predicate)) .Include(vo => vo.DataSet) .Where(vo => vo.DataSet.Id == wfInstance.DataSetId) //.AsNoTracking() .ToAsyncEnumerable() .ToList(); selectorInstance.SelectorInstanceValueObject = new List <SelectorInstanceValueObject>(); foreach (ValueObject vo in lstValueObject) { vo.FutureValue = null; SelectorInstanceValueObject sivo = new SelectorInstanceValueObject() { SelectorInstance = selectorInstance, ValueObject = vo }; sivo.InitDatesAndUser(""); selectorInstance.SelectorInstanceValueObject.Add(sivo); vo.SelectorInstanceValueObject.Add(sivo); vo.Status = ValueObjectStatusEnum.Modify; } int nbr = await UnitOfWork.GetDbContext().SaveChangesAsync(); // Création de la table temporaire de données... res.Append(await GridConfigurationDomain.CreateDataTableDB(selectorInstance, wfInstance)); // Recherche des modificateurs res.Append(await SelectorInstanceDomain.FindModificator(selectorInstance, wfInstance)); // Recherche des validateurs res.Append(await SelectorInstanceDomain.FindValidators(selectorInstance, wfInstance)); // On régle les données modifiables res.Append(await SelectorInstanceDomain.SetModifyData(selectorInstance, wfInstance, dimIds)); return(res); }
/// <summary> /// Créé la table temporaire pour un selectorInstance, selon la configuration de grid définie pour le WorkflowConfig lié. /// </summary> /// <param name="selectorInstance">Instance du SelectorInstance</param> /// <param name="wfInstance">Instance du WorkflowInstance</param> /// <returns>Message de retour</returns> public async Task <HttpResponseMessageResult> CreateDataTableDB(SelectorInstance selectorInstance, WorkflowInstance wfInstance) { // Transaction IDbContextTransaction transaction = SessionStatsHelper.HttpHitGetDBTransaction(_serviceProvider); if (transaction == null) { throw new DatabaseException("GridConfigurationDomain.CreateDataTableDB: impossible to retrieve transaction connexion."); } HttpResponseMessageResult res = new HttpResponseMessageResult() { IsSuccess = true }; // On récupére la configuration de l'opérateur List <GridConfig> lstGridConf = await UnitOfWork.GetDbContext().GridConfig .Include(gc => gc.ColumnDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.RowDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.FixedDimensions) .ThenInclude(gdc => gdc.Values) .Include(gc => gc.WorkflowConfig) .Where(gc => gc.WorkflowConfig.Id == wfInstance.WorkflowConfig.Id) .AsNoTracking() .ToAsyncEnumerable() .ToList(); GridConfig gridConf = lstGridConf.FirstOrDefault(); if (gridConf == null) { throw new SequenceException($"GridConfigurationDomain.CreateDataTableDB: no grid configuration for WorkflowConfig ({wfInstance.WorkflowConfig.Id})."); } // Construction de la requête StringBuilder query = new StringBuilder(); string nomTable = string.Format(Constant.TEMPLATE_TEMPORARY_TABLENAME, selectorInstance.Id.ToString()); List <string> nomCols = new List <string>(); IEnumerable <DistributionDimensionGrid> lstDistCols = GenerateDistribution(gridConf.ColumnDimensions); query.AppendLine($"CREATE TABLE {nomTable}("); query.AppendLine("ID bigint IDENTITY(1,1) NOT NULL,"); foreach (GridDimensionConfig fixes in gridConf.FixedDimensions.OrderBy(c => c.Order)) { string nomCol = ((int)fixes.InternalName).ToString(); query.AppendLine($"Dim{nomCol} nvarchar(max) NULL,"); nomCols.Add($"Dim{nomCol}"); } foreach (GridDimensionConfig row in gridConf.RowDimensions.OrderBy(r => r.Order)) { string nomCol = ((int)row.InternalName).ToString(); query.AppendLine($"Dim{nomCol} nvarchar(max) NULL,"); nomCols.Add($"Dim{nomCol}"); } foreach (DistributionDimensionGrid ddg in lstDistCols) { query.AppendLine($"{ddg.ColumnName}_ID bigint NOT NULL,"); query.AppendLine($"{ddg.ColumnName}_VAL float NOT NULL,"); nomCols.Add($"{ddg.ColumnName}_ID"); nomCols.Add($"{ddg.ColumnName}_VAL"); } query.SkipComma(); query.AppendLine(")"); // Exécution de la requete de création de table temporaire. int nbrQry = await ExecSqlHelper.ExecuteNonQueryTransactionAsync(query.ToString(), transaction); // Insertion des données dans la table temporaire. StringBuilder qryInsert = new StringBuilder(); qryInsert.AppendLine($"INSERT INTO {nomTable} ("); foreach (string nomCol in nomCols) { qryInsert.AppendLine($"{nomCol},"); } // Nettoyage qryInsert.SkipComma(); qryInsert.AppendLine(")"); qryInsert.AppendLine("SELECT "); List <string> groupedCols = new List <string>(); foreach (GridDimensionConfig fixes in gridConf.FixedDimensions.OrderBy(c => c.Order)) { string nomCol = fixes.InternalName.ToString(); qryInsert.AppendLine($"{nomCol},"); groupedCols.Add(nomCol); } foreach (GridDimensionConfig row in gridConf.RowDimensions.OrderBy(r => r.Order)) { string nomCol = row.InternalName.ToString(); qryInsert.AppendLine($"{nomCol},"); groupedCols.Add(nomCol); } foreach (DistributionDimensionGrid ddg in lstDistCols) { StringBuilder sbQry = new StringBuilder(); foreach (KeyValuePair <InternalNameDimension, string> pair in ddg.Selection) { if (sbQry.Length > 0) { sbQry.Append(" AND "); } sbQry.Append($"{pair.Key.ToString()} = '{pair.Value}'"); } qryInsert.AppendLine("MAX("); qryInsert.AppendLine("CASE"); qryInsert.Append("WHEN "); qryInsert.Append(sbQry); qryInsert.AppendLine(" THEN ID"); qryInsert.AppendLine("ELSE 0"); qryInsert.AppendLine("END"); qryInsert.AppendLine($"),"); qryInsert.AppendLine("MAX("); qryInsert.AppendLine("CASE"); qryInsert.Append("WHEN "); qryInsert.Append(sbQry); qryInsert.AppendLine(" THEN CurrentValue"); qryInsert.AppendLine("ELSE 0"); qryInsert.AppendLine("END"); qryInsert.AppendLine($"),"); } // Nettoyage qryInsert.SkipComma(); qryInsert.AppendLine("FROM ValueObject"); // Jointure avec la table de liaison qryInsert.AppendLine("WHERE ID IN ("); qryInsert.AppendLine($"SELECT ValueObjectId FROM SelectorInstanceValueObject WHERE SelectorInstanceId = {selectorInstance.Id} "); qryInsert.AppendLine(")"); qryInsert.Append("GROUP BY "); groupedCols.Reverse(); // Inverser pour la clause GROUP BY foreach (string grpCol in groupedCols) { qryInsert.Append($"{grpCol},"); } // Nettoyage qryInsert.SkipComma(); nbrQry = await ExecSqlHelper.ExecuteNonQueryTransactionAsync(qryInsert.ToString(), transaction); return(res); }
/// <summary> /// Permet de lire les données selon un format configuré par l'opérateur, avec des filtres, des tris, la pagination, etc... /// </summary> /// <param name="selectorInstanceId">Id du SelectorInstance concerné</param> /// <param name="filter">Chaines à filtrer, l'indexe représente le numéro de colonne sur lequel appliquer le filtre.</param> /// <param name="start">Numéro de ligne à partir duquel il faut commencer la selection</param> /// <param name="length">Nombre de ligne à sélectionner</param> /// <param name="sortCol">Numéro de colonne à trier</param> /// <param name="sortDir">Ordre du tri : ASC ou DESC</param> /// <returns>Message de retour + données</returns> public async Task <HttpResponseMessageResult> ReadData(long selectorInstanceId, string[] filter, int start, int length, int sortCol, string sortDir) { // Récupération du SelectorInstance et controles List <SelectorInstance> lst = await UnitOfWork.GetDbContext().SelectorInstance .Where(s => s.Id == selectorInstanceId) .Include(s => s.WorkflowInstance) .ThenInclude(wi => wi.WorkflowConfig) .AsNoTracking() .ToAsyncEnumerable() .ToList(); if ((lst == null) || (lst.Count == 0)) { throw new WrongParameterException($"ValueObject.ReadData : SelectorInstance ID {selectorInstanceId} not exist!"); } SelectorInstance sel = lst.FirstOrDefault(); // On récupére les noms de table et de colonnes. IEnumerable <string> colsTableName = await GridConfigurationDomain.GetColumnsFromGridConfiguration(sel, sel.WorkflowInstance); // On extrait les noms de colonnes effectives (non ID) List <string> nomColsDisplay = new List <string>(); for (int ic = 1; ic < colsTableName.Count(); ic++) { if (string.IsNullOrWhiteSpace(colsTableName.ElementAt(ic))) { continue; } if (colsTableName.ElementAt(ic).EndsWith("ID")) { continue; } nomColsDisplay.Add(colsTableName.ElementAt(ic)); } // Construction de la requête de lecture des données StringBuilder querySel = new StringBuilder(); // Choix des colonnes (toutes) querySel.AppendLine("SELECT "); foreach (string col in colsTableName.Skip(1)) { querySel.AppendLine($"{col},"); } querySel.SkipComma(); querySel.AppendLine($"FROM {colsTableName.ElementAt(0)}"); // Filtre StringBuilder where = new StringBuilder(); if ((filter != null) && (filter.Count() > 0) && (filter.Any(f => !string.IsNullOrWhiteSpace(f)))) { bool hasFilter = false; for (int i = 0; i < filter.Count(); i++) { if (i >= nomColsDisplay.Count) { continue; } if (where.Length > 0) { where.AppendLine("AND"); } where.AppendLine($"{nomColsDisplay[i]} LIKE '%{filter[i]}%'"); hasFilter = true; } if (hasFilter) { querySel.AppendLine("WHERE"); querySel.Append(where); } else { where.Clear(); } } // Tri bool hasOrderBy = false; if ((sortCol >= 0) && (sortCol < nomColsDisplay.Count)) { querySel.Append($"ORDER BY {nomColsDisplay[sortCol]} "); if (!string.IsNullOrWhiteSpace(sortDir) && sortDir.ToLower() == "asc") { querySel.AppendLine("ASC"); } else { querySel.AppendLine("DESC"); } hasOrderBy = true; } // Pagination if (start >= 0) { if (!hasOrderBy) { querySel.AppendLine("ORDER BY ID"); } querySel.AppendLine($"OFFSET {start} ROWS"); if (length > 0) { querySel.AppendLine($"FETCH NEXT {length} ROWS ONLY"); } } DbConnection connection = UnitOfWork.GetDbContext().Database.GetDbConnection(); IEnumerable <object[]> data = await ExecSqlHelper.ExecuteReaderAsync(querySel.ToString(), connection); Dictionary <string, object> dicoJson = new Dictionary <string, object>(); dicoJson.Add("TableName", colsTableName.ElementAt(0)); int numLine = 0; foreach (object[] row in data) { if (row.Length != colsTableName.Count() - 1) // -1 pour le nom de la table { continue; } Dictionary <string, object> rowJson = new Dictionary <string, object>(); for (int j = 0; j < row.Length; j++) { rowJson.Add(colsTableName.ElementAt(j + 1), row[j]); } dicoJson.Add(numLine.ToString(), rowJson); numLine++; } // Requete de comptage StringBuilder queryCount = new StringBuilder(); queryCount.AppendLine($"SELECT COUNT(1) FROM {colsTableName.ElementAt(0)} "); if (where.Length > 0) { queryCount.AppendLine("WHERE"); queryCount.Append(where); } IEnumerable <object[]> dataCount = await ExecSqlHelper.ExecuteReaderAsync(queryCount.ToString(), connection); if ((dataCount.Count() == 1) && (dataCount.ElementAt(0).Length == 1)) { int nbrTotal = (int)dataCount.ElementAt(0)[0]; dicoJson.Add("TotalRows", nbrTotal); } // Données modifiables List <long> idsValueObjectEditable = await UnitOfWork.GetDbContext().SelectorInstanceValueObject .Where(sivo => sivo.SelectorInstanceId == selectorInstanceId && sivo.IsEditable) .Select(sivo => sivo.ValueObjectId) .ToAsyncEnumerable() .ToList(); if ((idsValueObjectEditable != null) && (idsValueObjectEditable.Count > 0)) { dicoJson.Add("EditablesIds", idsValueObjectEditable); } // Reponse du retour HttpResponseMessageResult resData = new HttpResponseMessageResult() { IsSuccess = true, Json = JsonConvert.SerializeObject(dicoJson) }; return(resData); }