[英]Linq query that does left join and group by having count()
If I have a Rule which has many Criteria and a user selects multiple criteria, how do I write a linq query giving me all the rules where EVERY criteria within that rule exists with the user's selected criteria? 如果我有一个具有多个条件的规则并且用户选择了多个条件,那么如何编写一个linq查询,为我提供所有规则,其中该规则中的每个条件都存在于用户选择的条件中?
Here is how I'm doing it in SQL currently: 这是我目前在SQL中的方式:
Tables 表
rule:
ruleId int
categoryId int
ruleCriteria:
ruleId int,
criteriaId int
@userCriteria:
criteriaId int
categoryId int
Query 询问
SELECT
r.ruleId
FROM dbo.rule r
INNER JOIN dbo.ruleCriteria rc ON r.ruleId= rc.ruleId
LEFT OUTER JOIN @userCriteria uc
ON rc.criteriaId = uc.criteriaId
AND r.categoryId = uc.categoryId
GROUP BY r.ruleId
HAVING COUNT(rc.criteriaId) = COUNT(uc.criteriaId)
For the linq query, I'll have these objects (more denormalized, but I could put them in the same structure as the tables if that helps): 对于linq查询,我将拥有这些对象(更多非规范化,但如果有帮助,我可以将它们放在与表相同的结构中):
userCriteria:
criteriaId int
categoryId int
ruleCriteria:
ruleId int
categoryId int
criteriaId int
My goal is the same as the SQL query which is to get a distinct list of matching rules. 我的目标与获取不同匹配规则列表的SQL查询相同。 How would you do it?
你会怎么做?
I played around with some test data in LINQPad and this is what I came up with. 我在LINQPad中玩了一些测试数据,这就是我提出的。
from rc in ruleCriteria
group new { rc.criteriaId, rc.categoryId } by rc.ruleId into rules
where rules.Count() == userCriteria.Count(uc =>
rules.Contains(new { uc.criteriaId, uc.categoryId }))
select rules.Key
Here's the explanation, line-by-line: 以下是逐行说明:
ruleCriteria
ruleCriteria
获取规则 { criteriaId, categoryId }
by the ruleId
and save it in rules
ruleId
将{ criteriaId, categoryId }
等{ criteriaId, categoryId }
ruleId
,并将其保存在rules
userCriteria
is the same as the total number of rules, meaning the user has all the criteria. userCriteria
的数量是否与规则的总数相同,这意味着用户具有所有条件。 ruleId
. ruleId
。 This query generates better SQL than the other one, and it's more direct: 此查询生成的SQL比另一个更好,而且更直接:
from rc in ruleCriterias
group rc by rc.ruleId into rules
where rules.All(rc => userCriterias.Any(uc =>
uc.criteriaId == rc.criteriaId && uc.categoryId == rc.categoryId))
select rules.Key
You should make sure all the columns are NOT NULL
, because if they aren't, this has to generate extra SQL to check to see if things are null. 您应该确保所有列都是
NOT NULL
,因为如果它们不是,则必须生成额外的SQL以检查事物是否为空。
Unless I am misunderstanding (and therefore over simplyfying the problem) maybe the all .All() method is what you need. 除非我误解(因此只是简单地解决问题),否则所有.All()方法都是你需要的。
var userCriteria = ; //TODO: Build user criteria
var result = context.Rules.Where(r => r.CategoryId == userCriteria.CategoryId
&& r.RuleCriteria.All(rc => rc.id == userCriteria.CriteriaId));
This will only return rulls where all the containing criteria match your criteria. 这将只返回所有包含标准符合您标准的rulls。 I can't guarantee your sql though
我不能保证你的sql
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.