【问题标题】:deduct insured amount after every routine checkup for each employee每位员工每次例行体检后扣除保险金额
【发布时间】:2020-12-20 22:17:35
【问题描述】:

这是我的问题的示例数据,

List<EMPINSURED> lstEmpIns = new List<EMPINSURED>{
    new EMPINSURED{ EmpID = 558, TOTAL_INSURED_AMT = 50000},
    new EMPINSURED{ EmpID = 559, TOTAL_INSURED_AMT = 75000} 
};

List<EMP_ROUTINE_CHECKUP_HISTORY> lstEmpRoutineChkHist = new List<EMP_ROUTINE_CHECKUP_HISTORY>{
    new EMP_ROUTINE_CHECKUP_HISTORY{ ID = 1, EmpID = 558, ROUTINE_CHECKUP = 1, CHECK_UP_CHARGE = 20000},
    new EMP_ROUTINE_CHECKUP_HISTORY{ ID = 2, EmpID = 559, ROUTINE_CHECKUP = 1, CHECK_UP_CHARGE = 35000},
    new EMP_ROUTINE_CHECKUP_HISTORY{ ID = 3, EmpID = 558, ROUTINE_CHECKUP = 2, CHECK_UP_CHARGE = 10000},
    new EMP_ROUTINE_CHECKUP_HISTORY{ ID = 4, EmpID = 559, ROUTINE_CHECKUP = 2, CHECK_UP_CHARGE = 10000},
    new EMP_ROUTINE_CHECKUP_HISTORY{ ID = 5, EmpID = 558, ROUTINE_CHECKUP = 3, CHECK_UP_CHARGE = 20000}
};

一年内,一名员工只能接受 3 次例行检查。员工进行例行检查时,其检查费用必须从总保险金额中扣除。下一次例行检查,仅按保额总保额中剩余的部分发给员工检查费,超过此部分的费用,公司概不承担。 所以计算REMAINING AMOUNT的逻辑有点像这样::

    int var = 0;
if(ROUTINE_CHECKUP == 1)
{
    REMAINING_AMOUNT = TOTAL_INSURED_AMT - CHECK_UP_CHARGE;
    var = CHECK_UP_CHARGE;
} 
else if (ROUTINE_CHECKUP == 2)
{
    REMAINING_AMOUNT = TOTAL_INSURED_AMT - (CHECK_UP_CHARGE + var);
    var = CHECK_UP_CHARGE + var;
}
else if (ROUTINE_CHECKUP == 3)
{
    REMAINING_AMOUNT = TOTAL_INSURED_AMT - (CHECK_UP_CHARGE + var);
    var = CHECK_UP_CHARGE + var;
}

如何使用此逻辑开发 LINQ 查询以获取以下报告数据,或者可能有更好的方法来执行此操作。 报告格式见附图。

【问题讨论】:

  • 尚未进行体检的员工怎么办?您是否希望它们也在列表中,RoutineChekup = 0, CheckupCharge=0, RemainingAmount = TotalInsuredAmount
  • 是的,我也必须给他们看。

标签: c# asp.net asp.net-mvc linq asp.net-mvc-5


【解决方案1】:

使用一些System.Linq扩展方法,您可以将JoinlstEmpIns列表与EmpId字段上的lstEmpRoutineChkHist列表转换为匿名类型,该类型具有每个字段中相应字段的列的值列出,并使用OrderByRoutineCheckup 对结果进行排序。

丑陋的部分是确定RemainingBalance,因为我们必须查找该员工的所有记录,其中RoutineCheckup小于或等于当前项目,然后将CheckupCharge相加,这样我们就可以扣除它来自RemainingBalance。可能有更好的方法,但这是我想出的。

这是一个基于您的代码但使用现代命名约定的示例:

var results = empInsureds
    .Join(empRoutineCheckupHistories,
        emp => emp.EmpId,
        hist => hist.EmpId,
        (emp, hist) => new
        {
            emp.EmpId,
            emp.TotalInsuredAmt,
            hist.RoutineCheckup,
            hist.CheckupCharge,
            RemainingBalance =
                emp.TotalInsuredAmt -
                empRoutineCheckupHistories
                    .Where(h => h.EmpId == hist.EmpId &&
                                h.RoutineCheckup <= hist.RoutineCheckup)
                    .Sum(h => h.CheckupCharge)
        })
    .OrderBy(r => r.RoutineCheckup)
    .ToList();

生成输出的一些代码:

Console.WindowWidth = 81;

Console.WriteLine(GetRow("EmpID", "Total Insured Amt", "Routine Checkup", 
    "Checkup Charge", "Remaining Amount"));

Console.WriteLine(new string('-', 80));

