在数据库中保存类的最佳方法?

时间:2013-08-25 09:27:44

标签: c# database-design types

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

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

id | name | type 

type列表示它是什么动作。在我的代码中,它们对应于从父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 个答案:

答案 0 :(得分:2)

我会使用哈希表从第3个解决方案开始,因为它看起来似乎更清晰。我会将其管理权委托给数据库!

毕竟,这不是关系数据库最擅长的,在两个实体之间建立关系(在你的情况下,行动和类型)?其他优点是你最终得到了一个规范化的模式(当然,到目前为止,类型表只有一列,即它的名称,但规范化允许你在将来需要的时候轻松地为这些类型添加其他属性,这就是它作为设计更清洁的原因。)

架构将是这样的:

行动表

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

输入表格

type_id(PK) | type_name

现在,如果将来某个类的名称发生变化,您将会感到安全(请注意您的第一个命题是字符串类型)。实际上,您要做的只是更改相应type_name表格行中的Type值,而Action行仍会通过type_id链接到此行。 从未更改一旦创建(这里没有问题,因为它没有任何“商业含义”)。

你有一个可读格式的3(Type表)哈希表,因为RDMBS负责管理哈希表的密钥(type_id PK)。

请注意,您不必将您的课程与int列对应的type_id值绑定,而是从Type表中获取type_id查看类类型(type_name)。

答案 1 :(得分: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; } } }

这方面的最大优点是(即使它意味着更多的输入),它强制使用与类类型相关联的数值

现在class to 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做了一些反思(一次)以获得所有类型的操作(我使用this answer之类的东西)。我甚至可以通过going the expression route.

使实例化更快

好处:

  1. 创建新类时没有麻烦(没有属性)。

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

  3. 适度缓存,速度适中。

答案 2 :(得分:0)

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