2

在数据库中表示“类型”的好方法是什么?

我有一个Action由许多子类继承的基类。Action有成员 like等IdName它们都对应于数据库中名为action. 所以action表看起来像这样:

id | name | type 

type列表示它是什么操作。在我的代码中,它们对应于派生自 parent 的子类Action。现在如何将的类型保存到数据库中的类型字段

db 中的类型列可以是任何数据类型。

选项:

  1. 在数据库中另存action.GetType().ToString()为字符串。并通过使用反射将类型的字符串表示形式转换为其原始类型,从 db 中获取操作类型。但是,如果将来类名发生变化,这将是有问题的。

  2. 创建一个枚举来表示每个子类并用 a 装饰它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

I would go from the 3rd solution with a hash-table, as it does seem to be the cleaner design-wise. And I would delegate its management to the database!

After all, isn't this what relational databases excel at the most, creating relations between two entities (in your case, action and type)? Other advantage is you end up with a normalized schema (sure, so far, there is only one column to the type table, namely its name, but normalizing allows you to easily add additional attributes to the types should you need them in the future, which is why it is cleaner as a design).

The schema would be something like this:

Action table

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

Type table

type_id(PK) | type_name

Now you are safe if the name of a class changes in the future (concern from your first proposition with string type). Indeed, all you would do is change the type_name value in the corresponding Type table row and all your Action rows would still be linked to this row by the type_id, which never changes once created (no problem here, as it does not hold any "business meaning").

And you have your hash-table from 3 (the Type table) in a readable format as it is the RDMBS's responsibility to manage the keys of the hash-table (the type_id PK).

Note that you won't have to tie your class to an int value corresponding to the type_id column, but rather fetch from the Type table the type_id by looking it up against the Class type (type_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. 创建新类(无属性)时减少麻烦。

  2. 强制将 int 绑定到类类型。

  3. 速度适中,有足够的缓存。

于 2013-09-13T06:37:57.440 回答
0

我会选择你的第一个选项并使用反射。您似乎更有可能想要添加新的操作类型而不是更改现有的类名,因此使用反射序列化类型的便利性更有用。然后,您可以只使用一个实用程序类来序列化操作并从它们的类型字符串中恢复它们。

于 2013-08-26T10:04:04.307 回答