Exemple #1
0
        private void reCalculateLink(string calculateName, DateTimeOffset date)
        {
            try
            {
                //生成拓扑图
                ALGraph.MyGraph graph = new ALGraph.MyGraph();

                constructGraph(calculateName, graph, date);

                System.Collections.ArrayList toplist = graph.topSort();
                if (toplist.Count != graph.Vexnum)
                {
                    throw new Exception("仪器公式存在循环依赖");
                }

                //根据拓扑顺序依次更新

                for (int i = 0; i < toplist.Count; i++)
                {
                    string csn = (string)toplist[i];
                    //不必更新本身
                    if (csn != calculateName)
                    {
                        AppIntegratedInfo otherApp = new AppIntegratedInfo(csn, date);
                        reCalcValues(otherApp, null, date);
                        //要更新数据
                        otherApp.Update();
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("计算关联测点错误 " + ex.Message);
            }
        }
        /// <summary>
        /// 构造树型结点,并查找计算变量引用的测点
        /// </summary>
        /// <param name="appCalcName">计算名称</param>
        /// <param name="vars">计算公式中需要的计算变量</param>
        /// <param name="graph">拓扑树</param>
        /// <param name="idList">引用测点计算的计算名称列表</param>
        /// <param name="symbol">当前计算量的符号</param>
        private void intitalVars(string appCalcName, ArrayList vars, ALGraph.MyGraph graph, hammergo.caculator.MyList idList, string symbol)
        {
            for (int i = 0; i < vars.Count; i++)
            {
                string vs  = (string)vars[i];
                int    pos = vs.IndexOf('.');
                if (pos != -1)//带点的参数
                {
                    string otherID = vs.Substring(0, pos);
                    if (otherID == appCalcName)//计算名称
                    {
                        throw new Exception("公式中的变量不能包含本仪器的二级变量");
                    }
                    else
                    {
                        idList.add(otherID.ToUpper(), 0);
                    }
                }
                else
                {
                    //					//不带点的参数

                    //添加弧

                    graph.addArcNode(new ALGraph.ArcNode(), vs, symbol);
                }
            }
        }
Exemple #3
0
        /// <summary>
        /// 构建拓朴图
        /// </summary>
        /// <param name="calculateName">计算名称</param>
        /// <param name="graph">拓朴图</param>
        /// <param name="date">数据的日期,有可能不同日期的公式所引用的测点不一样</param>
        private void constructGraph(string calculateName, ALGraph.MyGraph graph, DateTimeOffset date)
        {
            hammergo.caculator.MyList list = getChildApp(calculateName, date);

            for (int i = 0; i < list.Length; i++)
            {
                string calcSn = list.getKey(i);
                graph.addArcNode(new ALGraph.ArcNode(), calculateName, calcSn);


                constructGraph(calcSn, graph, date);
            }
        }
 public void constructGraph(App app, ALGraph.MyGraph graph, List <Guid> loopCheckList)
 {
     foreach (App child in getChildApp(app))
     {
         if (loopCheckList.Exists(s => s == app.Id))
         {
             throw new Exception("测点公式中引用了其它测点的公式,但是存在循环引用的问题");
         }
         else
         {
             loopCheckList.Add(app.Id);
         }
         graph.addArcNode(new ALGraph.ArcNode(), app.CalculateName, child.CalculateName);
         constructGraph(app, graph, loopCheckList);
     }
 }
        public void Validate()
        {
            List <string> nameList   = new List <string>(20);
            List <string> symbolList = new List <string>(20);

            //_modifiedApp _modifiedParams和实例中的其它Entity属于不同的dbcontext

            //需要验证公式更新的逻辑,这是整个app最复杂的问题之一,其它有公式解析和拓扑排序
            //获取参数列表
            var paramsLocal = (from i in dbcontext.AppParams
                               where i.AppId == _modifiedApp.Id
                               select i).AsNoTracking().ToList();
            //获取该测点的所有计算公式

            //当前数据库中的参数列表
            var formulaeLocal = (from p in dbcontext.AppParams.OfType <CalculateParam>()
                                 where p.AppId == _modifiedApp.Id
                                 join f in dbcontext.Formulae
                                 on p.Id equals f.ParamId
                                 select f).ToList(); //需要更新formula的计算次序


            //处理added,modified,deleted
            //用修改的值替换内存中的值
            foreach (var entry in _paramsEntries)
            {
                var entity = entry.Entity as AppParam;
                if (entity.AppId == _modifiedApp.Id)
                {
                    //只能是modified或deleted
                    int index = paramsLocal.FindIndex(s => s.Id == entity.Id);
                    if (index >= 0)
                    {
                        paramsLocal.RemoveAt(index);
                    }
                    if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
                    {
                        paramsLocal.Add(entity);
                    }
                    else if (entry.State == EntityState.Deleted)
                    {
                        //在删除参数时,会级联删除公式

                        formulaeLocal.RemoveAll(s => s.ParamId == entity.Id);
                    }
                }
            }

            foreach (ObjectStateEntry entry in _formulaEntries)
            {
                var entity = entry.Entity as Formula;
                //公式必须依附于参数
                //paramList中的参数有可以是新增的参数,即数据库还没有记录
                if (paramsLocal.Exists(s => s.Id == entity.ParamId))
                {
                    int index = formulaeLocal.FindIndex(s => s.ParamId == entity.ParamId && s.StartDate == entity.StartDate);
                    if (index >= 0)
                    {
                        //entity已被修改,或增加,删除,得先从列表中先先移除
                        formulaeLocal.RemoveAt(index);
                    }
                    if (entry.State == EntityState.Modified || entry.State == EntityState.Added)
                    {
                        formulaeLocal.Add(entity);
                    }
                }
            }


            //检查名称和符号是否有重复
            checkParamNames(paramsLocal, nameList, symbolList);

            //测点公式的时间段必须具备连续性,所以需先对公式进行检查
            var formulaGroup = (from i in formulaeLocal
                                orderby i.StartDate ascending
                                group i by i.StartDate).ToList();
            int gCnt = formulaGroup.Count();

            if (gCnt > 0)
            {
                int calcParamsCnt = paramsLocal.OfType <CalculateParam>().Count();

                //每组公式的结束时间
                DateTimeOffset?endDate = null;;
                for (int i = 0; i < gCnt; i++)
                {
                    var item      = formulaGroup[i];
                    var startDate = item.Key;
                    if (endDate != null)
                    {
                        if (startDate != endDate)
                        {
                            throw new Exception(string.Format("起始时间为{0}的公式的开始时间与上一分段公式的结束时间没有衔接,\n即上一段公式的结束时间必须是下一段公式的开始时间", startDate));
                        }
                    }

                    //检查个数

                    if (item.Count() != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式与计算参数的数目不一致", startDate));
                    }

                    //公式和参数要一一对应,检查对应关系
                    var compositList = (from ci in paramsLocal.OfType <CalculateParam>()
                                        join f in item.AsEnumerable()
                                        on ci.Id equals f.ParamId
                                        select new
                    {
                        Param = ci,
                        Formula = f
                    }).ToList();
                    if (compositList.Count != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式没有与计算参数一一对应", startDate));
                    }


                    endDate = item.ElementAt(0).EndDate;

                    if (startDate >= endDate)
                    {
                        throw new Exception("分段公式的开始时间必须小于结束时间");
                    }

                    if (item.Count(s => s.EndDate == endDate) != calcParamsCnt)
                    {
                        throw new Exception(string.Format("起始时间为{0}的公式结束时间不一致", startDate));
                    }

                    //检查每组公式的计算逻辑

                    hammergo.caculator.MyList list = new hammergo.caculator.MyList(10);

                    int num = 1;//填充一些数据,测试计算的表达式
                    foreach (string s in symbolList)
                    {
                        list.add(s, num++);
                    }



                    // 简单的判断公式的依赖关系,只能精确到仪器,不能精确的量(如n01cf14.e的依赖关系,过于复杂)


                    //生成新的图
                    ALGraph.MyGraph graph = new ALGraph.MyGraph();
                    hammergo.caculator.CalcFunction calc = new hammergo.caculator.CalcFunction();
                    //引用测点的编号列表
                    hammergo.caculator.MyList calcNameList = new hammergo.caculator.MyList(5);



                    foreach (var cp in compositList)
                    {
                        string formulaString = cp.Formula.FormulaExpression;
                        string symbol        = cp.Param.ParamSymbol;

                        if (formulaString == null || formulaString.Trim().Length == 0)
                        {
                            throw new Exception(string.Format("计算参数 {0} 的计算公式不能为空", cp.Param.ParamName));
                        }

                        ArrayList vars = calc.getVaribles(formulaString);

                        intitalVars(_modifiedApp.CalculateName, vars, graph, calcNameList, symbol);
                    }


                    ArrayList toplist = graph.topSort();
                    if (toplist.Count != graph.Vexnum)
                    {
                        throw new Exception("公式存在循环依赖");
                    }

                    ArrayList storeTopList = toplist;

                    // 刚才是检查仪器内的循环依赖,现在和所有的仪器一起检查


                    graph = new ALGraph.MyGraph();

                    for (int j = 0; j < calcNameList.Length; j++)
                    {
                        graph.addArcNode(new ALGraph.ArcNode(), calcNameList.getKey(j), _modifiedApp.CalculateName); //全部使用计算名称
                        var loopCheckList = new List <Guid>(5);
                        constructGraph(_modifiedApp, graph, loopCheckList);                                          //递归加入其子结点
                    }

                    toplist = graph.topSort();
                    if (toplist.Count != graph.Vexnum)
                    {
                        System.Text.StringBuilder sb = new System.Text.StringBuilder(128);
                        foreach (ALGraph.VNode node in graph.vertices)
                        {
                            sb.Append(node.data).Append("  ");
                        }
                        throw new Exception(sb.ToString() + " 仪器公式存在循环依赖");
                    }


                    toplist = storeTopList;

                    //图不存在回路
                    //引用的其它测点,填充
                    for (int j = 0; j < calcNameList.Length; j++)
                    {
                        string calcName = calcNameList.getKey(j);

                        var refApp = dbcontext.Apps.AsNoTracking().FirstOrDefault(s => s.CalculateName == calcName);

                        if (refApp == null)
                        {
                            throw new Exception(string.Format("计算名称为{0}的仪器不存在!", calcName));
                        }
                        //ArrayList paList = new ArrayList(12);
                        //paList.AddRange(consBLL.GetListByappName(refApp.AppName));
                        //paList.AddRange(mesBLL.GetListByappName(refApp.AppName));
                        //paList.AddRange(calcBLL.GetListByappName(refApp.AppName));

                        var paList = refApp.AppParams.ToList();

                        for (int k = 0; k < paList.Count; k++)
                        {
                            var pi = paList[k];

                            list.add(calcName + "." + pi.ParamSymbol, k + 1);
                        }
                    }


                    foreach (var cp in compositList)
                    {
                        string formula = cp.Formula.FormulaExpression;
                        calc.compute(formula, list);

                        string symbol = cp.Param.ParamSymbol;

                        int index = toplist.IndexOf(symbol);
                        if (index < 0)
                        {
                            //此符号不在拓扑图中,没有公式依赖于它
                            index = toplist.Count;
                        }

                        //cp.CalculateOrder = (byte)index;
                        //更新计算次序
                        cp.Formula.CalculateOrder = (byte)index;
                    }
                }
            }
        }