我有一个父ProductCategory
和一个孩子Product
。例如:
ProductCategory --- Product
Drill --- DeWalt DWD 112
--- Black & Decker 5 C
Bicycle --- Motobecane Turino ELITE Disc Brake
--- Shimano Aluminum
对于给定的ProductCategory
,有一组属性,所有Products
都应该相互比较(即,有数据)。但是,这组属性可能会在ProductCategories
例如,对于Drill的ProductCategory
,属性可能是Voltage, Amps, Corded vs Cordless
。每个Product
钻取都需要有这样的信息。但是,对于自行车的ProductCategory
,属性应为Size, Road vs Mountain
,并且每个Product
自行车都需要具有此信息。 (对不起,我不知道任何关于演习或自行车的事情......为什么我选择这个是愚蠢的)
我试图设计数据库,以便对于给定的Product
,属性是我可以轻松搜索的内容。例如,理想情况下我可以运行此命令:
drills = Product.where(product_category_id:1)
drills.where("voltage >= ?", 5)
-> returns the individual drills, which may include DeWalt but not Black & Decker
这似乎是一个有趣的权衡...因为我必须让Product
为每个ProductCategory
的每个属性都有列,即使是那些不是# Product columns
:voltage, :integer #for Drill
:amps, :integer #for Drill
:corded, :boolean #for Drill
:size, :integer #for Bicycle
:mountain, :boolean #for Bicycle
...
的列。与之相关。例如:
ProductCategories
这看起来并不可持续......你可以很快看到,只有少数Product
很快会有无数Product
列!
另一方面,我考虑在父ProductCategory
中定义每个Product
所需的属性,然后请求这些属性/将它们存储在# ProductCategory has a column...
:required_attributes, :text
ProductCategory.where(name:"Drill").first.required_attributes
-> "voltage,amps,corded"
ProductCategory.where(name:"Bicycle").first.required_attributes
-> "size,mountain"
# Product has a column...
:attribute_data, :text
Product.where(name:"DeWalt").first.attribute_data
-> "{'voltage':5,'amps':5,'corded':5}"
上作为字符串化数据:
Product
通过上面的设计,我可以创建一个强制执行该操作的前端,在创建required_attributes
后,必须在每个drills = ProductCategory.where(name:"Drill")
drills.where("attribute_data ...")
基于逗号分割后为其提供信息。但是当然,这会使搜索效率降低,至少我认为它确实...所以这是我的问题。 如何有效地搜索字符串化数据?如果我要搜索至少5伏的所有演练,请完成下面的操作。
#**include "stdafx.h"
#include <iostream>
#include <process.h>
#include <ctime>
#include <cstdlib>
#include <random>
using namespace std;
double printMatrix();
int main()
{
int n = 0, m = 1;
srand(time(0));
rand() % 2;
double printMatrix();
cout << "Enter the number of rows: ";
cin >> n;
cout << "Enter the number of columns: ";
cin >> m;
system("pause");
return 0;
}
double printMatrix()
{
return (double)rand() / ((double)RAND_MAX + 1);
}
答案 0 :(得分:0)
最简单的解决方案是在products
上使用JSON or HSTORE数据类型列来存储规范。
但是如果你想为每个规范提供更多的控制和验证,你可以使用带有连接表的设计:
class Product
has_many :specs
has_many :definitions, through: :specs
end
# This is the "normalized" table that defines an specification
# for example "Size". This just holds the name for example and the acceptable values.
class Definition
has_many :specs
has_many :products, through: :specs
end
# this contains the actual specs of a product (the value)
# specs.payload is a JSON column
class Spec
belongs_to :definition
belongs_to :product
delegate :name, to: :definition
def value
payload[:value]
end
def value=(val)
payload[:value] = val
end
end
使用这样的设计的一个典型问题是specs
表必须将值存储为text(或varchar)列并处理类型转换的问题。但大多数现代数据库都支持动态列类型,如HSTORE或JSON,可用于存储实际值。
缺点是在查询时必须使用特殊的SQL语法:
Spec.where("payload->>'value' = ?", "foo")
这是所谓的Entity–attribute–value model的一种归一化变体,它可以是反模式,但通常是关系数据库中动态属性的唯一良好解决方案。
请参阅:
答案 1 :(得分:0)
解决避免EAV表问题的另一种解决方法是使用多表继承。此示例使用ActiveRecord :: ActsAs。
class Product < ActiveRecord::Base
actable
belongs_to :brand
validates_numericality_of :universal_product_code, length: 12
validates_presence_of :model_name, :price
end
class Bicycle < ActiveRecord::Base
acts_as :product
validates_numericality_of :gears
validates_presence_of :size
end
class PowerTool < ActiveRecord::Base
acts_as :product
validates_numericality_of :voltage, :amps
validates_presence_of :voltage, :amps
end
这会将基本信息存储在products
表中:
change_table :products do |t|
t.decimal :price
t.sting :model_name
t.integer :universal_product_code, length: 12
t.integer :actable_id
t.string :actable_type
end
它使用多态关联将产品的子类型存储在更具体的表中:
create_table :bicycles do |t|
t.integer :gears
t.integer :size
end
create_table :power_tools do |t|
t.boolean :corded
t.integer :amps
t.integer :size
end
这里的优点是你有一个定义的模式而不是一堆松散的属性。 缺点是,如果您正在设计一个通用的网上商店,那么固定的架构不会削减它。