简体   繁体   English

需要帮助应用程序设计

[英]Need Help With Application Design

So, I'd love some feedback on the best way to design the classes and store the data for the following situation: 所以,我喜欢关于设计类和存储以下情况的数据的最佳方法的一些反馈:

I have an interface called Tasks that looks like this: 我有一个名为Tasks的接口,如下所示:

interface ITask
{
    int ID{ get; set;}
    string Title {get; set;}
    string Description{get; set;}
}

I would like the ability to create different types of Tasks depending on who is using the application...for example: 我希望能够创建不同类型的任务,具体取决于谁在使用该应用程序...例如:

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;}
}

So the way I see it I can create a Tasks table in the database with columns that match the ITask interface and a column that shoves all of the properties of more specific tasks in a single column (or maybe even serialize the task object into a single column) 所以我看到它的方式我可以在数据库中使用与ITask接口匹配的列创建一个Tasks表,并在一列中推送更具体任务的所有属性(甚至可以将任务对象序列化为单个列)柱)

OR 要么

Create a table for each task type to store the properties that are unique to that type. 为每个任务类型创建一个表,以存储该类型唯一的属性。

I really don't like either solution right now. 我现在真的不喜欢任何一种解决方案。 I need to be able to create different types of Tasks ( or any other class) that all share a common core set of properties and methods through a base interface, but have the ability to store their unique properties in a fashion that is easy to search and filter against without having to create a bunch of database tables for each type. 我需要能够创建不同类型的任务(或任何其他类),它们通过基本接口共享一组共同的核心属性和方法,但能够以易于搜索的方式存储其独特属性并过滤而不必为每种类型创建一堆数据库表。

I've starting looking into Plug-In architecture and the strategy pattern, but I don't see where either would address my problem with storing and accessing the data. 我开始研究插件架构和策略模式,但我没有看到哪里可以解决我存储和访问数据的问题。

Any help or push in the right direction is greatly appreciated!!! 非常感谢任何帮助或推动正确的方向!

You should probably take a lead from how ORMs deal with this, like TPH/TPC/TPT 你可能应该从ORM如何处理这个问题,比如TPH / TPC / TPT

Given that ITask is an interface you should probably go for TPC (Table per Concrete Type). 鉴于ITask是一个接口,你应该选择TPC(每个混凝土类型的表)。 When you make it a baseclass, TPT and TPH are also options. 当你把它作为基类时,TPT和TPH也是选项。

Your second approach (one table per type) is the canonical way to solve this problem - while it requires a bit more effort to implement it fits better with the relational model of most databases and preserves a consistent and cohesive representation of the data. 您的第二种方法(每种类型一个表)是解决此问题的规范方法 - 虽然它需要更多的努力来实现它,它更适合大多数数据库的关系模型,并保留数据的一致和有凝聚力的表示。 The approach of using one table per concrete type works well, and is compatible with most ORM libraries (like EntityFramework and NHibernate). 每种具体类型使用一个表的方法效果很好,并且与大多数ORM库(如EntityFramework和NHibernate)兼容。

There are, however, a couple of alternative approaches sometimes used when the number of subtypes is very large, or subtypes are created on the fly. 然而,当子类型的数量非常大或者在运行中创建子类型时,有时会使用几种替代方法。

Alternative #1: The Key-Value extension table. 备选方案#1:键值扩展表。 This is a table with one row per additional field of data you wish to store, a foreign key back to the core table (Task), and a column that specifies what kind of field this is. 这是一个表,每个附加的数据字段需要存储一行,一个外键返回核心表(Task),以及一个指定这是哪种字段的列。 It's structure is typically something like: 它的结构通常类似于:

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)

Alternative #2: The Type-Mapped Extension Table. 备选方案#2:类型映射扩展表。 In this alternative, you create a table with a bunch of nullable columns of different data types (numbers, strings, date/time, etc) with names like DATA01, DATA02, DATA03 ... and so on. 在此替代方法中,您创建一个表,其中包含一组可以为不同数据类型(数字,字符串,日期/时间等)的可为空的列,其名称如DATA01,DATA02,DATA03 ......等等。 For each kind of Task, you select a subset of the columns and map them to particular fields. 对于每种任务,您可以选择列的子集并将它们映射到特定字段。 So, DATA01 may end up being the BuildVersion for a SoftwareTask and an AccountName for a SalesTask. 因此,DATA01可能最终成为SoftwareTask的BuildVersion和SalesTask的AccountName。 In this approach, you must manage some metadata somewhere that control which column you map specific fields to. 在此方法中,您必须在某处管理某些元数据,以控制将特定字段映射到的列。 A type-mapped table will often look something like: 类型映射表通常类似于:

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...

The main benefit of option #1 is that you can dynamically add as many different fields as you need, and you can even support a level of backward compatibility. 选项#1的主要好处是您可以根据需要动态添加任意数量的不同字段,甚至可以支持一定程度的向后兼容性。 A significant downside, however, is that even simple queries can become challenging because fields of the objects are pivoted into rows in the table. 然而,一个重要的缺点是即使是简单的查询也会变得具有挑战性,因为对象的字段被转移到表中的行中。 Unpivoting turns out to be an operation that is both complicated and often poorly performing. Unpivoting原来是一个既复杂又往往表现不佳的操作。

The benefits of option #2 is that it's easy to implement, and preserves a 1-to-1 correspondence betweens rows, making queries easy. 选项#2的好处在于它易于实现,并且在行之间保持一对一的对应关系,使查询变得容易。 Unfortunately, there are some downsides to this as well. 不幸的是,这也存在一些缺点。 The first is that the column names are completely uninformative, and you have to refer to some metadata dictionary to understand which columns maps to which field for which type of task. 第一个是列名完全没有信息,你必须引用一些元数据字典来了解哪些列映射到哪个类型的任务的字段。 The second downside is that most databases limit the number of columns on a table to a relatively small number (usually 50 - 300 columns). 第二个缺点是大多数数据库将表上的列数限制为相对较小的数字(通常为50-300列)。 As a result, you can only have so many numeric, string, datetime, etc columns available to use. 因此,您只能使用这么多数字,字符串,日期时间等列。 So if you type ends up having more DateTime fields than the table supports you have to either use string fields to store dates, or create multiple extension tables. 因此,如果您键入的最终日期时间字段多于表支持,则必须使用字符串字段来存储日期,或者创建多个扩展表。

Be forewarned, most ORM libraries do not provide built-in support for either of these modeling patterns. 预先警告,大多数ORM库不提供对这些建模模式中的任何一种的内置支持。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM