在 SQL Server 数据库中使用单行配置表。坏主意?

发布于 2024-08-22 09:54:56 字数 204 浏览 4 评论 0原文

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

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

存储这些信息的适当方法是什么?

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

In developing a shopping cart application I've found that I needed to save settings and configurations based on the administrator's preferences and requirements. This information can be anything from company information, Shipping account IDs, PayPal API keys, notification preferences, etc.

It seems highly inappropriate to create a table to store a single row in a relational database system.

What is the appropriate way to store this information?

Note: my DBMS is SQL Server 2008 and programming layer is implemented with ASP.NET (in C#).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

夜深人未静 2024-08-29 09:54:56

我过去用两种方法完成了这件事——单行表和键/值对表——每种方法都有优点和缺点。

单行

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

键/值对 正值

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

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

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

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

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

I have done this two ways in the past - a single row table and a key/value pair table - and there are positives and negatives to each approach.

Single Row

  • positive: the values are stored in the correct type
  • positive: it is easier to deal with in code (due to the above)
  • positive: default values can be given to each setting individually
  • negative: a schema change is required to add a new setting
  • negative: the table can become very wide if there are lots of settings

Key/Value Pair

  • positive: adding new settings does not require a schema change
  • positive: the table schema is narrow, with extra rows being used for new settings
  • negative: each setting has the same default value (null/empty?)
  • negative: everything has to be stored as strings (ie. nvarchar)
  • negative: when dealing with the settings in code, you have to know what type a setting is and cast it

The single row option is by far the easiest one to work with. This is because you can store each setting in its correct type in the database and not have to store the types of the settings as well as their lookup keys in code.

One thing I was concerned with using this approach was having multiple rows in the "special" single row settings table. I overcame this by (in SQL Server):

  • adding a new bit column with a default value of 0
  • creating a check constraint to ensure that this column has a value of 0
  • creating a unique constraint on the bit column

This means that only one row can exist in the table because the bit column has to have a value of 0, but there can only be one row with that value because of the unique constraint.

云胡 2024-08-29 09:54:56

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

You should create a table with a column for the information type and information value (at least). This way you avoid having to create new columns every time a new information is added.

日记撕了你也走了 2024-08-29 09:54:56

单行就可以正常工作;它甚至会有强类型:

show_borders    bit
admin_name      varchar(50)
max_users       int

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

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

This hasweak types ( everything is a varchar),但添加新设置只是添加一行,只需数据库写入访问即可完成此操作。

A single row will work fine; it will even have strong types:

show_borders    bit
admin_name      varchar(50)
max_users       int

One disadvantage is that it requires a schema change (alter table) to add a new setting. One alternative is normalizing, where you end up with a table like:

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

This has weak types (everything is a varchar), but adding a new setting is just adding a row, something you can do with just database write access.

情话难免假 2024-08-29 09:54:56

就我个人而言,如果可行的话,我会将其存储在单行中。将其存储在 SQL 表中是否太过分了?也许吧,但这样做并没有什么真正的坏处。

Personally, I would store it in a single row if that is what works. Overkill to store it in an SQL table? probably, but there is no real harm in doing so.

萌面超妹 2024-08-29 09:54:56

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

存储配置和/或用户首选项类型信息的便捷方法是使用 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 模型还将“元数据”(即与属性本身相关的数据)放置在数据表中,从而避免了常见的所有列名称的硬编码当配置参数存储在单行中时。

As you guessed, and except for the simplest situations, putting all configurations parameters in a single rows has many drawbacks. It is a bad idea...

A convenient way to store configuration and/or user preference type of information is in XML. Many DBMSes support the XML data type. The XML syntax allows you to expend the "language" and structure describing the configuration as this configuration evolves. One advantage of XML is its implicit support for hierarchical structure, allowing for example to store small lists of configuration parameters without having to name these with a numbered suffix. A possible drawback of XML format is that searching and generally modifying this data isn't as straight forward as other approaches (nothing complicated, but not as simple/natural)

If you want to remain closer to relational model, the Entity-Attribute-Value model is probably what you need, whereby the individual values are stored in a table that typically looks like:

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)

Whereby the AttributeId is a foreign key to a table where each possible Attribute ("configuration parameter" in your case) is defined, with say

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

