LINQ GROUPBY 和 SUM with Dapper 可以实现吗?
Can LINQ GROUPBY and SUM with Dapper achieve this?
我想要实现的是每天计算利息 [DailyLoanCalculation] 并在月底获得每个帐户的总计并保存在 [Total-interest] Table 中。每个月都会发生同样的事情
我有一个 table 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
};
}
}
}
}
如果有更好的解决方法请帮帮我
谢谢
我得承认,我有点不明白你为什么要在 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");
...
您的声明:
loans = conn.Query<DailyInterest>
("Select * from DailyInterest where BackgroundMonthly is Null");
在此声明之后,贷款不再为空。它可能是一个空序列,但它不是空的。
改进 #1: 不要测试贷款中的元素数量。如果序列为空,则以下语句不会执行任何操作。此外,如果你只想知道是否至少有一笔贷款,为什么要 Count() all thousand loans:
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 的总和。注:序列尚未枚举!
您有 table 个 TotalInterests。显然您已经知道如何填写属性 Day、AccountNo 和 Loan。您想要做的就是知道如何填写 属性 InterestsTotal
我不确定 table interestsTotal 是数据库 table 还是您程序中的 table。
改进 3: 保持数据库规范化
我不确定将这些总数单独 table 是否明智。如果这样做,您将失去一些数据库规范化。每当一个 table 中的一项兴趣发生变化时,您就必须更新 interestsTotal table。这应该表明您在几个 table 秒内拥有相同的信息。
如果 InterestsTotal 是 table,请考虑删除 table,并创建一个 Dapper SQL 或从 table DailyLoanCalculations 获取信息的 LINQ 查询。您的存储库 class 的用户不会注意到计算了 interestsTotal 序列,而不是单独的 table.
如果您真的想要一个单独的 InterestTotals table,那么您应该在一个 SQL 更新调用中更新您的 InterestsTotal table 和 DailyLoanCalculations。这样你就可以确定没有人可以从 DailyLoanCalculations 获得更新的值,而来自 InterestTotals 的值还没有更新。
LINQ 永远无法更改源,因此要更新 TotalInterests table,您必须枚举。如果您使用 entity framework,您可以获取所有必须在一次数据库访问中更新的 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 不是数据库 table
在那种情况下,考虑 TotalInterests table 与 TotalEachLoanInterest 的(组)连接。如果您还想在最终结果中得到不在 TotalEachLoanInterest 中的 TotalInterests,您将需要 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();
我想要实现的是每天计算利息 [DailyLoanCalculation] 并在月底获得每个帐户的总计并保存在 [Total-interest] Table 中。每个月都会发生同样的事情
我有一个 table 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
};
}
}
}
}
如果有更好的解决方法请帮帮我 谢谢
我得承认,我有点不明白你为什么要在 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");
...
您的声明:
loans = conn.Query<DailyInterest>
("Select * from DailyInterest where BackgroundMonthly is Null");
在此声明之后,贷款不再为空。它可能是一个空序列,但它不是空的。
改进 #1: 不要测试贷款中的元素数量。如果序列为空,则以下语句不会执行任何操作。此外,如果你只想知道是否至少有一笔贷款,为什么要 Count() all thousand loans:
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 的总和。注:序列尚未枚举!
您有 table 个 TotalInterests。显然您已经知道如何填写属性 Day、AccountNo 和 Loan。您想要做的就是知道如何填写 属性 InterestsTotal
我不确定 table interestsTotal 是数据库 table 还是您程序中的 table。
改进 3: 保持数据库规范化
我不确定将这些总数单独 table 是否明智。如果这样做,您将失去一些数据库规范化。每当一个 table 中的一项兴趣发生变化时,您就必须更新 interestsTotal table。这应该表明您在几个 table 秒内拥有相同的信息。
如果 InterestsTotal 是 table,请考虑删除 table,并创建一个 Dapper SQL 或从 table DailyLoanCalculations 获取信息的 LINQ 查询。您的存储库 class 的用户不会注意到计算了 interestsTotal 序列,而不是单独的 table.
如果您真的想要一个单独的 InterestTotals table,那么您应该在一个 SQL 更新调用中更新您的 InterestsTotal table 和 DailyLoanCalculations。这样你就可以确定没有人可以从 DailyLoanCalculations 获得更新的值,而来自 InterestTotals 的值还没有更新。
LINQ 永远无法更改源,因此要更新 TotalInterests table,您必须枚举。如果您使用 entity framework,您可以获取所有必须在一次数据库访问中更新的 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 不是数据库 table
在那种情况下,考虑 TotalInterests table 与 TotalEachLoanInterest 的(组)连接。如果您还想在最终结果中得到不在 TotalEachLoanInterest 中的 TotalInterests,您将需要 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();