【问题标题】:Can LINQ GROUPBY and SUM with Dapper achieve this?LINQ GROUPBY 和 SUM with Dapper 可以实现这一点吗?
【发布时间】:2020-04-08 19:07:28
【问题描述】:

我想要实现的是每天计算利息 [DailyLoanCalculation] 并在月底得到每个帐户的总计并保存在 [Total-interest] 表中。每个月都会发生同样的事情

我有一张 DailyLoanCalculation 表格,我在其中计算了每天结束时的每日利息。我已经做到了。

    DailyLoanCalculation table          
Day    Account No   Loan     interest Amount Per day    
1         12345     3000       150  
1         23456     1000       50   
1         43567     2500       125  
2         12345     3000       150  
2         23456     1000       50   
2         43567     2500       125  

    Total-Interest Table            
Day Account No  Loan   Total Interest  Total    
30  12345       3000    4500           7500
30  23456       1000    1500           2500
30  43567       2500    3750           6250

现在实现 [Total-Interest] 的目标是问题所在。 这是我一直在努力但无法前进的事情

 //Calculate the EndOfMonthDailyInterestCalculation
        public void EndOfMonthDailyInterestCalculation()
        {
            IEnumerable<DailyInterest> loans = null;

            using (var conn = new SqlConnection(ConnectionString))
            {
                conn.Open();

                loans = conn.Query<DailyInterest>("Select * from DailyInterest where BackgroundMonthly is Null");
                if (loans.Count() == 0) 
                {
                    return;
                }


                var TotalEachLoanInterest = loans.GroupBy(x => x.LoanAccountNo).Select(g =>g.Sum(x=>x.AmountPerDay));

**//I cant go further at this point**

                if (TotalEachLoanInterest.Count() == 0)
                {
                    return;
                }
                else
                {
                    foreach (var loan in loans)
                    {

                        var SumOfInteretForTheMonth = loan.


                        var markDailyAsCalculated = new
                        {
                            amountPerday = loan.AmountPerDay
                        };


                    }
                }
            }
        }

如果有更好的解决方法,请帮助我 谢谢

【问题讨论】:

  • 如果3K贷款一天的利息是150,30天后怎么变成300?您的总利息是每天 30 * 吗?这些实际表在您的数据库中吗?资本偿还是否在任何地方都考虑在内?如果有的话,它什么时候复合?
  • 这只是一个例子。 That will be 4500 in 30 days or 4650 in 31 days
  • 但是错误示例的问题在于,我们站在这里试图找出如何编写代码来匹配示例的总和。如果计算机求和,那真的很难做到4500,你的问题说它应该总和为 300 - 我们不知道哪一点是错误的。请更正您的问题,使其与自身保持一致
  • 当你说“我可以走得更远”时——你的意思是“我不能走得更远”吗?如果你能走得更远,你为什么不呢?
  • @CaiusJard 表格已更正。谢谢

标签: c# linq asp.net-core windows-services dapper


【解决方案1】:

您的陈述:

loans = conn.Query<DailyInterest>
    ("Select * from DailyInterest where BackgroundMonthly is Null");

在此声明之后,贷款不再为空。它可能是一个空序列,但它不为空。

改进#1:不要测试贷款中的元素数量。如果序列为空,则以下语句不会执行任何操作。此外,如果您只想知道是否至少有一笔贷款,那么为什么要 Count() 所有千笔贷款:

if (loans.Any())

这将在第一次贷款时停止枚举。 Count() 将枚举所有贷款。

var TotalEachLoanInterest = loans.GroupBy(x => x.LoanAccountNo)
    .Select(g =>g.Sum(x=>x.AmountPerDay));

这不是你想要的。您使用相同的 LoanAccountNo 进行贷款组。之后,您获取每组贷款,获取每个 Loan.AmountPerDay 并将它们相加。结果是一系列和。您不知道这笔款项所属的 LoanAccountNo。

改进#2:考虑overload of Enumerable.GroupBy that has a resultSelector

var loanInterestTotals = loans.GroupBy(
    loan => loan.LoanAccountNo,                // keySelector: group by same LoanAccountNo
    (accountNo, loansWithThisAccountNo) => new // resultSelector: take each loanAccountNo
    {                                          // and all loans with this accountNo
                                               // to make one new object
        LoanAccountNo = accountNo,
        TotalInterests = loansWithThisAccountNo
             .Select(loan => loan.AmountPerDay)
             .Sum(),
    });

