简体   繁体   English

通过count()确实离开了join和group的Linq查询

[英]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: 以下是逐行说明:

  1. Get the rules from ruleCriteria ruleCriteria获取规则
  2. Group the criteria like { criteriaId, categoryId } by the ruleId and save it in rules 通过ruleId{ criteriaId, categoryId }{ criteriaId, categoryId } ruleId ,并将其保存在rules
  3. For each whole rule, check to see if the number of matching userCriteria is the same as the total number of rules, meaning the user has all the criteria. 对于每个完整规则,检查匹配的userCriteria的数量是否与规则的总数相同,这意味着用户具有所有条件。
  4. Select just the key for this group, which is the 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM