158

在开发购物车应用程序时,我发现我需要根据管理员的偏好和要求保存设置和配置。此信息可以是公司信息、运输帐户 ID、PayPal API 密钥、通知首选项等。

在关系数据库系统中创建一个表来存储单行似乎是非常不合适的。

存储此信息的适当方式是什么?

注意:我的 DBMS 是 SQL Server 2008,编程层是用 ASP.NET(在 C# 中)实现的。

4

12 回答 12

207

我过去做过这两种方法——单行表和键/值对表——每种方法都有积极和消极的一面。

单行

  • 正:值以正确的类型存储
  • 正面:在代码中更容易处理(由于上述原因)
  • 正:可以单独为每个设置赋予默认值
  • 否定:需要更改架构才能添加新设置
  • 否定:如果有很多设置,表格可能会变得很宽

键/值对

  • 正面:添加新设置不需要更改架构
  • 肯定的:表模式很窄,有额外的行用于新设置
  • 负数:每个设置都有相同的默认值(null/empty?)
  • 否定:所有内容都必须存储为字符串(即 nvarchar)
  • 否定:在处理代码中的设置时,您必须知道设置是什么类型并进行转换

单行选项是迄今为止最容易使用的选项。这是因为您可以将每个设置以其正确的类型存储在数据库中,而不必将设置的类型及其查找键存储在代码中。

我担心使用这种方法的一件事是在“特殊”单行设置表中有多行。我通过(在 SQL Server 中)克服了这个问题:

  • 添加默认值为 0 的新位列
  • 创建检查约束以确保该列的值为 0
  • 在位列上创建唯一约束

这意味着表中只能存在一行,因为位列必须具有值 0,但由于唯一约束,只能存在具有该值的一行。

于 2010-02-20T00:13:40.143 回答
11

您应该创建一个包含信息类型和信息值列的表(至少)。这样您就可以避免每次添加新信息时都必须创建新列。

于 2010-02-19T23:44:22.443 回答
6

单行就可以了;它甚至会有强类型:

show_borders    bit
admin_name      varchar(50)
max_users       int

一个缺点是它需要更改架构 ( alter table) 才能添加新设置。一种替代方法是规范化,最终得到如下表格:

pref_name       varchar(50) primary key
pref_value      varchar(50) 

这具有弱类型(所有内容都是 varchar),但添加新设置只是添加一行,您可以通过数据库写入访问来执行此操作。

于 2010-02-20T00:06:30.410 回答
5

就个人而言,如果可行的话,我会将它存储在一行中。将其存储在 SQL 表中是否矫枉过正?可能,但这样做并没有真正的危害。

于 2010-02-19T23:57:17.207 回答
4

如您所料,除了最简单的情况外,将所有配置参数放在一行中会有很多缺点。这是个坏主意……

存储配置和/或用户偏好类型信息的一种便捷方式是使用 XML。许多 DBMS 支持 XML 数据类型。XML 语法允许您随着配置的发展而扩展描述配置的“语言”和结构。XML 的一个优点是它对层次结构的隐式支持,例如,允许存储配置参数的小列表,而不必使用编号后缀来命名它们。XML 格式的一个可能缺点是搜索和一般修改此数据不像其他方法那样直接(没有复杂,但没有那么简单/自然)

如果您想更接近于关系模型实体-属性-值模型可能是您所需要的,其中各个值存储在通常如下所示的表中:

EntityId     (foreign key to the "owner" of this attribute)
AttributeId  (foreign key to the "metadata" table where the attribute is defined)
StringValue  (it is often convenient to have different columns of different types
IntValue      allowing to store the various attributes in a format that befits 
              them)

其中 AttributeId 是表的外键,其中定义了每个可能的属性(在您的情况下为“配置参数”),例如

AttributeId  (Primary Key)
Name
AttributeType     (some code  S = string, I = Int etc.)
Required          (some boolean indicating that this is required)
Some_other_fields   (for example to define in which order these attributes get displayed etc...)

最后,EntityId 允许您识别“拥有”这些不同属性的某个实体。在您的情况下,如果您只有一个配置要管理,它可能是 UserId 甚至是隐式的。

除了允许可能的配置参数列表随着应用程序的发展而增长之外,EAV 模型将“元数据”(即与属性本身相关的数据)放在数据表中,因此避免了所有常见的列名硬编码当配置参数存储在一行中时。

于 2010-02-20T00:03:42.997 回答
3

在规范化方法中添加新配置参数时,您当然不必更改架构,但您仍然可能更改代码以处理新值。

为您的部署添加一个“更改表”对于单行方法的简单性和类型安全性而言似乎并不是那么大的权衡。

于 2011-03-22T13:48:28.550 回答
2

键值对类似于可以存储配置设置的 .Net App.Config。

因此,当您想要检索值时,您可以执行以下操作:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';
于 2011-05-02T22:06:57.620 回答
1

一种常见的方法是创建一个与属性文件类似的“属性”表。在这里,您可以存储您所有的应用程序常量,或者您只需要拥有的不太固定的东西。

然后,您可以根据需要从该表中获取信息。同样,当您发现要保存一些其他设置时,您可以添加它。这是一个示例:

property_entry_table

[id, scope, refId, propertyName, propertyValue, propertyType] 
1, 0, 1, "COMPANY_INFO", "Acme Tools", "ADMIN"  
2, 0, 1, "SHIPPING_ID", "12333484", "ADMIN"  
3, 0, 1, "PAYPAL_KEY", "2143123412341", "ADMIN"   
4, 0, 1, "PAYPAL_KEY", "123412341234123", "ADMIN"  
5, 0, 1, "NOTIF_PREF", "ON", "ADMIN"  
6, 0, 2, "NOTIF_PREF", "OFF", "ADMIN"   

通过这种方式,您可以存储您拥有的数据,以及您明年将拥有但还不知道的数据:)。