results.ForEach(r => Console.WriteLine(GetRow($"{r.EmpId}", $"{r.TotalInsuredAmt:C}", 
    $"{r.RoutineCheckup}", $"{r.CheckupCharge:C}", $"{r.RemainingBalance:C}")));

GetKeyFromUser("\nDone! Press any key to exit...");

其中使用了辅助函数:

public static string GetRow(string col1, string col2, string col3, string col4, 
    string col5)
{
    return col1.PadRight(5) + " | " +
           col2.PadLeft(17) + " | " +
           col3.PadRight(16) + " | " +
           col4.PadLeft(14) + " | " +
           col5.PadLeft(16);
}

输出

【讨论】:

  • 我可以使用group 子句与EmpID, RoutineCheckup 分组吗?
【解决方案2】:

如果您的源不是 IQueryable 而是 IEnumerable,我的建议是使用 Queryable.GroupJoin 的重载之一或其等效的 IEnumerable。

使用 GroupJoin,您可以获得“所有员工,每个人都有零次或多次例行检查”。通过使用参数 resultSelector,您可以创建所需的输出。

GroupJoin 的优势在于您还将获得迄今为止尚未进行任何检查的员工。如果您使用 Join,那么您根本不会得到这些员工。

var employeesWithTheirCheckups = dbContext.Employees.GroupJoin(
    dbContext.RoutineCheckUps,

    employee => employee.EmpId,     // from every Employee take the primary key
    checkup => checkup.EmpId,       // from every RoutineCheckup take the foreign key
                                   // to the Employee

    // parameter resultSelector: for every Employee and his zero or more Checkups,
    // make one new object:
    (employee, checkupsOfThisEmployee) => new
    {
        EmpId = employee.Id,
        TotalInsuredAmount = employee.TotalInsuredAmount,

        Checkups = checkupsOfThisEmployee.Select(checkup => new
        {
            RoutineCheckup = checkup.RoutineCheckup,
            CheckupCharge = checkup.CheckupCharge,

            // TODO: Remaining Amount   
        })
        .ToList(),
    });

剩余的检查费用,等于该员工的总金额减去“该员工在本次检查前的总检查费用”。

因此,对于带有 RoutineCheckup 2 的历史记录,您需要将所有带有 RoutineCheckups 的历史记录的所有计费金额相加

计算如下:

var chargedUntilNow = checkupsOfThisEmployee
    .Where(checkupOfThisEmployee => checkupOfThisEmployee <= checkup)
    .Select(checkupOfThisEmployee => checkupOfThisEmployee.CheckUpCharge)
    .Sum();

剩下的就是这个员工的总数 -chargeUntilNow。

返回GroupJoin:

(employee, checkupsOfThisEmployee) => new
{
    EmpId = employee.Id,
    TotalInsuredAmount = employee.TotalInsuredAmount,

    Checkups = checkupsOfThisEmployee.Select(checkup => new
    {
        RoutineCheckup = checkup.RoutineCheckup,
        CheckupCharge = checkup.CheckupCharge,

        // remaining is the total of this employee - chargedUntilNow.
        RemainingAmount = employee.TotalInsured -
            checkupsOfThisEmployee
            .Where(checkupOfThisEmployee => checkupOfThisEmployee <= checkup)
            .Select(checkupOfThisEmployee => checkupOfThisEmployee.CheckUpCharge)
            .Sum();
    })
    .ToList(),

结果是所有员工的序列(嗯,只有他的 ID 和他的总保险金额),每个员工都有他的零个或多个检查。每个 Checkup 都会有 RoutineCheckup 编号、CheckupAmount 和 RemainingAmount。

好东西:您还将拥有尚未进行检查的员工!

另外:[EmpId, TotalInsuredAmount],每个员工只能转移一次。如果您使用标准联接,则每次检查都会发送一次相同的 [EmpId, TotalInsuredAmount]。

如果您希望它变平,就像您的最终结果一样,请使用 SelectMany。继续 LINQ:

.SelectMany(groupJoinResult, groupJoinResult.Checkups, 

// parameter resultSelector: take the GroupJoinResult, and each one of its Checkups
// to make one new:
(groupJoinResult, checkupOfThisGroupJoinResult) => new
{
    EmpId = groupJoinResult.EmpId,
    TotalInsuredAmount = groupJoinResult.TotalInsuredAmount,

    RoutineCheckUp = checkupOfThisGroupJoinResult.RoutineCheckup,
    CheckupCharge = checkupOfThisGroupJoinResult.CheckupCharge,
    RemainingAmount = checkupOfThisGroupJoinResult.RemainingAmount,
});

问题是您将失去尚未进行任何检查的员工。要解决此问题,您必须提供默认值

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-09-06
    • 2021-11-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    相关资源
    最近更新 更多