问题
问题在于这句话:
where tmp.PayAmount != tmp1.DepositAmount //the culprit
并且由于tmp1 被定义为单个子事务,该语句将导致等于错误值:
展示台:
1000 != 600 //(result: true -> selected) comparing parent 1 and child 1
1000 != 400 //(result: true -> selected) comparing parent 1 and child 2
3000 != 1000 //(result: true -> selected) comparing parent 2 and child 3
3000 != 1000 //(result: true -> selected) comparing parent 2 and child 4
3000 != 1000 //(result: true -> selected) comparing parent 2 and child 5
5000 != 2000 //(result: true -> selected) comparing parent 2 and child 5
//However, you do not want it to behave like this actually
但你想要的却是:
展示台:
1000 != (600 + 400) //(result: false -> not selected) comparing parent 1 and child 1 & 2, based on the TransactionId
3000 != (1000 + 1000 + 1000) //(result: false -> not selected) comparing parent 2 and child 3, 4, & 5, based on the TransactionId
5000 != (2000) //(result: true -> selected) comparing parent 3 and child 6, based on the TransactionId
6000 != nothing paid //(result: true -> selected) comparing parent 3 with the whole childTransaction and found there isn't any payment made
因此,您应该将tmp1 设置为一个集合子项,而不是单个子项。
解决方案
未付交易
像这样更改您的代码:
var data = (from tmp in context.ParentTransaction
join tmp1 in context.ChildTransaction.GroupBy(x => x.TransactionId) //group this by transaction id
on tmp.TransactionId equals tmp1.Key //use the key
where tmp.PayAmount > tmp1.Sum(x => x.DepositAmount) //get the sum of the deposited amount
select tmp)
.Union( //added after edit
(from tmp in context.ParentTransaction
where !context.ChildTransaction.Select(x => x.TransactionId).Contains(tmp.TransactionId)
select tmp)
);
说明
这一行:
join tmp1 in context.ChildTransaction.GroupBy(x => x.TransactionId) //group this by transaction id
在Linq 中使用GroupBy,这行代码使tmp1 成为一个组 孩子,而不是一个单个 孩子,并且理所当然地基于它的外键,即TransactionId。
然后这一行:
on tmp.TransactionId equals tmp1.Key //use the key
我们简单地将tmp.TransactionId等同于儿童组密钥tmp1.Key
然后下一行:
where tmp.PayAmount > tmp1.Sum(x => x.DepositAmount) //get the sum of the deposited amount
获取孩子的DepositAmount而不是单个孩子的DepositAmount的总和值,小于父级中的PayAmount,然后
select tmp
选择满足上述所有条件的所有父交易。这样,我们就完成了一半。
下一步是考虑发生在父节点中但不在子节点中的事务。这也被认为是无偿的。
我们可以使用Union 将第一个query 与第二个query 的结果结合起来
.Union( //added after edit
(from tmp in context.ParentTransaction
where !context.ChildTransaction.Select(x => x.TransactionId).Contains(tmp.TransactionId)
select tmp)
);
这会选择父事务中存在但子事务中根本不存在的任何内容(因此被视为未付款)。
您将获得正确的data,其中包含未全额支付的ParentTransaction 行,无论其TransactionId 是否存在于子交易中的父交易。
付费交易
至于付费交易,只需将查询从>改为<=即可:
var datapaid = (from tmp in context.ParentTransaction
join tmp1 in context.ChildTransaction.GroupBy(y => y.TransactionId)
on tmp.TransactionId equals tmp1.Key
where tmp.PayAmount <= tmp1.Sum(x => x.DepositAmount)
select tmp);
结合
我们可以像这样进一步简化上面的查询:
var grp = context.ChildTransaction.GroupBy(y => y.TransactionId);
var data = (from tmp in context.ParentTransaction
join tmp1 in grp //group this by transaction id
on tmp.TransactionId equals tmp1.Key //use the key
where tmp.PayAmount > tmp1.Sum(x => x.DepositAmount)
select tmp)
.Union((
from tmp in context.ParentTransaction
where !context.ChildTransaction.Select(x => x.TransactionId).Contains(tmp.TransactionId)
select tmp));
var datapaid = (from tmp in context.ParentTransaction
join tmp1 in grp
on tmp.TransactionId equals tmp1.Key
where tmp.PayAmount <= tmp1.Sum(x => x.DepositAmount)
select tmp);