我们说我有一个共同的基类/接口
interface ICommand
{
void Execute();
}
然后有一些命令从这个接口继承。
class CommandA : ICommand
{
int x;
int y;
public CommandA(int x, int y)
{ ... }
public void Execute () { ... }
}
class CommandB : ICommand
{
string name;
public CommandB(string name)
{ ... }
public void Execute () { ... }
}
现在我想使用常用方法将这些命令存储在数据库中,然后将所有这些命令从DB加载到List<ICommand>
并执行它们的Execute方法。
现在我在数据库中只有一个名为命令的表,这里我存储了对象的字符串序列化。基本上表中的列是:id|commandType|commaSeparatedListOfParameters
。虽然这非常简单并且适用于加载所有命令,但我无法使用子字符串和其他模糊方法轻松查询命令。我想有一个简单的SELECT id,x,y FROM commandA_commands WHERE x=...
方法,同时有一个从命令表加载所有命令的通用方法(我想这将是某种命令的UNION / JOIN,commandB_commands等等) )。
重要的是,添加新命令不需要在DB中手动调整或手动创建序列化/解析方法。我有很多它们,并且新的一直被添加和删除。我不介意创建一个命令+表+查询生成工具,但这是否是最佳解决方案所必需的。
我能想到的最好的是一个像id|commandType|param1|param2|param3|etc..
这样的常见表,它比我当前的解决方案要好得多(实际上更糟糕?),因为许多命令需要空参数,数据类型将是因此我不得不再次使用常见的字符串转换,并将每个字段的大小调整为最大的命令。
数据库是SQL Server 2008
找到类似的问题答案 0 :(得分:13)
您可以使用ORM将命令继承映射到数据库。例如,您可以使用ORM提供的“每个层次结构表”技术(例如:实体框架,nHibernate等)。 ORM将在您检索它们时实例化正确的子类。
以下是首先在实体框架代码中执行此操作的示例
abstract class Command : ICommand
{
public int Id {get;set;}
public abstract void Execute();
}
class CommandA : Command
{
public int X {get;set;}
public int Y {get;set;}
public override void Execute () { ... }
}
class CommandB : Command
{
public string Name {get;set;}
public override void Execute () { ... }
}
引用EF 4.1 Code First Walkthrough以使用EF配置此模型。
如果您的命令采用截然不同的参数集,则可以考虑使用“每类型表”继承建模。在这里,你将支付一些重要的性能损失,因为很多联合和表联接都涉及到这一点。
替代方法是将Command参数存储为您手动(de)序列化的XML配置。这样,您可以将所有命令保存在单个表中,而不会牺牲性能。同样,这有一个缺点,你无法使用命令参数进行过滤。
每种方法都有其优点和缺点。您可以选择适合您要求的策略。
答案 1 :(得分:5)
这个问题很常见,我没有看到没有缺点的解决方案。在数据库中精确存储对象层次结构的唯一选择是使用一些NoSQL数据库。
但是,如果强制要求关系数据库,我通常采用这种方法:
在你的情况下,我会创建:
查看命令,类似于:
select cb.ID, a.X, a.Y, b.Name
from CommandBase cb
left outer join CommandA a on a.ID = cb.ID
left outer join CommandB b on b.ID = cb.ID
这种方法的优点在于它反映了你的班级结构。它易于理解和使用。
缺点是,当你添加新类时会变得越来越麻烦,很难对多层次的层次结构进行建模,如果有很多后代,视图可以长达一英里。
就个人而言,如果我知道子类的数量相对较小且相对固定,我会使用这种方法,因为它需要为每个新类型创建(和维护)一个新表。但是,该模型非常简单,因此可以创建一个可以为您创建和维护的工具/脚本。
答案 2 :(得分:1)
我们越来越多地在SQL中使用XML来处理软数据。查询(使用XPath)可能有点痛苦,但它允许我们每行存储元数据,根据模式进行验证等。
然后可以通过代码解析XML,并且可以通过反射将参数与反序列化对象中的参数进行匹配。
实际上,这复制了ORM功能,但是使用平面数据库结构,简化了查询,甚至可以通过XPath查询参数。
记住孩子,观点是邪恶的。