2

データベースで「タイプ」を示す良い方法は何ですか?

Action多数の子クラスに継承される基本クラスがあります。には、 というデータベース内のテーブルの同等の列に対応する などのメンバーActionがあります。したがって、テーブルは次のようになります。IdNameactionaction

id | name | type 

type列は、それが何のアクションであるかを示します。私のコードでは、それらは parent から派生した子クラスに対応していますActionクラスのタイプをデータベースのタイプフィールドに保存するにはどうすればよいですか?

db の type 列は、任意のデータ型にすることができます。

オプション:

  1. action.GetType().ToString()db に文字列として保存します。そして、リフレクションを使用して型の文字列表現を元の型に変換することにより、db からアクション型を取得します。しかし、クラス名が将来変更された場合、これは問題になります。

  2. 各子クラスを示す列挙型を作成しTypeAttribute、次のように で装飾します。

    public abstract class Action
    {
        public enum Kind 
        {
            [Type(typeof(ControlAction))]
            ControlAction = 1, 
    
            [Type(typeof(UpdateAction))]
            UpdateAction = 2, 
    
            etc 
        }
    
        public abstract Kind ActionType { get; }
    }
    
    public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } }
    public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } }
    //etc
    

    これは良さそうですが、ここから先はクラスごとに列挙型を作成する必要があります。そして、やるべきことが少し多すぎるように感じます。

  3. <int, Type>クラスを値に結び付ける別の静的ハッシュ テーブルを作成しintます。少し読みにくいかもしれません。

これに対するより良い解決策はありますか?

4

3 に答える 3

3

設計的にはよりクリーンなように見えるため、ハッシュテーブルを使用して3番目のソリューションから進みます。そして、その管理をデータベースに委任します!

結局のところ、リレーショナル データベースが最も優れているのは、2 つのエンティティ (あなたの場合はアクションとタイプ) 間の関係を作成することではないでしょうか? その他の利点は、正規化されたスキーマが得られることです (確かに、これまでのところ、型テーブルには 1 つの列、つまりその名前しかありませんが、正規化により、将来必要になった場合に型に属性を簡単に追加できます。そのため、デザインとしてすっきりしています)。

スキーマは次のようになります。

アクションテーブル

action_id(PK) | name | type_id (int, FK to Type table)

型式表

type_id(PK) | type_name

これで、クラスの名前が将来変更されても安全です (文字列型の最初の命題からの懸念)。実際、対応するテーブル行のtype_name値を変更するだけで、すべての行が によってこの行にリンクされます。一度作成されると変更されることはありません (「ビジネス上の意味」を保持していないため、ここでは問題ありません)。 .TypeActiontype_id

また、ハッシュ テーブル ( PK)Typeのキーを管理するのは RDMBS の責任であるため、3 (テーブル) のハッシュ テーブルを読み取り可能な形式で保持します。type_id

intクラスを列に対応する値に関連付ける必要はありませんが、クラスの型 ( ) に対して参照してテーブルtype_idからフェッチする必要があることに注意してください。Typetype_idtype_name

于 2013-08-25T09:53:53.097 に答える
2

オプション 2 を使用することになりましたが、属性の混乱は少なくなりました。このようなもの:

public abstract class Action
{
    public enum Kind 
    {
        ControlAction = 1, 

        UpdateAction = 2, 

        etc 
    }

    public abstract Kind ActionType { get; }
}

public class ControlAction : Action { public override Kind ActionType { get { return Kind.ControlAction; } } }
public class UpdateAction : Action { public override Kind ActionType { get { return Kind.UpdateAction; } } }

これの最大の利点は、(より多くのタイピングを意味する場合でも)、数値をクラス type に関連付けることを強制することです。

intへのクラスは次のとおりです。

var value = (int)instance.ActionType;

とても早い。

しかし、int をクラス インスタンス (またはクラス タイプ) に変換するには、各サブ アクション タイプのインスタンスを作成し、そのActionTypeプロパティを比較して入力 int 値と一致させる必要があります。これは遅くなります。しかし、何かをキャッシュして高速化することはできます。次のようなもの

static readonly Dictionary<Action.Kind, Type> actionTypes = 
   GetDefaultInstanceOfAllActions().ToDictionary(x => x.ActionType, x => x.GetType());
public static Action ToAction(this Action.Kind value)
{
    return (Action)Activator.CreateInstance(actionTypes[value]);
}

GetDefaultInstanceOfAllActions、すべてのタイプのアクションを取得するために(1回)リフレクションを行います(そのためにこの回答のようなものを使用します)。式ルートを使用して、インスタンス化を高速化することもできます。

メリット:

  1. 新しいクラス (属性なし) を作成する際の手間が軽減されます。

  2. int がクラス型に関連付けられるように強制します。

  3. 適切なキャッシングで適度に高速。

于 2013-09-13T06:37:57.440 に答える
0

私はあなたの最初のオプションに行き、リフレクションを使用します。既存のクラス名を変更するのではなく、新しいアクション タイプを追加する可能性が高いため、リフレクションを使用してタイプを簡単にシリアル化できると便利です。次に、アクションをシリアル化し、タイプ文字列から復元するためのユーティリティ クラスを作成します。

于 2013-08-26T10:04:04.307 に答える