我有一个名为两个交易表ParentTransaction和ChildTransaction其中TransactionId
的ParentTransaction将作为外来ChildTransaction的TransactionId
.
现在我想获得payamount
未完成的ParentTransaction的所有TransactionId .
从下面的输出我想要事务Id 3的记录,因为只有1000支付了transactionid
3而不是5000.
我有一个这样的表:
Transactionid(p.k) PayAmount 1 1000 2 3000 3 5000 4 6000
ChildTransaction
Id TransactionId(F.k) DepositAmount 1 1 600 2 1 400 3 2 1000 4 2 1000 5 2 1000 6 3 2000
这是我的查询:
var data = (from tmp in context.ParentTransaction join tmp1 in context.ChildTransaction on tmp.Transactionid equals tmp1.Transactionid where tmp.PayAmount !=tmp1.DepositAmount select tmp);
但在这里我得到了交易ID 1和2,尽管他们的交易已经完成了两个部分,即600和400的交易ID 1.
查询语言的一般概念是表达所需的结果,而不是如何获得它.
将它应用于您的场景会导致这样的简单查询
var query = context.ParentTransaction .Where(t => t.PayAmount != context.ChildTransaction .Where(ct => ct.TransactionId == t.TransactionId) .Sum(ct => ct.DepositAmount));
如果您使用EF和正确的模型导航属性,它甚至会很简单
var query = context.ParentTransaction .Where(t => t.PayAmount != t.ChildTransactions.Sum(ct => ct.DepositAmount));
可以说,与@Vadim Martynov的回答相比,上述内容效率低下.好吧,可能是的,可能不是.Vadim试图强制执行一个特定的执行计划,我可以理解 - 当实际遇到查询性能问题时,我们必须做这些事情.但这并不自然,只有在我们遇到性能问题时才应该是最后的手段.在大多数情况下,查询提供程序和SQL查询优化器将为我们做(并且正在做)这项工作,因此我们不需要考虑是否需要使用join
vs subquery
等.
我不确定这!=
是否是最好的价值.这是一个>
检查和分组的解决方案:
var expectedValue = context.ChildTransaction .GroupBy(t => t.TransactionId, (key, group) => new { TransactionId = key, Deposit = group.Sum(e => e.Deposit) }) .Join(context.ParentTransaction, grouped => grouped.TransactionId, transaction => transaction.TransactionId, (group, transaction) => new { Transaction = transaction, group.Deposit }) .Where(result => result.Transaction.PayAmount > result.Deposit) .Select(result => result.Transaction);
可以像下一个要求那样以声明方式读取此查询:
通过TransactionId
和为每个组的子事务的组集合检索具有字段TransactionId =分组键(== TransactionId)和存款的匿名类型对象,存储是具有相同TransactionId的行的存款的总和.
加入组从第1部分到表PaerntTransaction
的TransactionId
字段.对于每一个连接一对检索匿名类型与字段事务从对象==交易ParentTransactions
表和存款其是从第1部分设置其与同一矿床总和存款TransactionId
从ChildTransactions
表.
仅从结果集中过滤掉PayAmount比存款总和更大的对象.
仅返回ParentTransaction
每个已过滤行的对象.
这是SQL优化的方案,因为连接,过滤和分组可以防止嵌套查询,这些查询可以在其他情况下添加到实际执行计划中,从而降低性能.
UPDATE
要解决没有存款的交易问题,您可以使用LEFT JOIN:
var expectedValue = from parent in context.ParentTransaction join child in context.ChildTransaction on parent.TransactionId equals child.TransactionId into gj from subset in gj.DefaultIfEmpty() let joined = new { Transaction = parent, Deposit = subset != null ? subset.Deposit : 0 } group joined by joined.Transaction into grouped let g = new { Transaction = grouped.Key, Deposit = grouped.Sum(e => e.Deposit) } where g.Transaction.PayAmount > g.Deposit select g.Transaction;
与LINQ方法链相同的查询:
var expectedValue = context.ParentTransaction .GroupJoin(context.ChildTransaction, parent => parent.TransactionId, child => child.TransactionId, (parent, gj) => new { parent, gj }) .SelectMany(@t => @t.gj.DefaultIfEmpty(), (@t, subset) => new { @t, subset }) .Select(@t => new { @t, joined = new { Transaction = @t.@t.parent, Deposit = @t.subset != null ? @t.subset.Deposit : 0 } }) .GroupBy(@t => @t.joined.Transaction, @t => @t.joined) .Select(grouped => new { grouped, g = new { Transaction = grouped.Key, Deposit = grouped.Sum(e => e.Deposit) } }) .Where(@t => @t.g.Transaction.PayAmount > @t.g.Deposit) .Select(@t => @t.g.Transaction);
现在,您检索所有父事务并将其与子事务连接,但如果没有子事务,则以Deposit == 0
类似方式使用和分组已连接的实体ParentTransaction
.