结果:LoanAccountNo 的序列,每个都有 AmountPerDay 的总和。注意:尚未枚举序列!

您有一个表 TotalInterests。显然您已经知道如何填写属性 Day、AccountNo 和 Loan。您要做的就是知道如何填写属性 InterestsTotal

我不确定表interestTotal 是数据库表,还是您程序中的表。

改进 3: 保持数据库规范化

我不确定单独列出这些总数是否明智。如果这样做,您将失去一些数据库规范化。每当一个表中的一项兴趣发生变化时,您都必须更新interestsTotal 表。这应该表明您在多个表格中拥有相同的信息。

如果 InterestsTotal 是一个表,请考虑删除该表,并创建一个 Dapper SQL 或 LINQ 查询以从表 DailyLoanCalculations 中获取信息。您的存储库类的用户不会注意到计算了interestTotal 序列,而不是单独的表。

如果您真的想要一个单独的 InterestTotals 表,那么您应该在一次 SQL 更新调用中更新您的 InterestsTotal 表和 DailyLoanCalculations。这样您就可以确定没有人可以从 DailyLoanCalculations 中获取更新后的值,而 InterestTotals 中的值尚未更新。

LINQ 永远无法更改源,因此要更新 TotalInterests 表,您必须枚举。如果您使用实体框架,您可以获取所有必须在一次数据库访问中更新的 interestTotals:

foreach (var loanInterestTotal in loanInterestTotals)
{
     // entity framework method: fetch the TotalInterestToUpdate with the same LoandAccountNo
     var totalInterestToUpdate = dbContext.TotalInterests
         .Where(totalInterest => totalInterest.LoanAccountNo == loanInterestTotal.LoanAccountNo)
         .FirstOrDefault();
     totalInterestToUpdate.TotalInterest = loanInterestTotal.TotalInterests;
}
dbContext.SaveChanges()

如果您使用 Dapper,您可能可以一次性更新数据。你比我更懂 SQL。

如果 InterestsTotal 不是数据库表

在这种情况下,请考虑 TotalInterests 表与 TotalEachLoanInterest 的(组)联接。如果您想要在最终结果中还包含不在 TotalEachLoanInterest 中的 TotalInterest,您将需要 GroupJoin。否则一个简单的连接就足够了。

var result = TotalInterests.Join(TotalEachLoanInterests,
totalInterest => totalInterest.AccountNo,                 // from each totalIntere take the AccountNo,
totalEachLoanInterest => totalEachLoanInterest.AccountNo, // from each totalEachLoanInterest take the account no

(totalInterest, totalEachLoanInterest) => new             // when they match make one new
{
     Day = totalInterest.Day,
     AccountNo = totalInterest.AccountNo,
     Loan = TotalInterest.Loan

     TotalInterest = totalEeachLoanInterest.TotalInterests,
     Total = TotalInterest.Loan + totalEeachLoanInterest.TotalInterests,
});

顺便说一句:您注意到我仍然没有列举任何这些 LINQ 语句吗?

要获得最终结果,只需使用 ToList()。如果您的原始贷款序列为空,您的结果也将为空。因此不需要 Count() 原始贷款。

var endResult = result.ToList();

【讨论】:

  • 谢谢,非常深入的解释
【解决方案2】:

我必须承认,我有点困惑,为什么你要在 C# 中进行这个计算,而数据库看起来可以做到这一点:

    public void EndOfMonthDailyInterestCalculation()
    {
        IEnumerable<TotalInterest> loans = null;

        using (var conn = new SqlConnection(ConnectionString))
        {
            //conn.Open(); //you don't need to open the conn - Dapper knows how

            loans = conn.Query<TotalInterest>("Select MAX(day) as Day, AccountNo, Loan, SUM(InterestAmountPerDay) as TotalInterest, Loan + SUM(InterestAmountPerDay) as Total from DailyInterest WHERE BackgroundMonthly is Null GROUP BY AccountNo, Loan");

...

【讨论】:

  • 这在数据库中怎么可能?我怎样才能做到这一点
  • 我没有在数据库中提供代码吗?看看 SQL... 它生成了一个结果集,Dapper 应该能够解压缩到 TotalInterest 对象中,但所有数据都来自 DailyInterest 表
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2016-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多