Table 带有自定义字段
Table with custom fields
我们目前在 CRM 中工作,我们的 table 之一需要有多个字段,该字段应存储通过 API 发送的自定义数据,客户可能需要许多这样的字段.
最初,我们有如下内容:
Entity
id, -specific fields to the entity-, customField1, customField2, customField3
但后来被告知只有3个字段不够,要求至少100个字段。
考虑到这一点,我陷入了困境,我应该使用类似 EAV 的结构,还是只将字段添加到 table(customField1,...,customField100)?
类似于 EAV 的结构类似于:
Entity
id
EntityCustomField
id, entityId, fieldValue
这里的主要问题是查询,它变得更复杂(而且很慢?)。
更多信息:
- 只有字符串会存储在这些字段中。
- 字段需要可索引并且可以单独搜索每个字段。 (因此将数据编码为 JSON 在这里可能无济于事)。
- 目前无法使用非关系数据库。
- 此 table 的写入次数将多于读取次数。
- 我们无法切换 RDMS。
有人遇到过类似问题并找到了解决方案,或者对所提出的任何可能解决方案有经验吗?
如果您正在使用 RDBMS 并且不想切换,处理此类用例的唯一选择是使用 @JoinColumn
和 @OneToMany
映射来持久化自定义字段的实体而不是存储直接。
如果您使用任何 ORM,读取和写入都可以得到高效处理,查询也很容易。
(我不熟悉 doctrine2 )
只是一个想法:
为什么不用 table 来保存字段值:
CREATE TABLE field_values_table (
id int(11) NOT NULL AUTO_INCREMENT
,field_value_1 varchar(100) NOT NULL DEFAULT ''
,field_value_2 varchar(100) NOT NULL DEFAULT ''
,field_value_3 varchar(100) NOT NULL DEFAULT ''
,field_value_n varchar(100) NOT NULL DEFAULT ''
,PRIMARY KEY (id)
);
和另一个 table 来保存相应的字段名称:
CREATE TABLE field_names_table
(
id int(11) NOT NULL AUTO_INCREMENT
,field_name_1 varchar(100) NOT NULL DEFAULT ''
,field_name_2 varchar(100) NOT NULL DEFAULT ''
,field_name_3 varchar(100) NOT NULL DEFAULT ''
,field_name_n varchar(100) NOT NULL DEFAULT ''
,PRIMARY KEY (id)
);
或者
- 考虑以上两个table之间的一对一关系,id为公共字段
- 或者有另一个 table 作为上述两个 tables
之间的关系 table
说:
CREATE TABLE field_name_value_relation (
id int(11) NOT NULL AUTO_INCREMENT
,field_names_table_row_id int(11) NOT NULL DEFAULT '0'
,field_values_table_row_id int(11) NOT NULL DEFAULT '0'
,PRIMARY KEY (id)
);
因此,如果您要搜索一个名为 country
且值为 New Zealand
的字段(您可能无法单独通过 SQL 查询完全实现它,但是)一个非常高的级别 SQL 查询可以是:
SELECT
*
FROM
field_names_table
LEFT OUTER JOIN field_name_value_relation
ON field_name_value_relation.field_names_table_row_id = field_names_table.id
LEFT OUTER JOIN field_values_table
ON field_values_table.id = field_name_value_relation.field_values_table_row_id
WHERE
field_name_n = 'country'
AND field_value_n = 'New Zealand'
这不是那么简单,因为您不知道 country
字段名称可能在 field_names_table
中的所有列。
无论如何,我希望这能给你一些想法来完成你的要求。
您尝试使用 EAV 创建的结构类型可以用许多不同的方式建模。
我的第一个选择是为每个需要存储的数据类型创建一个 table,例如 'integer'、'text' 和 'datetime'。
'customfields_text' table 的架构将是:
object_id、field_name、text_value
Primary Key = object_id + field_name
Index at text_value
相同的架构也适用于 'customfields_integer' 和 'customfields_datetime'。
查询时,您将能够:
SELECT * FROM objects o JOIN customfields_integer ci ON o.id = ci.object_id WHERE ci.field_name = 'my_custom_attribute'
我们目前在 CRM 中工作,我们的 table 之一需要有多个字段,该字段应存储通过 API 发送的自定义数据,客户可能需要许多这样的字段.
最初,我们有如下内容:
Entity
id, -specific fields to the entity-, customField1, customField2, customField3
但后来被告知只有3个字段不够,要求至少100个字段。
考虑到这一点,我陷入了困境,我应该使用类似 EAV 的结构,还是只将字段添加到 table(customField1,...,customField100)?
类似于 EAV 的结构类似于:
Entity
id
EntityCustomField
id, entityId, fieldValue
这里的主要问题是查询,它变得更复杂(而且很慢?)。
更多信息:
- 只有字符串会存储在这些字段中。
- 字段需要可索引并且可以单独搜索每个字段。 (因此将数据编码为 JSON 在这里可能无济于事)。
- 目前无法使用非关系数据库。
- 此 table 的写入次数将多于读取次数。
- 我们无法切换 RDMS。
有人遇到过类似问题并找到了解决方案,或者对所提出的任何可能解决方案有经验吗?
如果您正在使用 RDBMS 并且不想切换,处理此类用例的唯一选择是使用 @JoinColumn
和 @OneToMany
映射来持久化自定义字段的实体而不是存储直接。
如果您使用任何 ORM,读取和写入都可以得到高效处理,查询也很容易。
(我不熟悉 doctrine2 )
只是一个想法:
为什么不用 table 来保存字段值:
CREATE TABLE field_values_table (
id int(11) NOT NULL AUTO_INCREMENT
,field_value_1 varchar(100) NOT NULL DEFAULT ''
,field_value_2 varchar(100) NOT NULL DEFAULT ''
,field_value_3 varchar(100) NOT NULL DEFAULT ''
,field_value_n varchar(100) NOT NULL DEFAULT ''
,PRIMARY KEY (id)
);
和另一个 table 来保存相应的字段名称:
CREATE TABLE field_names_table
(
id int(11) NOT NULL AUTO_INCREMENT
,field_name_1 varchar(100) NOT NULL DEFAULT ''
,field_name_2 varchar(100) NOT NULL DEFAULT ''
,field_name_3 varchar(100) NOT NULL DEFAULT ''
,field_name_n varchar(100) NOT NULL DEFAULT ''
,PRIMARY KEY (id)
);
或者
- 考虑以上两个table之间的一对一关系,id为公共字段
- 或者有另一个 table 作为上述两个 tables 之间的关系 table
说:
CREATE TABLE field_name_value_relation (
id int(11) NOT NULL AUTO_INCREMENT
,field_names_table_row_id int(11) NOT NULL DEFAULT '0'
,field_values_table_row_id int(11) NOT NULL DEFAULT '0'
,PRIMARY KEY (id)
);
因此,如果您要搜索一个名为 country
且值为 New Zealand
的字段(您可能无法单独通过 SQL 查询完全实现它,但是)一个非常高的级别 SQL 查询可以是:
SELECT
*
FROM
field_names_table
LEFT OUTER JOIN field_name_value_relation
ON field_name_value_relation.field_names_table_row_id = field_names_table.id
LEFT OUTER JOIN field_values_table
ON field_values_table.id = field_name_value_relation.field_values_table_row_id
WHERE
field_name_n = 'country'
AND field_value_n = 'New Zealand'
这不是那么简单,因为您不知道 country
字段名称可能在 field_names_table
中的所有列。
无论如何,我希望这能给你一些想法来完成你的要求。
您尝试使用 EAV 创建的结构类型可以用许多不同的方式建模。
我的第一个选择是为每个需要存储的数据类型创建一个 table,例如 'integer'、'text' 和 'datetime'。
'customfields_text' table 的架构将是:
object_id、field_name、text_value
Primary Key = object_id + field_name
Index at text_value
相同的架构也适用于 'customfields_integer' 和 'customfields_datetime'。
查询时,您将能够:
SELECT * FROM objects o JOIN customfields_integer ci ON o.id = ci.object_id WHERE ci.field_name = 'my_custom_attribute'