这是我写的一段代码,我是这样写的.注明一下this是EmployeeDividedBonusImportTransCollection,就是Excel
导入数据对应的集合表.EmployeeDividedBonusTransCollection,这个就是汇总表的集合,EmployeeDividedBonusDetailTrans是明细表的实体类.
/// <summary>
/// 生成汇总表,根据导入的Excel集合
/// </summary>
/// <returns>填充好的汇总表集合</returns>
public EmployeeDividedBonusTransCollection GenerateDividedBonusTransAndDetialTrans(YearlyBonusDivideForm form)
{
//查询出importCol中的员工的详细信息
Dictionary<string, string> dic = new Dictionary<string, string>();
this.ForEach(import =>
{
dic.Add(import.IdentityCardCode, import.EmployeeName);
});
EmployeeCollection employees = EmployeeAdapter.Instance.LoadEmployeeByIdentityCardCode(dic);
//将importCol中的employeeCode属性填上值
this.ForEach(import =>
{
import.EmployeeCode = employees.Find(p => p.IdentityCardCode == import.IdentityCardCode).Code;
});
//将员工转为OguUser类型,可以用GetOrgCode()获取OrgCode,组织Code
List<OguUser> lists = new List<OguUser>();
foreach (var emp in employees)
{
OguUser users = new OguUser(emp.Code);
lists.Add(users);
}
EmployeeDividedBonusTransCollection divBonTranCol = new EmployeeDividedBonusTransCollection();
//获取个税信息
SalaryTaxRule taxRule = SalaryTaxRuleAdapter.Instance.Get();
taxRule.NullCheck<ExpectedObjectNotExsitsException>("个税规则未设置");
//根据员工Code,获取员工薪酬参数信息
SalaryEmpCfgCollection configs = SalaryEmpCfgAdapter.Instance.LoadByEmpCodes(employees.Select(p => p.Code));
//根据获取到的员工详细信息和一些其他信息,修复主表和明细表
string employeeNames = string.Empty;
foreach (var user in lists)
{
//获取该员工的薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
if (salaryConfig == null)
{
employeeNames += this.Find(p => p.EmployeeCode == user.ID).EmployeeName + ",";
}
}
if (employeeNames.Length > 0)
{
throw new ExpectedObjectNotExsitsException(string.Format("员工[{0}]未找到员工薪酬参数设置", employeeNames.Substring(0, employeeNames.Length - 1)));
}
foreach (var user in lists)
{
//获取员工名
string empName = this.Find(p => p.EmployeeCode == user.ID).EmployeeName;
//获取该员工的薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
//根据员工的信息生成明细表记录
EmployeeDividedBonusDetailTrans detailTrans = TransDataCreator.Init(new EmployeeDividedBonusDetailTrans()
{
EmployeeCode = user.ID,
EmployeeName = empName, //user.DisplayName,
OrgCode = user.GetOrgCode() ?? string.Empty,
OrgName = user.GetOrgName(),
SalaryItemCode = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemCode,
SalaryItemName = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemName,
BonusSource = BonusSourceTypeEnum.BulkImport,
Amount = this.Find(p => p.EmployeeCode == user.ID).Amount,
Creator = DeluxeIdentity.CurrentUser.LogOnName,
CreateTime = DateTime.Now.SimulateTime(),
});
detailTrans.BonusPerformanceDistributeResultCode = detailTrans.Code;
//构造交易类
EmployeeDividedBonusTrans trans = TransDataCreator.Init(new EmployeeDividedBonusTrans()
{
FormCode = form.ID,
EmployeeCode = user.ID,
EmployeeName = empName,
OrgCode = user.GetOrgCode() ?? string.Empty,
OrgName = user.GetOrgName(),
Exemption = salaryConfig.IsManualSalaryTaxExemption ? salaryConfig.SalaryTaxExemption : taxRule.Exemption,
SalaryCheckStartPeriod = form.SalaryCheckStartPeriod,
});
detailTrans.DividedBonusCode = trans.Code;
trans.EmployeeDividedBonusDetail.Add(detailTrans);
divBonTranCol.Add(trans);
};
return divBonTranCol;
}
整个方法大体介绍下就是:将Excel中的数据连同一些数据,生成汇总表集合和明细表集合.
具体点就是:要生成一个汇总表的集合,那么要生成汇总表实体类,准备数据(前面那一堆代码都是用来准备各种填充汇总表和明细表用得到的数据的),将汇总表填充完整;然后由于汇总表实体类上有一个属性EmployeeDividedBonusDetail是明细表的集合,用于挂明细表集合.所以还需要生成明细表实体类,然后将明细表实体类上填充好数据,然后挂载到该属性上,这个过程就完成了.
接着分析就是,对于导入的Excel中的数据,由于要求一个人只能有一条记录,所以进行Foreach循环是根据人来循环的.(像是其他奖金分期发放,由于一个人可以有多条记录,并且每条记录都是可以生成明细表记录的,所以应该根据Excel记录来循环.)所以最后生成的记录就是每个人一条汇总表记录,每条汇总表记录上带着一条明细表记录.
其实,上面这个方法的写法是没有什么问题的,但是确不够清晰,尤其是对于我这种头脑不清晰的人来说,开始做的时候,我经常搞不清楚,我要用什么来进行循环,我是要对人来进行循环,还是对于Excel记录来循环.之前还有一个需求是,同一个人,可有多条明细记录,但是只能有一条汇总表记录,当时我差点没把自己给绕晕进去.后来我的做法是将Excel中的数据中的所有人取出,去重;然后对人进行循环,每人生成一条汇总记录;然后在循环的过程中,查询Excel导入集合中的该人的记录,查询出的一到多条记录,每条记录生成一条明细记录.
所以后来我进行优化的时候,把这个方法修改成了这样.
/// <summary>
/// 生成汇总表,根据导入的Excel集合
/// </summary>
/// <param name="importCol">excel对应的导入类</param>
/// <param name="formCode">页面的FormCode</param>
/// <returns>填充好的汇总表集合</returns>
public EmployeeDividedBonusTransCollection GenerateDividedBonusTransAndDetailTrans(YearlyBonusDivideForm form)
{
EmployeeDividedBonusTransCollection divBonTranCol = new EmployeeDividedBonusTransCollection();
//获取Excel中的员工信息
List<OguUser> listUser = this.ConvertToOguUser();
//获取个税信息和员工参数信息集合,并进行验证
SalaryTaxRule taxRule = null;
SalaryEmpCfgCollection configs = null;
ValidateSalaryEmpCfg(listUser, out taxRule, out configs);
//构造汇总表和明细表
listUser.ForEach(user =>
{
//员工薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
EmployeeDividedBonusTrans divTrans = TransDataCreator.Init(new EmployeeDividedBonusTrans()
{
FormCode = form.ID,
EmployeeCode = user.ID,
EmployeeName = user.DisplayName,
OrgCode = user.GetOrgCode() ?? string.Empty,
OrgName = user.GetOrgName(),
Exemption = salaryConfig.IsManualSalaryTaxExemption ? salaryConfig.SalaryTaxExemption : taxRule.Exemption,
SalaryCheckStartPeriod = form.SalaryCheckStartPeriod,
});
EmployeeDividedBonusDetailTrans detailTrans = TransDataCreator.Init(new EmployeeDividedBonusDetailTrans()
{
DividedBonusCode = divTrans.Code,
SalaryItemCode = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemCode,
SalaryItemName = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemName,
BonusSource = BonusSourceTypeEnum.BulkImport,
Amount = this.Find(p => p.EmployeeCode == user.ID).Amount,
Creator = DeluxeIdentity.CurrentUser.LogOnName,
CreateTime = DateTime.Now.SimulateTime(),
});
detailTrans.BonusPerformanceDistributeResultCode = detailTrans.Code;
divTrans.EmployeeDividedBonusDetail.Add(detailTrans);
divBonTranCol.Add(divTrans);
});
return divBonTranCol;
}
/// <summary>
/// 将excel导入对象转换为oguUser
/// </summary>
/// <param name="importCol"></param>
/// <returns></returns>
private List<OguUser> ConvertToOguUser()
{
//查询出importCol中的员工的详细信息
Dictionary<string, string> dic = new Dictionary<string, string>();
//获取员工身份证号和员工姓名,去重
var importColCopy = this.Select(p => new { p.IdentityCardCode, p.EmployeeName }).Distinct((x, y) => x.IdentityCardCode == y.IdentityCardCode);
importColCopy.ForEach(import =>
{
dic.Add(import.IdentityCardCode, import.EmployeeName);
});
//根据身份证号获取员工信息
EmployeeCollection employeeCol = EmployeeAdapter.Instance.LoadEmployeeByIdentityCardCode(dic);
//将importCol中的employeeCode属性填上值
this.ForEach(import =>
{
import.EmployeeCode = employeeCol.Find(p => p.IdentityCardCode == import.IdentityCardCode).Code;
});
//将员工转为OguUser类型,可以用GetOrgCode()获取OrgCode,组织Code
List<OguUser> lists = new List<OguUser>();
foreach (var emp in employeeCol)
{
OguUser users = new OguUser(emp.Code);
lists.Add(users);
}
return lists;
}
/// <summary>
/// 检查个税信息和员工薪酬参数信息,并返回个税信息和员工薪酬参数信息集合
/// </summary>
/// <param name="listUser"></param>
/// <param name="taxRule"></param>
/// <param name="configs"></param>
private void ValidateSalaryEmpCfg(List<OguUser> listUser, out SalaryTaxRule taxRule, out SalaryEmpCfgCollection configs)
{
//获取个税信息
taxRule = SalaryTaxRuleAdapter.Instance.Get();
taxRule.NullCheck<ExpectedObjectNotExsitsException>("个税规则未设置");
//根据员工Code,获取员工薪酬参数信息
configs = SalaryEmpCfgAdapter.Instance.LoadByEmpCodes(listUser.Select(p => p.ID));
//根据获取到的员工详细信息和一些其他信息,修复主表和明细表
string employeeNames = string.Empty;
foreach (var user in listUser)
{
//获取该员工的薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
if (salaryConfig == null)
{
employeeNames += this.Find(p => p.EmployeeCode == user.ID).EmployeeName + ",";
}
}
if (employeeNames.Length > 0)
{
throw new ExpectedObjectNotExsitsException(string.Format("员工[{0}]未找到员工薪酬参数设置", employeeNames.Substring(0, employeeNames.Length - 1)));
}
}
其实,就是把上面的那堆准备数据,进行了拆分,写成了方法,放在其他地方,这样这个方法就简洁多了.首先是将Excel导入的集合,变成员工信息(OguUser),然后就开始遍历循环,这些员工信息,每人生成一条汇总表和明细表记录.然后还是准备一些信息,并进行验证,最后就是构造汇总表和明细表记录集合.
这样的好处是将方法变得简短清晰,分离出来的方法也可以方便复用;缺点是方法变多了,在某种程度上,也影响了阅读性,并且方法可以复用的话,一旦某个复用该方法的地方的需求变化,需要修改该方法,很可能导致其他地方出现问题,有好也有坏.
写这篇博客之前,我觉得我优化的挺好的;写这篇博客的时候,我发现我优化根本没改什么;并且写着写着我发现,我还优化错了.本来修改的效果不是这样的,因为我忘了一个特别重要的地方,就是循环中,尽量不要去查询数据库,因为这样会影响效率.所以才会出现先查询员工薪酬参数集合,然后循环的时候只是去找该员工的薪酬参数的做法.可是我给忘了,我在循环中加了Load数据库,所以又重新修改了.
但是总是感觉上面的优化还是不好,我是有4个这样的方法,我把他们分散到各个类中,然后去完成类似的方法,总觉得代码无法复用.我在写代码的时候有一点疑问,就是一个方法到底应该放在哪个类里.就想我的生成汇总表集合的方法,我是把它放在汇总表的集合类中,还是应该根据他的参数Excel导入集合,放到导入集合中?不过,不管这些了,我最后还是把这4个方法放到了汇总表的集合类中,所以我进行了又一次的优化,代码改成了这样.
/// <summary>
/// 生成汇总表,根据导入的Excel集合,年终奖金分期发放
/// </summary>
/// <param name="importCol">excel对应的导入类</param>
/// <param name="formCode">页面的FormCode</param>
/// <returns>填充好的汇总表集合</returns>
public EmployeeDividedBonusTransCollection GenerateDividedBonusTransAndDetailTrans(EmployeeDividedBonusImportTransCollection importCol, YearlyBonusDivideForm form)
{
//获取Excel中的员工信息
//获取Excel中的员工信息
Dictionary<string, string> dic = new Dictionary<string, string>();
//获取员工身份证号和员工姓名,去重
var importColCopy = importCol.Select(p => new { p.IdentityCardCode, p.EmployeeName }).Distinct((x, y) => x.IdentityCardCode == y.IdentityCardCode);
importColCopy.ForEach(import =>
{
dic.Add(import.IdentityCardCode, import.EmployeeName);
});
//根据身份证号获取员工信息
EmployeeCollection employeeCol = EmployeeAdapter.Instance.LoadEmployeeByIdentityCardCode(dic);
//将otherImportCol中的employeeCode属性填上值
importCol.ForEach(import =>
{
import.EmployeeCode = employeeCol.Find(p => p.IdentityCardCode == import.IdentityCardCode).Code;
});
//将员工转为OguUser类型,可以用GetOrgCode()获取OrgCode,组织Code
List<OguUser> listUser = ConvertToOguUser(employeeCol);
//获取个税信息和员工参数信息集合,并进行验证
SalaryTaxRule taxRule = null;
SalaryEmpCfgCollection configs = null;
ValidateSalaryEmpCfg(listUser, out taxRule, out configs);
string strSalaryCode = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemCode;
string strSalaryName = BonusDivideConfig.GetConfig().FirstPartStrategySalaryItemName;
//构造汇总表和明细表
listUser.ForEach(user =>
{
//构造汇总表
//员工薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
decimal exemption = salaryConfig.IsManualSalaryTaxExemption ? salaryConfig.SalaryTaxExemption : taxRule.Exemption;
EmployeeDividedBonusTrans divBonTrans = EmployeeDividedBonusTrans.GenerateTran(form.ID, user, exemption, form.SalaryCheckStartPeriod, null);
//构造明细表
decimal decAmount = importCol.Find(p => p.EmployeeCode == user.ID).Amount;
EmployeeDividedBonusDetailTrans detailTrans = EmployeeDividedBonusDetailTrans.GenerateDetailTran(divBonTrans.Code, strSalaryCode, strSalaryName, decAmount, BonusSourceTypeEnum.BulkImport, null);
divBonTrans.EmployeeDividedBonusDetail.Add(detailTrans);
this.Add(divBonTrans);
});
return this; }
/// <summary>
/// 将员工集合信息转为OguUser
/// </summary>
/// <param name="employeeCol"></param>
/// <returns></returns>
private List<OguUser> ConvertToOguUser(EmployeeCollection employeeCol)
{
//将员工转为OguUser类型,可以用GetOrgCode()获取OrgCode,组织Code
List<OguUser> lists = new List<OguUser>();
foreach (var emp in employeeCol)
{
OguUser users = new OguUser(emp.Code);
lists.Add(users);
}
return lists;
}
/// <summary>
/// 检查个税信息和员工薪酬参数信息,并返回个税信息和员工薪酬参数信息集合
/// </summary>
/// <param name="listUser"></param>
/// <param name="taxRule"></param>
/// <param name="configs"></param>
private void ValidateSalaryEmpCfg(List<OguUser> listUser, out SalaryTaxRule taxRule, out SalaryEmpCfgCollection configs)
{
//获取个税信息
taxRule = SalaryTaxRuleAdapter.Instance.Get();
taxRule.NullCheck<ExpectedObjectNotExsitsException>("个税规则未设置");
//根据员工Code,获取员工薪酬参数信息
configs = SalaryEmpCfgAdapter.Instance.LoadByEmpCodes(listUser.Select(p => p.ID));
//根据获取到的员工详细信息和一些其他信息,修复主表和明细表
string employeeNames = string.Empty;
foreach (var user in listUser)
{
//获取该员工的薪酬参数信息
SalaryEmpCfg salaryConfig = configs.SingleOrDefault(p => p.EmployeeCode == user.ID);
if (salaryConfig == null)
{
employeeNames += this.Find(p => p.EmployeeCode == user.ID).EmployeeName + ",";
}
}
if (employeeNames.Length > 0)
{
throw new ExpectedObjectNotExsitsException(string.Format("员工[{0}]未找到员工薪酬参数设置", employeeNames.Substring(0, employeeNames.Length - 1)));
}
}
EmployeeDividedBonusTrans 类
/// <summary>
/// 构造汇总表
/// </summary>
/// <param name="strFormCode">FormCode</param>
/// <param name="user">用于填充EmployeeCode,EmployeeName,OrgCode和OrgName</param>
/// <param name="dicExemption">Exemption</param>
/// <param name="period">用于填充发放期间年份和月份</param>
/// <param name="employment">填充岗位类别Code和岗位类别名称</param>
/// <returns></returns>
public static EmployeeDividedBonusTrans GenerateTran(string strFormCode, OguUser user, decimal decExemption, MonthPeriod period, Employment employment)
{
EmployeeDividedBonusTrans divBonTran = TransDataCreator.Init(new EmployeeDividedBonusTrans()
{
FormCode = strFormCode,
EmployeeCode = user.ID,
EmployeeName = user.DisplayName,
OrgCode = user.GetOrgCode() ?? string.Empty,
OrgName = user.GetOrgName(),
Exemption = decExemption,
SalaryCheckStartPeriod = period,
SpecializationCode = employment == null ? string.Empty : employment.SpecializationCode,
SpecializationName = employment == null ? string.Empty : employment.SpecializationCode,
});
return divBonTran;
}
EmployeeDividedBonusDetailTrans类
/// <summary>
/// 构造明细表
/// </summary>
/// <param name="strDividedBonusCode">DividedBonusCode</param>
/// <param name="strSalaryItemCode">薪酬结构项Code</param>
/// <param name="strSalaryItemName">薪酬结构项Name</param>
/// <param name="decAmount">金额</param>
/// <param name="enumBonusSource">数据来源</param>
/// <param name="result">绩效奖金结果,没有就为null</param>
/// <returns></returns>
public static EmployeeDividedBonusDetailTrans GenerateDetailTran(string strDividedBonusCode, string strSalaryItemCode, string strSalaryItemName, decimal decAmount, BonusSourceTypeEnum enumBonusSource, BonusPerformanceDistributeResult result)
{
EmployeeDividedBonusDetailTrans detailTran = TransDataCreator.Init(new EmployeeDividedBonusDetailTrans()
{
DividedBonusCode = strDividedBonusCode,
SalaryItemCode = strSalaryItemCode,
SalaryItemName = strSalaryItemName,
BonusSource = enumBonusSource,
Amount = decAmount,
Creator = DeluxeIdentity.CurrentUser.LogOnName,
CreateTime = DateTime.Now.SimulateTime(),
});
if (result != null)
{
detailTran.BonusPerformanceDistributeResultCode = result.Code;
detailTran.PerformanceYear = result.EmpAssessPeriod.Year;
detailTran.EmpAssessPeriodDetailCode = result.EmpAssessPeriod.PeriodDetailCode;
detailTran.BonusTypeCode = result.BonusTypeCode;
}
return detailTran;
}
对于提取的private List<OguUser> ConvertToOguUser()方法,因为没有办法复用,所以放弃提取整个大的方法,改而提取 private List<OguUser> ConvertToOguUser(EmployeeCollection employeeCol),至少可以做到复用.并且将实体类的构建方法抽取,放到了各自的实体类中.这样的好处是,比较明确,因为基本上所有字段都列出,你所要做的只是对于不需要的就不用赋值.优化完之后,我一点也不觉得我的代码有任何清晰化的特征,但是我至少做到了让代码行数变少了.
写完这篇博客,我感觉我在写代码这条路上真的任重而道远.