首先,我知道我应该使用模型而不是直接使用数据库.话虽如此,有没有人知道Magento如何处理非全球产品属性?
我有2个网站core_website
:Admin(website_id = 0)和主网站(website_id = 1).我还有两个商店core_store
:Admin(store_id = 0)和Default Store View(store_id = 0).似乎产品(或类别?)属性是否在范围内是全局属性存储在catalog_eav_attribute
.is_global
.值0对应于"商店视图"的范围,值1对应于"全局",2对应于"网站".到现在为止还挺好.
现在,如果我想为所有产品获取特定于商店的属性的值,例如"name"(eav_attribute
.attribute_id
= 71; eav_attribute
.backend_type
='varchar'; catalog_eav_attribute
.is_global
= 0),您会认为我会这样做:
SELECT *
FROM catalog_product_entity_varchar
WHERE attribute_id = 71
AND store_id = 1
Run Code Online (Sandbox Code Playgroud)
但这没有任何回报.所有这些名称实际上都在store_id
= 0 行中.据我所知,数据库中存储为store_id
= 1 的唯一属性是'url_key'和'url_path'.那么Magento如何存储这些价值呢?Magento如何检索它们?
是否所有值最初(或者)都存储为store_id
= 0作为一种默认值,直到需要存储与该值不同的值?当需要存储与admin值不同的特定于商店的值时,magento会创建一个store_id
= 1 的新行(或者它是什么store_id)?
如果那样 - 或类似的东西 - 就是这种情况,那么Magento如何检索特定于商店的值?它检查catalog_eav_attribute
.is_global
首先是有问题的属性?如果它是非全局的,那么它可以先用store_id
= 1 查询,如果没有返回任何内容,那么查询默认值store_id
= 0?
我想我的主要问题是magento是如何实际做到的.其次,为什么magento这样做而不是用实际的store_id存储值?另外,如果我要编写查询,我应该同时查询store_id
= 0和store_id
= 1,并根据属性是否为全局以及是否存在store_id = 1的值来选择正确的值?
你似乎想通了.至少你对如何完成工作有个好主意.
总结并确认您的怀疑:
所有属性值都存储在catalog_product_entity_*
哪里*
可以是以下任何一个:decimal, int, varchar, text, datetime
取决于属性类型(backend_type
).
还有其他表格可以保存与层级定价和图像相关的数据,但现在让我们离开.
属性表定义
每个表都包含以下列:
value_id - just an increment id for the table
entity_type_id - the entity type id for the product (always the same)
attribute_id - reference to the attribute
store_id - reference to the store view
entity_id - reference to the product
value - actual value
Run Code Online (Sandbox Code Playgroud)
有这些列上唯一约束entity_id
,attribute_id
,store_id
.这意味着对于一个产品和一个属性,您只能拥有一个商店视图的值.
现在你正确的部分.
store_id = 0
表示存储的值是默认值.
如果没有为特定商店视图指定值(store_id> = 1),则将使用此值.
如果属性设置为global,则store_id = 0
即使您有值,也将使用值for store_id = 1
.
例子
要了解如何检索值,请将此代码放在某个文件中并运行它(确保平面目录已禁用 - 稍后将详细介绍,并确保首先使用创建应用程序的实例Mage::app()
):
存储视图属性
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('name', 'some_name');
echo $collection->getSelect();
Run Code Online (Sandbox Code Playgroud)
上面的代码意味着我想要检索具有该名称的产品列表some_name
.
与集合关联的SQL查询如下所示:
SELECT
`e`.*,
IF(at_name.value_id > 0, at_name.value, at_name_default.value) AS `name`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_varchar` AS `at_name_default`
ON (`at_name_default`.`entity_id` = `e`.`entity_id`) AND
(`at_name_default`.`attribute_id` = '96') AND
`at_name_default`.`store_id` = 0
LEFT JOIN
`catalog_product_entity_varchar` AS `at_name`
ON (`at_name`.`entity_id` = `e`.`entity_id`) AND
(`at_name`.`attribute_id` = '96') AND
(`at_name`.`store_id` = 1)
WHERE
(IF(at_name.value_id > 0, at_name.value, at_name_default.value) = 'some_name')
Run Code Online (Sandbox Code Playgroud)
丑陋吧?
因为name
属性(ID 96在我的情况)是一个存储视图范围属性(is_global
= 0)的Magento与表连接的两倍catalog_product_entity_varchar
(即保持所述一个name
),用于当前存储器视图为detault商店视图(ID,一次和一次= 0).添加条件:
IF(at_name.value_id > 0, at_name.value, at_name_default.value)
Run Code Online (Sandbox Code Playgroud)
因此,如果商店标识1没有值,请使用默认值.
全球归因
现在让我们看看如果我们按全局属性过滤会发生什么.
$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('weight', '1');
echo $collection->getSelect();
Run Code Online (Sandbox Code Playgroud)
sql打印如下:
SELECT
`e`.*,
`at_weight`.`value` AS `weight`
FROM
`catalog_product_entity` AS `e`
INNER JOIN
`catalog_product_entity_decimal` AS `at_weight`
ON (`at_weight`.`entity_id` = `e`.`entity_id`) AND
(`at_weight`.`attribute_id` = '101') AND
(`at_weight`.`store_id` = 0)
WHERE
(at_weight.value = '1')
Run Code Online (Sandbox Code Playgroud)
因此catalog_product_entity_decimal
,与商店id = 0 的表的单个连接.
网站属性
如果属性的范围website
就像它对商店视图范围那样发生,因为Magento在保存产品时在当前网站中的每个商店视图的属性值表中创建一行.
如果您想尝试使用status
上面示例中的属性.
扁平目录
我早些时候承诺过一些关于"平面目录"的解释.
出于性能原因,Magneto介绍了这个功能(我不记得版本).
基本上,cron运行(或者您可以手动运行)并将产品和类别的EAV方法转换为平面表.每个商店视图一个(商店ID = 0除外).
这意味着一个属性将转换为新表中的一列.调用新表catalog_product_flat_{store_view_id_here}
.
当想要某些属性的值时,这避免了许多左/内连接.
但同样,出于性能原因,并非所有属性都作为列添加到平面表中(仅适用于产品.对于类别,所有属性都已添加).
只有后端标记的属性Use in product listing
才会转换为列.
您可以从System->Configuration->Catalog->Frontend->Use Flat Catalog Product
(或Use Flat Catalog Category
)打开/关闭此功能.
即使打开,平面表也只在前端使用.后端仍然使用EAV方法.
结论
我的结论是,编写自己的查询几乎不可能直接从数据库中检索数据.您应该使用magento提供的模型和集合.它可以节省很多心理健康.
我希望我能为你做一些更清楚的事情.