title: Match a non-specific number of records with LINQ
body: <p>I have a function on an ASP.NET website I'm building that allows users to register for multiple categories in a particular event. Site administrators need to be able to add these categories and also to add rules that govern which groups of categories attract a discount.</p>
  
  <p>My solution was to create a header table called CategorySelectionRule, which looks like this:</p>
  
  <pre><code>CREATE TABLE CategorySelectionRules (
  RuleId INTEGER IDENTITY PRIMARY KEY,
  RuleDescription VARCHAR(100),
  RuleMessage VARCHAR(255),
  Discount DECIMAL
  )
  </code></pre>
  
  <p>...and a detail table called CategorySelectionRuleDetail which looks like this:</p>
  
  <pre><code>CREATE TABLE CategorySelectionRuleDetail (
  RuleCategoryId INTEGER IDENTITY PRIMARY KEY,
  RuleId INTEGER REFERENCES CategorySelectionRules(RuleId),
  CategoryId INTEGER REFERENCES EntryCategory(CategoryId)
  }
  </code></pre>
  
  <p>So if someone enters category 1 and 4, the code checks for a rule that contains these categories (and only these categories), then returns the discount and message that apply.  My problem is that the code is getting out of control, as I need to allow for any number of categories in a rule, but I can't figure out how to do that without a select case that joins the detail table back on itself, like this, which only works for rules with two categories (Oh, and it doesn't actually work):</p>
  
  <pre><code>categoryRuleId = (From r1 In _db.CategorySelectionRuleDetail _
                    Join r2In _db.CategorySelectionRuleDetail _
                      On r1.RuleId Equals r2.RuleId _
                    Where ((r1.CategoryId = matchCategory1 _
                    AndAlso r2.CategoryId = matchCategory2) _
                    OrElse (r1.CategoryId = matchCategory2 _
                    AndAlso r2.CategoryId = matchCategory1)) _
                    AndAlso !(From r3 In _db.CategorySelectionRuleDetail  _
                              Group r3 By r3.RuleId Into g_
                              Where g.Count(RuleId) &gt; 2).Contains(r1.RuleId) _
                    Select r1.RuleId).FirstOrDefault()
  </code></pre>
  
  <p>Is there a better way to do this that I'm not seeing? I feel like the data structure is right, but I'm sure there's an easier way to match the data I want without resorting to separate LINQ statements for each number of categories.</p>