1

私が構築している ASP.NET Web サイトには、ユーザーが特定のイベントで複数のカテゴリに登録できる機能があります。サイト管理者は、これらのカテゴリを追加できる必要があり、また、カテゴリのどのグループが割引を引き付けるかを管理するルールも追加できる必要があります。

私の解決策は、次のような CategorySelectionRule というヘッダー テーブルを作成することでした。

CREATE TABLE CategorySelectionRules (
RuleId INTEGER IDENTITY PRIMARY KEY,
RuleDescription VARCHAR(100),
RuleMessage VARCHAR(255),
Discount DECIMAL
)

...そして、次のような CategorySelectionRuleDetail という詳細テーブル:

CREATE TABLE CategorySelectionRuleDetail (
RuleCategoryId INTEGER IDENTITY PRIMARY KEY,
RuleId INTEGER REFERENCES CategorySelectionRules(RuleId),
CategoryId INTEGER REFERENCES EntryCategory(CategoryId)
}

したがって、誰かがカテゴリ 1 と 4 を入力すると、コードはこれらのカテゴリ (およびこれらのカテゴリのみ) を含むルールをチェックし、適用される割引とメッセージを返します。私の問題は、ルールで任意の数のカテゴリを許可する必要があるため、コードが制御不能になっていることですが、詳細テーブルを結合する選択ケースなしではそれを行う方法がわかりません。このように、2 つのカテゴリを持つルールでのみ機能します (ああ、実際には機能しません)。

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) > 2).Contains(r1.RuleId) _
                  Select r1.RuleId).FirstOrDefault()

私が見ていないこれを行うためのより良い方法はありますか? データ構造は正しいと思いますが、カテゴリの数ごとに個別の LINQ ステートメントに頼らずに、必要なデータを一致させる簡単な方法があると確信しています。

4

1 に答える 1

0

この Linq ステートメントは、あなたが望むことを行います:

var rules = from r in db.CategorySelectionRules
                   where r.CategorySelectionRuleDetails.Count() == selectedCategories.Count &&
                         r.CategorySelectionRuleDetails.Where(cr => selectedCategories.Contains(cr.CategoryId.Value)).Count() == selectedCategories.Count
                   select r;

同じカテゴリ要件を持つ 2 つの異なるルールがある場合、これは複数のルールも返します。

プログラム全体:

データベース構造の生成に使用される SQL

CREATE TABLE EntryCategory ( 
CategoryId INTEGER IDENTITY PRIMARY KEY, 
CategoryDescription VARCHAR(100)
) 

CREATE TABLE CategorySelectionRules ( 
RuleId INTEGER IDENTITY PRIMARY KEY, 
RuleDescription VARCHAR(100), 
RuleMessage VARCHAR(255), 
Discount DECIMAL 
) 

CREATE TABLE CategorySelectionRuleDetail ( 
RuleCategoryId INTEGER IDENTITY PRIMARY KEY, 
RuleId INTEGER REFERENCES CategorySelectionRules(RuleId), 
CategoryId INTEGER REFERENCES EntryCategory(CategoryId) 
)

C# プログラム (コンソール アプリ)

namespace StackOverFlowTesting
{
  using System;
  using System.Collections.Generic;
  using System.Linq;

  class Program
  {
    static void Main(string[] args)
    {
      //Load Data
      using (var db = new DatabaseDataContext())
      {
        //Check to see if the data has already been loaded
        if (db.EntryCategories.Count() == 0)
        {
          //Load in inital categories
          db.EntryCategories.InsertOnSubmit(new EntryCategory() { CategoryDescription = "Category1" });
          db.EntryCategories.InsertOnSubmit(new EntryCategory() { CategoryDescription = "Category2" });
          db.EntryCategories.InsertOnSubmit(new EntryCategory() { CategoryDescription = "Category3" });

          //Load in inital rules
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule1", RuleMessage = "Rule1 Message", Discount = .5M });
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule2", RuleMessage = "Rule2 Message", Discount = .5M });
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule3", RuleMessage = "Rule3 Message", Discount = .5M });
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule4", RuleMessage = "Rule4 Message", Discount = .5M });
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule5", RuleMessage = "Rule5 Message", Discount = .5M });
          db.CategorySelectionRules.InsertOnSubmit(new CategorySelectionRule() { RuleDescription = "Rule6", RuleMessage = "Rule6 Message", Discount = .5M });

          //Link up the categories and rules
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 1, RuleId = 1 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 1, RuleId = 2 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 2, RuleId = 2 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 1, RuleId = 3 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 2, RuleId = 3 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 3, RuleId = 3 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 1, RuleId = 4 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 3, RuleId = 4 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 2, RuleId = 5 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 3, RuleId = 5 });
          db.CategorySelectionRuleDetails.InsertOnSubmit(new CategorySelectionRuleDetail() { CategoryId = 3, RuleId = 6 });

          //Populate the database with our temp records
          db.SubmitChanges();
        }

        /** Different ways of testing **/
        //var selectedCategories = new List<int>() { 1 }; //Rule 1
        var selectedCategories = new List<int>() { 1, 2 }; //Rule 2
        //var selectedCategories = new List<int>() { 1, 2,3 }; //Rule 3
        //var selectedCategories = new List<int>() { 1, 3 }; //Rule 4
        //var selectedCategories = new List<int>() { 2, 3 }; //Rule 5
        //var selectedCategories = new List<int>() { 3 }; //Rule 6

        var rules = from r in db.CategorySelectionRules
                   where r.CategorySelectionRuleDetails.Count() == selectedCategories.Count &&
                         r.CategorySelectionRuleDetails.Where(cr => selectedCategories.Contains(cr.CategoryId.Value)).Count() == selectedCategories.Count
                   select r;

        if (rules.Count() == 0)
        {
          Console.WriteLine("No rule found");
        }
        else
        {
          Console.WriteLine(rules.Count().ToString() + " Rules Found");
          foreach (var rule in rules)
          {
            Console.WriteLine(rule.RuleDescription);
          }          
        }
        Console.ReadLine();
      }
    }
  }
}
于 2012-10-02T17:07:00.493 に答える