所以,我喜欢关于设计类和存储数据的最佳方法的一些反馈,以满足以下情况:
我有一个名为Tasks的界面,如下所示:
interface ITask
{
int ID{ get; set;}
string Title {get; set;}
string Description{get; set;}
}
我希望能够创建不同类型的任务,具体取决于谁在使用该应用程序...例如:
public class SoftwareTask: ITask
{
//ITask Implementation
string BuildVersion {get; set;}
bool IsBug {get; set;}
}
public class SalesTask: ITask
{
//ITask Implementation
int AccountID {get; set;}
int SalesPersonID {get; set;}
}
所以我看到它的方式我可以在数据库中创建一个Tasks表,其中包含与ITask接口匹配的列,以及在单个列中推送更具体任务的所有属性的列(或者甚至可以序列化任务对象分成一栏)
OR
为每个任务类型创建一个表,以存储该类型唯一的属性。
我现在真的不喜欢任何一种解决方案。我需要能够创建不同类型的任务(或任何其他类),它们通过基本接口共享一组共同的核心属性和方法,但能够以易于搜索的方式存储其独特属性并且不必为每种类型创建一堆数据库表进行过滤。
我开始研究插件架构和策略模式,但我没有看到哪里可以解决存储和访问数据的问题。
非常感谢任何帮助或推动正确的方向!
答案 0 :(得分:3)
你可能应该从ORM处理这个方面起带头作用,比如TPH/TPC/TPT
鉴于ITask是一个接口,你应该选择TPC(每个混凝土类型的表)。当你把它作为基类时,TPT和TPH也是选项。
答案 1 :(得分:3)
您的第二种方法(每种类型一个表)是解决此问题的规范方法 - 虽然它需要更多的努力来实现它更适合大多数数据库的关系模型并保留数据的一致和有凝聚力的表示。每种具体类型使用一个表的方法效果很好,并且与大多数ORM库(如EntityFramework和NHibernate)兼容。
但是,当子类型的数量非常大或者动态创建子类型时,有时会使用几种替代方法。
备选方案#1:键值扩展表。这是一个表,每个额外的数据字段需要存储一行,一个外键返回核心表(Task),和一列,指定这是什么类型的字段。它的结构通常类似于:
TaskExt Table
=================
TaskID : Number (foreign key back to Task)
FieldType : Number or String (this would be AccountID, SalesPersonID, etc)
FieldValue : String (this would be the value of the associated field)
备选方案#2:类型映射扩展表。在此替代方案中,您创建一个包含一堆可以为不同数据类型的列(数字,字符串,日期/时间等)的表名称如DATA01,DATA02,DATA03 ......等。对于每种任务,您可以选择列的子集并将它们映射到特定字段。因此,DATA01可能最终成为SoftwareTask的BuildVersion和SalesTask的AccountName。在此方法中,您必须在某处管理某些元数据,以控制将特定字段映射到的列。类型映射表通常类似于:
TaskExt Table
=================
TaskID : Number (foreign key back to task)
Data01 : String
Data02 : String
Data03 : String
Data04 : String
Data05 : Number
Data06 : Number
Data07 : Number
Data08 : Number
Data09 : Date
Data10 : Date
Data11 : Date
Data12 : Date
// etc...
选项#1的主要好处是您可以根据需要动态添加任意数量的不同字段,甚至可以支持一定程度的向后兼容性。然而,一个重要的缺点是即使是简单的查询也会变得具有挑战性,因为对象的字段被转移到表中的行中。 Unpivoting原来是一个既复杂又往往表现不佳的操作。
选项#2的好处是它易于实现,并且在行之间保持一对一的对应关系,使查询变得容易。不幸的是,这也存在一些缺点。第一个是列名完全没有信息,你必须引用一些元数据字典来了解哪些列映射到哪个类型的任务的字段。第二个缺点是大多数数据库将表上的列数限制为相对较小的数字(通常为50-300列)。因此,您只能使用这么多数字,字符串,日期时间等列。因此,如果您键入的最终日期时间字段多于表格支持,则必须使用字符串字段来存储日期,或者创建多个扩展表。
预先警告,大多数ORM库不提供对这些建模模式的内置支持。