首先,我知道我应该使用该模型而不是直接使用数据库。话虽这么说,有没有人确切知道Magento如何处理非全球产品属性?
我在core_website
中有2个网站:Admin(website_id = 0)和主网站(website_id = 1)。我在core_store
中还有两个商店:Admin(store_id = 0)和默认商店视图(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
但这没有任何回报。所有名称实际上都在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的值是否存在?
答案 0 :(得分:8)
你似乎想通了。至少你对如何完成工作有很好的了解
总结并确认您的怀疑:
所有属性值都存储在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
这些列entity_id
,attribute_id
,store_id
有一个唯一约束。这意味着对于一个产品和一个属性,您只能拥有一个商店视图的值。
现在你正确的部分。
store_id = 0
表示存储的值是默认值
如果没有为特定商店视图指定值(store_id> = 1),则将使用此值
如果该属性设置为全局,那么即使您有store_id = 0
的值,也会使用store_id = 1
的值。
<强>实施例强>
要了解如何检索值,请将此代码放在某个文件中并运行它(确保平面目录已禁用 - 稍后将详细介绍,并确保首先使用{{{}创建应用程序实例1}}):
商店视图属性
Mage::app()
上面的代码意味着我想要检索名为$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('name', 'some_name');
echo $collection->getSelect();
的产品列表
与集合关联的SQL查询如下所示:
some_name
丑陋吗?
因为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')
属性(在我的情况下为id 96)是商店视图范围属性(name
= 0),Magento与表is_global
(持有{{1}的表}连接两次}),一次用于当前商店视图,一次用于detault商店视图(id = 0)。添加条件:
catalog_product_entity_varchar
因此,如果商店标识1没有值,请使用默认值。
全球归属
现在让我们看看如果我们按全局属性过滤会发生什么。
name
sql打印如下:
IF(at_name.value_id > 0, at_name.value, at_name_default.value)
因此,对于商店ID = 0,只需与表$collection = Mage::getModel('catalog/product')->getCollection()
->addAttributeToFilter('weight', '1');
echo $collection->getSelect();
进行一次联接。
网站属性
如果属性范围为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')
,则所有操作都与商店视图范围相同,因为Magento在保存产品时在当前网站中的每个商店视图的属性值表中创建一行。
如果您想尝试使用上面示例中的属性catalog_product_entity_decimal
。
平面目录
我早些时候答应了一些关于“平面目录”的解释
出于性能原因,Magneto介绍了这个功能(我不记得版本)
基本上,cron运行(或者您可以手动运行)并将产品和类别的EAV方法转换为平面表。每个商店视图一个(商店ID = 0除外)
这意味着一个属性将转换为新表中的一列。新表名为website
当想要某些属性的值时,这避免了许多左/内连接
但同样,出于性能原因,并非所有属性都作为列添加到平面表中(仅适用于产品。对于类别,所有属性都已添加)。
只有后端带有status
标记的属性才会转换为列
您可以从catalog_product_flat_{store_view_id_here}
(或Use in product listing
)开启/关闭此功能。
即使打开,平面表也只在前端使用。后端仍然使用EAV方法。
<强>结论强>
我的结论是,编写自己的查询几乎不可能直接从数据库中检索数据。您应该使用magento提供的模型和集合。它可以节省很多心理健康。
我希望我能让你的事情更加清晰。