在此示例中,您的范围和 refId 可用于后端的任何内容。因此,如果 propertyType "ADMIN" 的范围为 0 refId 2,您就知道它是什么偏好。

当有一天,您还需要在此处存储非管理员信息时,属性类型就派上用场了。

请注意,您不应该以这种方式存储购物车数据,也不要为此进行查找。但是,如果数据是系统特定的,那么您当然可以使用这种方法。

例如:如果你想存储你的DATABASE_VERSION,你会使用这样的表。这样,当您需要升级应用程序时,您可以查看属性表以查看客户端具有的软件版本。

关键是您不想将其用于与购物车有关的事物。将业务逻辑保存在定义明确的关系表中。属性表仅用于系统信息。

于 2010-02-20T00:02:20.410 回答
1

Have a key column as varchar and a value column as JSON. 1 is numeric whereas "1" is a string. true and false are both boolean. You can have objects as well.

于 2016-04-11T16:30:26.923 回答
0

我不确定单行是配置的最佳实现。您最好为每个配置项设置一行,其中包含两列(configName、configValue),尽管这需要将所有值转换为字符串并返回。

无论如何,使用单行进行全局配置并没有什么坏处。将其存储在数据库(全局变量)中的其他选项更糟糕。您可以通过插入第一个配置行来控制它,然后禁用表上的插入以防止多行。

于 2010-02-19T23:44:07.437 回答
0

您可以通过为每种主要类型添加一列和一列告诉您数据在哪一列中来进行键/值对而无需转换。

所以你的桌子看起来像:

id, column_num, property_name, intValue, floatValue, charValue, dateValue
1, 1, weeks, 51, , ,
2, 2, pi, , 3.14159, , 
3, 4, FiscYearEnd, , , , 1/31/2015
4, 3, CompanyName, , , ACME, 

它使用了更多的空间,但您最多使用了几十个属性。您可以使用 column_num 值的 case 语句来拉/连接正确的字段。

于 2015-01-16T01:11:11.803 回答
0

对不起,我来了,多年以后。但无论如何,我所做的事情是简单而有效的。我只是创建了一个包含三个 () 列的表:

ID - 整数 (11)

名称 - varchar (64)

值 - 文本

在创建新的配置列、更新或读取之前我所做的是序列化“值”!这样我就可以确定类型(嗯,php是:))

例如:

乙:0;适用于B OOLEAN ( false )

乙:1;适用于B OOLEAN ( true )

我:1988;是为NT

s:5:"卡德尔"; 用于5 个字符长度的S TRING

我希望这有帮助 :)

于 2016-02-01T06:28:07.093 回答