Linq查询,通过count()进行左连接和分组

本文关键字:连接 查询 通过 count Linq | 更新日期: 2023-09-27 18:02:29

如果我有一个规则,其中有许多条件和用户选择多个条件,我如何编写一个linq查询给我所有的规则,其中每个条件在该规则中存在与用户选择的条件?

这是我目前在SQL中如何做的:

<<p> 表/strong>
rule:
  ruleId int
  categoryId int
ruleCriteria:
  ruleId int,
  criteriaId int
@userCriteria:
  criteriaId int
  categoryId int
查询

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)

对于linq查询,我将使用这些对象(更非规范化,但如果有帮助,我可以将它们放在与表相同的结构中):

userCriteria:
  criteriaId int
  categoryId int
ruleCriteria:
  ruleId int
  categoryId int
  criteriaId int

我的目标与SQL查询相同,即获得匹配规则的不同列表。你会怎么做?

Linq查询,通过count()进行左连接和分组

这个查询比另一个查询生成更好的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

您应该确保所有列都是NOT NULL,因为如果它们不是,这必须生成额外的SQL来检查是否为空

我在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

下面是逐行解释:

  1. ruleCriteria
  2. 获取规则
  3. { criteriaId, categoryId }等标准按ruleId分组保存在rules
  4. 对于每条完整的规则,检查匹配userCriteria的数量是否与规则的总数相同,这意味着用户拥有所有的条件。
  5. 只选择此组的密钥,即ruleId

除非我误解了(因此过度简化了问题),否则您可能需要all . 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));

这将只返回所有包含条件与您的条件匹配的规则。我不能保证你的sql