Finally the EntityId allows you to identify some entity which "owns" these various attributes. In your case it could be a UserId or even just implicit if you only have one configuration to manage.

Aside from allowing the list of possible configuration parameters to grow as the application evolves, the EAV model places the "meta data", i.e. the data pertaining to the Attribute themselves, in datatables, hence avoiding all the hard-coding of column names commonly seen when the configuration parameters are stored in a single row.

镜花水月 2024-08-29 09:54:56

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

在部署中添加“更改表”对于单行方法的简单性和类型安全性来说似乎并不是那么大的权衡。

You certainly don't have to change your schema when adding a new configuration parameter in the normalized approach, but you're still probably changing your code to process the new value.

Adding an "alter table" to your deployment doesn't seem like that big of a tradeoff for the simplicity and type safety of the single row approach.

奢望 2024-08-29 09:54:56

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

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

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';

A Key and Value pair is similar to a .Net App.Config which can store configuration settings.

So when you want to retrieve the value you could do:

SELECT value FROM configurationTable
WHERE ApplicationGroup = 'myappgroup'
AND keyDescription = 'myKey';
乞讨 2024-08-29 09:54:56

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

因此,您的表看起来像这样:

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 语句来拉出/连接正确的字段。

You can do the Key/Value Pair without conversions by adding a column for each major type and one column telling you which column the data is in.

So your table would look something like:

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, 

It uses a little more room but at most you are using a few dozen attributes. You can use a case statement off the column_num value to pull / join the right field.

梦屿孤独相伴 2024-08-29 09:54:56

执行此操作的常见方法是使用类似于属性文件的“属性”表。在这里,您可以存储所有应用程序常量,或者您只需要保留的不太常量的东西。

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

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,您可以使用这样的表。这样,当您需要升级应用程序时,您可以检查属性表以查看客户端拥有的软件版本。

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

A common way to do this is to have a "properties" table simmular to a properties file. Here you can store all your app constants, or not so constant things that you just need to have around.

You can then grab the info from this table as you need it. Likewise, as you find you have some other setting to save, you can add it in. Here is an example:

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"   

This way you can store the data you have, and the data that you will have next year and don't know about yet :) .

In this example, your scope and refId can be used for whatever you want on the back end. So if propertyType "ADMIN" has a scope 0 refId 2, you know what preference it is.

Property type comes in hand when, someday, you need to store non-admin info in here as well.

Note that you should not store cart data this way, or lookups for that matter. However if the data is System specific, then you can certainly use this method.

For example: If you want to store your DATABASE_VERSION, you'd use a table like this. That way, when you need to upgrade the app, you can check the properties table to see what version of your software the client has.

The point is you do not want to use this for things that pertain to the cart. Keep you business logic in well defined relational tables. The properties table is for system info only.

心奴独伤 2024-08-29 09:54:56

有一个 varchar 形式的键列和一个 JSON 形式的值列。 1 是数字,而 "1" 是字符串。 truefalse 都是布尔值。您也可以拥有对象。

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.

呢古 2024-08-29 09:54:56

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

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

I'm not sure a single row is the best implementation for configuration. You might be better off having a row per configuration item with two columns (configName, configValue), although this will require casting all of your values to strings and back.

Regardless, there's no harm in using a single row for global config. The other options for storing it in the DB (global variables) are worse. You could control it by inserting your first configuration row, then disabling inserts on the table to prevent multiple rows.

情愿 2024-08-29 09:54:56

抱歉,几年后我才来。但无论如何,我做的事情既简单又有效。我只是创建一个包含三 () 列的表:

ID - 整数 (11)

名称 - varchar (64)

值 - 文本

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

例如:

b:0;适用于 BOOLEAN(false

b:1;用于BOOLEAN(true

我:1988;适用于INT

s:5:"卡德尔";适用于长度为 5 个字符的 STRING

我希望这会有所帮助:)

Sorry I come like, yeaars later. But anyways, what I do is simple and effective. I simply create a table with three () columns:

ID - int (11)

name - varchar (64)

value - text

What I do before creating a new config column, updating it or reading is to serialize the "value"! This way I am sure of the type (Well, php is :) )

For instance:

b:0; is for BOOLEAN (false)

b:1; is for BOOLEAN (true)

i:1988; is for INT

s:5:"Kader"; is for a STRING of 5 characters length

I hope this helps :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文