Esempio n. 1
0
        /// <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.");
            //}
        }
Esempio n. 2
0
        /// <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);
        }
Esempio n. 3
0
        /// <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);
            }
        }
Esempio n. 4
0
        /// <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));
        }
Esempio n. 5
0
        /// <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);
        }
Esempio n. 6
0
        /// <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);
        }
Esempio n. 7
0
        /// <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);
        }
Esempio n. 8
0
        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);
        }
Esempio n. 9
0
        /// <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);
        }
Esempio n. 10
0
        /// <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);
        }
Esempio n. 11
0
        /// <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
            });
        }
Esempio n. 12
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.");
                }
            }
        }
Esempio n. 13
0
        /// <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);
            //}
        }
Esempio n. 14
0
        /// <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);
        }
Esempio n. 23
0
        /// <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);
        }
Esempio n. 24
0
        /// <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);
        }