zoukankan      html  css  js  c++  java
  • .net 动态编译解决考勤计算问题

           由于公司实施SAP HR项目,但是SAP HR对考勤功能真的太弱化了,直接从考勤机上读取的原始打卡记录不能直接传输到HR系统里面,因为SAP HR不能识别那些多余的打卡记录,而且必须把打卡记录进行成组标记(P10,P20),以上标红色的是SAP HR顾问给我的反馈信息。

           这样以来,必须开发一套算法来把多余的打卡记录进行过滤掉,然后标记上是P10还是P20,这样以来,HR系统在做时间评估时才不会出现异常情况。

           需求已经明确,那么就是设计开发的问题,要开发该功能,需要用到的资源:

          1、考勤的排班数据

          2、原始打卡数据

          3、取原始打卡数据的算法

          然后就是确定该功能在我们的外围基础数据平台开发(外围系统是用.net开发的)

         

          由于我们公司的考勤计算方式可能会经常有变化,因为不能把打卡数据的算法写死到代码里面,这样有两种解决方案:1是用侟储过程  2是用动态编译

    考虑到以后数据库的迁移问题,最终采取.net动态编译方式来处理该问题

          具体的实现思想如下:

          1、把算法代码存储在数据库表中

          2、新建一个计算考勤的静态类,类里面定义一个计算考勤的静态方法,传入参数为两上Table类型,一个为排班表,一个为原始打卡记录表,返回参数也

              为DataTable内型,为计算完成后的结果数据,把该段代码保存在一个静态变量里面。

          3、调用计算方法时,把静态类的代码加上代算法代码编译成动态类。

          4、利用反射技术,调用计算方法,返回结果。

          关键性代码如下:

     

    动态编译类:

    DynCompiler.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.CodeDom.Compiler;
    using Microsoft.CSharp;
    using System.Reflection;
    using System.Data;
    
    namespace EDICLibrary
    {
        public class DynCompiler:IDisposable
        {
    
            CodeDomProvider _codeprovide;
            CompilerParameters _parameters; 
            CompilerResults _result = null;
            MethodInfo _method = null;
            Object _instance = null;
           
           
            public DynCompiler()
            {
                _codeprovide = new CSharpCodeProvider();
                _parameters = new CompilerParameters();
                _parameters.GenerateExecutable = false;
                _parameters.GenerateInMemory = true;
                _parameters.ReferencedAssemblies.Add("System.dll");
                _parameters.ReferencedAssemblies.Add("System.Data.dll");
                _parameters.ReferencedAssemblies.Add("System.Xml.dll");
            }
    
            public bool SourceCompiler(string source, out string outputMsg)
            {
                 outputMsg = "";
                 StringBuilder sbout = new StringBuilder();
                 StringBuilder sb = new StringBuilder();
                if (string.IsNullOrEmpty(source))
                {
                    outputMsg = "源代码不能为空!";
                    return false;
                }
                else
                {
                   
                    sb.AppendLine("using System;");
                    sb.AppendLine("using System.Collections.Generic;");
                    sb.AppendLine("using System.Text;");
                    sb.AppendLine("using System.Data;");
                    sb.AppendLine ("using System.Xml;");
                    sb.AppendLine("namespace JMCompiler");
                    sb.AppendLine("{");
                    sb.AppendLine("public class DynCompilerHelper");
                    sb.AppendLine("{");
                    sb.AppendLine("public DataTable Calculate(DataTable dtShiftInfo,DataTable dtTimes)");
                    sb.AppendLine("{");
                    sb.Append(source);
                    sb.Append("}");
                    sb.AppendLine("}");
                    sb.AppendLine("}");
                }
                _result  =  _codeprovide.CompileAssemblyFromSource(_parameters, sb.ToString());
                if (_result.Errors.HasErrors)
                {
                    foreach (string str in _result.Output)
                    {
                        sbout.AppendLine(str);
                    }
                    outputMsg = sbout.ToString();
                    return false;
                }
                else
                {
                    Type _type = _result.CompiledAssembly.GetType("JMCompiler.DynCompilerHelper");
                    _instance = Activator.CreateInstance(_type);
                    _method = _type.GetMethod("Calculate",new Type[]{typeof(DataTable),typeof (DataTable)});
                    outputMsg = "编译成功";
                    return true;
                }
    
            }
    
            public object GetReturnResult(List<DataTable> parameters)
            {             
    
                if (_method == null)
                {
                      throw new Exception ("未进行代码编译");
                }
                return _method.Invoke(_instance, parameters.ToArray());   
            }
    
            
            #region IDisposable 成员
    
            public void Dispose()
            {
                 _codeprovide = null;
                 _parameters = null;
                 _result = null;
                 _method = null;
                 _instance = null;
            }
    
            #endregion
        }
    }
    

    计算考勤类:

    AttdCalculate.cs

     public  class AttdCalculate
        {
            /// <summary>
            /// 计算考勤
            /// </summary>
            /// <param name="source">计算考勤算法代码</param>
            /// <param name="dtShiftInfo">排班信息</param>
            /// <param name="dtTimes">原始打卡的数据</param>
            /// <param name="msg">输出信息</param>
            /// <returns>计算后的结果表</returns>
            public static DataTable Calculate(string source, DataTable dtShiftInfo, DataTable dtTimes, out string msg)
            {
                if (string.IsNullOrEmpty(source))
                {
                    msg = "考勤计算逻辑不能为空";
                    return new DataTable();
                }
                DynCompiler complier = new DynCompiler();
                string output;
                bool result = complier.SourceCompiler(source, out output);
                List<DataTable> lstData = new List<DataTable>();
                lstData.Add(dtShiftInfo);
                lstData.Add(dtTimes);
                if (result)
                {
                    msg = "计算成功";
                    return (DataTable)complier.GetReturnResult(lstData);
                }
                else
                {
    
                    msg = output;
                    return new DataTable();
                }
            }           
            
        }

    考勤调用代码

      //计算公式
                    string Source = string.Empty;
                    //获取计算工式
                    Source  = <获取计算工式的方法>                 
                    string msg;
                    //获取考勤数据
                    
                    DataTable dtResult = MIS.Util.AttdCalculate.Calculate(Source, dtShiftInfo, dtTimes, out msg);

    在写这篇文章的时候,开发的功能还没有投入到正式运行,但是经过最近一段时候的测试来看,没有任何问题。

  • 相关阅读:
    LOJ 2550 「JSOI2018」机器人——找规律+DP
    LOJ 2548 「JSOI2018」绝地反击 ——二分图匹配+网络流手动退流
    2019.4.24 一题(CF 809E)——推式子+虚树
    LOJ 2551 「JSOI2018」列队——主席树+二分
    bzoj 2632 [ neerc 2011 ] Gcd guessing game —— 贪心
    bzoj 1927 星际竞速 —— 最小费用最大流
    bzoj 2535 & bzoj 2109 航空管制 —— 贪心+拓扑序
    bzoj 3671 随机数生成器 —— 暴力
    bzoj 2395 Timeismoney —— 最小乘积生成树
    bzoj 3157 & bzoj 3516 国王奇遇记 —— 推式子
  • 原文地址:https://www.cnblogs.com/miarchen/p/3235011.html
Copyright © 2011-2022 走看看